diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index f3fbb20a..cd717df9 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -511,7 +511,7 @@ const numstat = await gitService.getNumstat(cwd); ```typescript import { processService } from '../services/process'; -await processService.spawn(sessionId, config); +await processService.spawn(config); await processService.write(sessionId, 'input\n'); await processService.interrupt(sessionId); // SIGINT/Ctrl+C await processService.kill(sessionId); diff --git a/Auto Run Docs/Refactor-20251219-5.md b/Auto Run Docs/Refactor-20251219-5.md new file mode 100644 index 00000000..ae526e26 --- /dev/null +++ b/Auto Run Docs/Refactor-20251219-5.md @@ -0,0 +1,433 @@ + +## Renderer - Utilities (`src/renderer/utils/`) + +- [x] **Task 63:** `src/renderer/utils/templateVariables.ts` + Template variable processing. Examine for: + - Dead: Unused template functions + - Deprecated: Old template patterns + - Duplication: Same logic in shared/templateVariables.ts + - Smells: Template parsing robustness + - Types: Template typing + + **Audit Result:** ✅ Clean. This file is a minimal re-export (16 lines) from `shared/templateVariables.ts` for backward compatibility. All 5 exports (substituteTemplateVariables, TEMPLATE_VARIABLES, TEMPLATE_VARIABLES_GENERAL, TemplateContext, TemplateSessionInfo) are used by renderer code. No changes needed. + +- [x] **Task 64:** `src/renderer/utils/gitDiffParser.ts` + Git diff parsing. Examine for: + - Dead: Unused parsing functions + - Deprecated: Old diff format handling + - Duplication: Diff logic elsewhere + - Smells: Parser robustness, edge cases + - Types: Diff result typing + + **Audit Result:** ✅ Clean. All 3 exports (`parseGitDiff`, `getFileName`, `getDiffStats`) are actively used in `GitDiffViewer.tsx` and `GitLogViewer.tsx`. Uses modern `react-diff-view` library. Robust edge case handling for binary files, images, new/deleted files. Well-typed with `ParsedFileDiff` interface. Comprehensive test coverage (50+ test cases). No changes needed. + +- [x] **Task 65:** `src/renderer/utils/remarkFileLinks.ts` + Markdown file link plugin. Examine for: + - Dead: Unused link handling + - Deprecated: Old remark plugin patterns + - Duplication: Link handling elsewhere + - Smells: Link resolution reliability + - Types: Plugin typing + + **Audit Result:** ✅ Clean. Modern remark plugin using `unist-util-visit`. Actively used in `FilePreview.tsx` and `MarkdownRenderer.tsx`. Properly reuses `buildFileIndex` from `shared/treeUtils.ts`. Supports wiki-links `[[...]]`, path references, absolute paths, and image embeds. Well-typed with `mdast` types. 571 lines of tests provide comprehensive coverage. No changes needed. + +- [x] **Task 66:** `src/renderer/utils/remarkFrontmatterTable.ts` + Frontmatter parsing. Examine for: + - Dead: Unused frontmatter handling + - Deprecated: Old frontmatter patterns + - Duplication: Frontmatter logic elsewhere + - Smells: Parse error handling + - Types: Frontmatter typing + + **Audit Result:** ✅ Clean. Small focused plugin (135 lines) that transforms YAML frontmatter into styled HTML tables. Used in `FilePreview.tsx` and `MarkdownRenderer.tsx`. All internal helpers (`parseYamlKeyValues`, `isUrl`, `escapeHtml`, `generateTableHtml`) are used. Proper HTML escaping for security. Note: No dedicated tests exist, but the plugin is simple and stable. No changes needed. + +- [x] **Task 67:** `src/renderer/utils/markdownConfig.ts` + Markdown configuration. Examine for: + - Dead: Unused markdown options + - Deprecated: Old markdown-it/remark patterns + - Duplication: Config spread across files + - Smells: Config complexity + - Types: Config typing + + **Audit Result:** ⚠️ Dead code removed. `generateTerminalProseStyles` was exported but never used - removed it (9 lines). The remaining exports (`generateProseStyles`, `createMarkdownComponents`, `generateAutoRunProseStyles`) are actively used by `AutoRun.tsx`. Well-typed with `ProseStylesOptions` and `MarkdownComponentsOptions` interfaces. Updated header comment to reflect current usage. + +- [x] **Task 68:** `src/renderer/utils/textProcessing.ts` + Text processing utilities. Examine for: + - Dead: Unused text functions + - Deprecated: Old string handling + - Duplication: Text utils elsewhere + - Smells: Unicode handling, performance + - Types: Text function typing + + **Audit Result:** ✅ Mostly clean. `processCarriageReturns`, `processLogTextHelper`, `filterTextByLinesHelper`, `getCachedAnsiHtml`, and `stripMarkdown` are actively used in `TerminalOutput.tsx` and `GroupChatMessages.tsx`. `clearAnsiCache` is exported but unused - kept for API completeness (allows cache management in tests/debugging). `ANSI_CACHE_MAX_SIZE` is used internally. Good LRU cache implementation. Well-typed with DOMPurify for XSS protection. No changes needed. + +- [x] **Task 69:** `src/renderer/utils/formatters.ts` + Formatting utilities. Examine for: + - Dead: Unused formatters + - Deprecated: Old formatting patterns + - Duplication: Formatters in shared/formatters.ts + - Smells: Locale handling, edge cases + - Types: Formatter typing + + **Audit Result:** ✅ Clean. Minimal re-export file (15 lines) from `shared/formatters.ts`. All 7 exports (`formatSize`, `formatNumber`, `formatTokens`, `formatTokensCompact`, `formatRelativeTime`, `formatActiveTime`, `formatCost`) are actively used across multiple components (AchievementCard, SessionListItem, AgentSessionsBrowser, TabSwitcherModal, etc.). Correct architecture - shared formatters with renderer-specific re-export. No changes needed. + +- [x] **Task 70:** `src/renderer/utils/logger.ts` + Renderer logger. Examine for: + - Dead: Unused log methods + - Deprecated: Old console patterns + - Duplication: Logger in main/ and web/ + - Smells: Log performance, filtering + - Types: Log entry typing + + **Audit Result:** ✅ Clean. Minimal renderer logger (28 lines) that sends logs to main process via IPC. Used in `main.tsx` and `ErrorBoundary.tsx`. Only `logger.error()` is currently used; `debug`, `info`, `warn` are part of standard logging API but unused. Separate from `main/utils/logger.ts` by design (process isolation). No changes needed - keeping full API for future use. + +- [x] **Task 71:** `src/renderer/utils/shortcutMatcher.ts` + Shortcut matching. Examine for: + - Dead: Unused matching functions + - Deprecated: Old key event handling + - Duplication: Matching in handlers + - Smells: Cross-platform key handling + - Types: Key event typing + + **Audit Result:** ⚠️ Dead code removed. The entire file was dead code - all 3 exports (`matchShortcut`, `isAltMetaShortcut`, `isAltMetaNumberShortcut`) were never imported by any application code. The logic was duplicated in `useKeyboardShortcutHelpers.ts` which is the actual keyboard handler used by the app. Removed `shortcutMatcher.ts` (105 lines) and its test file `shortcutMatcher.test.ts` (436 lines). The hook retains identical functionality with its inline implementation. + +- [x] **Task 72:** `src/renderer/utils/shortcutFormatter.ts` + Shortcut formatting. Examine for: + - Dead: Unused format functions + - Deprecated: Old display patterns + - Duplication: Formatting elsewhere + - Smells: Platform-specific display + - Types: Format result typing + + **Audit Result:** ✅ Clean. `formatShortcutKeys` is actively used across 18+ components (SettingsModal, SessionList, RightPanel, AutoRun, QuickActionsModal, etc.). `formatKey` is used internally and exported as part of the complete API. `isMacOS` is exported for conditional rendering use cases. Platform detection using navigator.userAgent is correct for browser/Electron. Well-typed with Record mappings. Comprehensive test coverage (96 test cases covering both macOS and Windows/Linux platforms). No changes needed. + +- [x] **Task 73:** `src/renderer/utils/tabHelpers.ts` + Tab management utilities. Examine for: + - Dead: Unused tab functions + - Deprecated: Old tab patterns + - Duplication: Tab logic in components + - Smells: Tab state management + - Types: Tab typing + + **Audit Result:** ⚠️ Duplication fixed. Found `hasDraft()` function duplicated between `tabHelpers.ts` (internal only) and `TabBar.tsx` (local definition). Fixed by exporting `hasDraft` from tabHelpers and importing it in TabBar.tsx. All 12 exported functions (`hasDraft`, `getNavigableTabs`, `getActiveTab`, `createTab`, `closeTab`, `reopenClosedTab`, `setActiveTab`, `getWriteModeTab`, `getBusyTabs`, `navigateToNextTab`, `navigateToPrevTab`, `navigateToTabByIndex`, `navigateToLastTab`) are actively used. `getNavigableTabs` is only used internally + tests but kept as part of complete navigation API. Well-typed with 4 interface definitions (`CreateTabOptions`, `CreateTabResult`, `CloseTabResult`, `ReopenTabResult`, `SetActiveTabResult`). 81 tests all pass. Build succeeds. + +- [x] **Task 74:** `src/renderer/utils/fileExplorer.ts` + File explorer utilities. Examine for: + - Dead: Unused file functions + - Deprecated: Old file handling + - Duplication: File logic in hooks + - Smells: Path handling, permissions + - Types: File tree typing + + **Audit Result:** ⚠️ Duplication fixed. Found 3 duplicated functions between `fileExplorer.ts` and `useFileExplorer.ts` hook: `shouldOpenExternally` (with incomplete extension list), `flattenTree` (identical logic), and `getAllFolderPaths` (identical logic). Fixed by: + 1. Updated `shouldOpenExternally` in fileExplorer.ts with complete extension list (added 35+ extensions for images, design files, database files, fonts, compiled files, etc.) + 2. Refactored `useFileExplorer.ts` to import and use `shouldOpenExternally`, `flattenTree`, `getAllFolderPaths`, and `FileTreeNode` from `fileExplorer.ts` instead of duplicating + 3. Removed ~45 lines of duplicated code from the hook + + All exports are actively used: `shouldOpenExternally` (App.tsx:4873,6363), `loadFileTree` (useFileTreeManagement.ts), `getAllFolderPaths` (App.tsx:4945, useFileExplorer.ts), `flattenTree` (App.tsx:5059, useFileExplorer.ts), `compareFileTrees` (useFileTreeManagement.ts). Type exports `FileTreeNode`, `FlatTreeNode`, `FileTreeChanges` are all used. The `loadFileTree` function in the hook has different filtering behavior (skips hidden files) which is intentional for the hook's use case, so it was kept separate. All 298 file explorer tests pass. Build succeeds. + +- [x] **Task 75:** `src/renderer/utils/sessionValidation.ts` + Session validation. Examine for: + - Dead: Unused validation functions + - Deprecated: Old validation patterns + - Duplication: Validation elsewhere + - Smells: Validation completeness + - Types: Validation result typing + + **Audit Result:** ✅ Clean. All 3 exports are actively used: `validateNewSession` (App.tsx, NewInstanceModal.tsx), `validateEditSession` (NewInstanceModal.tsx), `getProviderDisplayName` (InputArea.tsx). Well-typed with `SessionValidationResult` interface. Internal helper `normalizeDirectory` handles case-insensitive comparison and trailing slash normalization. Minor overlap with `getToolTypeLabel` functions in `web/mobile/` but these are separate architectures with different agent lists - cross-architecture refactoring would add complexity without clear benefit. Comprehensive test coverage (27 tests, 345 lines). No changes needed. + +- [x] **Task 76:** `src/renderer/utils/theme.tsx` + Theme utilities. Examine for: + - Dead: Unused theme functions + - Deprecated: Old theme handling + - Duplication: Theme logic scattered + - Smells: Theme application consistency + - Types: Theme utility typing + + **Audit Result:** ✅ Clean. All 4 exports are actively used: `getContextColor` (App.tsx, SessionList.tsx, TabSwitcherModal.tsx), `getStatusColor` (SessionItem.tsx, SessionList.tsx), `getFileIcon` (FileExplorerPanel.tsx), `formatActiveTime` (re-exported from formatters, used in SessionList.tsx). Note: `getStatusColor` exists in 3 web files (`Card.tsx`, `SessionPillBar.tsx`, `TabSearchModal.tsx`) with slight variations, but these are in the separate web architecture with different color interfaces - cross-architecture refactoring would add complexity without clear benefit (same pattern as Task 75). Hardcoded `#ff8800` for 'connecting' state is intentional (not part of standard theme colors). Well-typed with Theme, SessionState, FileChangeType types. Comprehensive test coverage (67 tests). No changes needed. + +- [x] **Task 77:** `src/renderer/utils/search.ts` + Search utilities. Examine for: + - Dead: Unused search functions + - Deprecated: Old search patterns + - Duplication: Search in components + - Smells: Search performance, fuzzy matching + - Types: Search result typing + + **Audit Result:** ✅ Clean. All 3 exports are actively used: `fuzzyMatch` (useFileTreeManagement.ts, useFileExplorer.ts, ShortcutsHelpModal.tsx), `fuzzyMatchWithScore` (FileSearchModal.tsx, TabSwitcherModal.tsx, useAtMentionCompletion.ts), and `FuzzyMatchResult` interface (used in type annotations). No duplication - other search patterns in the codebase use simple `includes()` for substring matching, which is a different use case than character-by-character fuzzy matching. Good O(n) performance with comprehensive scoring algorithm (consecutive matches, word boundaries, case sensitivity, position, length ratio, exact match bonuses). Proper Unicode handling via `toLowerCase()`. Excellent test coverage (62 tests). No changes needed. + +- [x] **Task 78:** `src/renderer/utils/ids.ts` + ID generation. Examine for: + - Dead: Unused ID functions + - Deprecated: Old ID patterns + - Duplication: ID generation elsewhere + - Smells: ID uniqueness guarantees + - Types: ID typing + + **Audit Result:** ⚠️ Duplication fixed. Found 5 places in `src/renderer` that directly called `crypto.randomUUID()` instead of using the centralized `generateId()` helper: + 1. `usePlaybookManagement.ts:206` - batch document entry creation + 2. `LeaderboardRegistrationModal.tsx:48` - client token generation + 3. `BatchRunnerModal.tsx:91` - initial document entry + 4. `DocumentsPanel.tsx:551` - duplicate document creation + 5. `DocumentsPanel.tsx:576` - new document addition + + Fixed by adding `import { generateId } from '../utils/ids'` to each file and replacing `crypto.randomUUID()` calls with `generateId()`. This ensures consistent ID generation through a single source and allows future changes to be made in one place. The `generateId` function uses `crypto.randomUUID()` which is cryptographically secure and generates proper UUID v4 identifiers. All tests pass (3 tests in ids.test.ts). Build succeeds. + +- [x] **Task 79:** `src/renderer/utils/participantColors.ts` + Participant color assignment. Examine for: + - Dead: Unused color functions + - Deprecated: Old color assignment + - Duplication: Color logic elsewhere + - Smells: Color accessibility, collisions + - Types: Color typing + + **Audit Result:** ⚠️ Duplication fixed. Found `normalizeMentionName` and `mentionMatchesName` (identical to `mentionMatches`) duplicated between `participantColors.ts` and `group-chat-router.ts` (main process). Fixed by: + 1. Moved `normalizeMentionName` and `mentionMatches` to `src/shared/group-chat-types.ts` (the appropriate shared location for group chat utilities) + 2. Updated `participantColors.ts` to re-export from shared for backward compatibility + 3. Updated `group-chat-router.ts` to import from shared instead of defining locally, renamed `mentionMatchesName` calls to `mentionMatches` + + All 10 exports are actively used: `normalizeMentionName` (GroupChatInput.tsx, group-chat-router.ts), `mentionMatches` (group-chat-router.ts), `generateParticipantColor` (GroupChatMessages.tsx), `buildParticipantColorMap` (3 components), `buildParticipantColorMapWithPreferences` + `loadColorPreferences` + `saveColorPreferences` + `ParticipantColorInfo` (GroupChatRightPanel.tsx). `MODERATOR_COLOR_INDEX` and `COLOR_PALETTE_SIZE` are exported for API completeness but currently only used internally. Color generation uses golden ratio hue distribution for visual distinction and adapts saturation/lightness for theme compatibility. No accessibility or collision issues detected. Build succeeds. No dedicated tests exist for this file. + +--- + +## Renderer - Services (`src/renderer/services/`) + +- [x] **Task 80:** `src/renderer/services/git.ts` + Git service wrapper. Examine for: + - Dead: Unused git methods + - Deprecated: Old git service patterns + - Duplication: Logic with IPC handlers + - Smells: Error handling, caching + - Types: Git result typing + + **Audit Result:** ✅ Clean with minor consistency update. All 7 methods are actively used across App, hooks, and UI (isRepo, getStatus, getDiff, getNumstat, getRemoteBrowserUrl, getBranches, getTags). Refactored `getStatus` to use `createIpcMethod` like the rest of the service for consistent error handling and default return values. Existing tests cover all behaviors; no changes needed. + +- [x] **Task 81:** `src/renderer/services/process.ts` + Process service wrapper. Examine for: + - Dead: Unused process methods + - Deprecated: Old service patterns + - Duplication: Logic with IPC handlers + - Smells: Process state tracking + - Types: Process typing + + **Audit Result:** ⚠️ Type mismatch fixed. `processService.spawn` accepted `(sessionId, config)` even though the IPC API expects a single config object that includes `sessionId`. Updated `ProcessConfig` to match the actual spawn payload (agent/session options + per-session overrides), adjusted `processService.spawn` to call `window.maestro.process.spawn(config)`, and refreshed docs/tests accordingly. Added parity with renderer types by re-exporting `ProcessConfig` from `src/renderer/types/index.ts`. Tests updated and passing. + +- [ ] **Task 82:** `src/renderer/services/ipcWrapper.ts` + IPC wrapper utilities. Examine for: + - Dead: Unused wrappers + - Deprecated: Old IPC wrapper patterns + - Duplication: Wrappers for same endpoints + - Smells: Error handling consistency + - Types: IPC typing + +--- + +## Renderer - Hooks (`src/renderer/hooks/`) + +- [ ] **Task 83:** `src/renderer/hooks/useSettings.ts` + Settings management. Examine for: + - Dead: Unused settings, dead setters + - Deprecated: Old settings patterns + - Duplication: Settings logic spread out + - Smells: Settings persistence timing, validation + - Types: Settings type completeness + +- [ ] **Task 84:** `src/renderer/hooks/useSessionManager.ts` + Session management. Examine for: + - Dead: Unused session operations + - Deprecated: Old session patterns + - Duplication: Session logic in components + - Smells: Session state complexity, race conditions + - Types: Session typing + +- [ ] **Task 85:** `src/renderer/hooks/useBatchProcessor.ts` + Batch processing. Examine for: + - Dead: Unused batch operations + - Deprecated: Old batch patterns + - Duplication: Batch logic elsewhere + - Smells: Batch state management, cancellation + - Types: Batch state typing + +- [ ] **Task 86:** `src/renderer/hooks/useAgentCapabilities.ts` + Agent capabilities hook. Examine for: + - Dead: Unused capability checks + - Deprecated: Old capability patterns + - Duplication: Capability checks scattered + - Smells: Capability caching, updates + - Types: Capability typing + +- [ ] **Task 87:** `src/renderer/hooks/useAgentErrorRecovery.tsx` + Error recovery hook. Examine for: + - Dead: Unused recovery paths + - Deprecated: Old error handling patterns + - Duplication: Error handling elsewhere + - Smells: Recovery state machine complexity + - Types: Error typing + +- [ ] **Task 88:** `src/renderer/hooks/useAgentExecution.ts` + Agent execution hook. Examine for: + - Dead: Unused execution paths + - Deprecated: Old execution patterns + - Duplication: Execution logic scattered + - Smells: Execution state management + - Types: Execution typing + +- [ ] **Task 89:** `src/renderer/hooks/useAgentSessionManagement.ts` + Session management hook. Examine for: + - Dead: Unused session methods + - Deprecated: Old session patterns + - Duplication: Overlap with useSessionManager.ts + - Smells: Session lifecycle complexity + - Types: Session typing + +- [ ] **Task 90:** `src/renderer/hooks/useAutoRunHandlers.ts` + Auto Run handlers. Examine for: + - Dead: Unused handlers + - Deprecated: Old Auto Run patterns + - Duplication: Handler logic repeated + - Smells: Handler complexity, side effects + - Types: Handler typing + +- [ ] **Task 91:** `src/renderer/hooks/useAutoRunImageHandling.ts` + Image handling for Auto Run. Examine for: + - Dead: Unused image operations + - Deprecated: Old image patterns + - Duplication: Image logic elsewhere + - Smells: Image loading, memory management + - Types: Image typing + +- [ ] **Task 92:** `src/renderer/hooks/useAutoRunUndo.ts` + Auto Run undo functionality. Examine for: + - Dead: Unused undo operations + - Deprecated: Old undo patterns + - Duplication: Undo logic elsewhere + - Smells: Undo stack management + - Types: Undo state typing + +- [ ] **Task 93:** `src/renderer/hooks/useFileExplorer.ts` + File explorer hook. Examine for: + - Dead: Unused explorer operations + - Deprecated: Old file tree patterns + - Duplication: Explorer logic in utils + - Smells: Tree performance, lazy loading + - Types: File tree typing + +- [ ] **Task 94:** `src/renderer/hooks/useFileTreeManagement.ts` + File tree management. Examine for: + - Dead: Unused tree operations + - Deprecated: Old tree patterns + - Duplication: Overlap with useFileExplorer.ts + - Smells: Tree state synchronization + - Types: Tree typing + +- [ ] **Task 95:** `src/renderer/hooks/useGitStatusPolling.ts` + Git polling hook. Examine for: + - Dead: Unused polling features + - Deprecated: Old polling patterns + - Duplication: Polling in context + - Smells: Polling frequency, performance + - Types: Poll result typing + +- [ ] **Task 96:** `src/renderer/hooks/useGroupManagement.ts` + Group management hook. Examine for: + - Dead: Unused group operations + - Deprecated: Old group patterns + - Duplication: Group logic scattered + - Smells: Group state consistency + - Types: Group typing + +- [ ] **Task 97:** `src/renderer/hooks/useInputProcessing.ts` + Input processing hook. Examine for: + - Dead: Unused processing paths + - Deprecated: Old input patterns + - Duplication: Processing elsewhere + - Smells: Input validation, sanitization + - Types: Input typing + +- [ ] **Task 98:** `src/renderer/hooks/useKeyboardNavigation.ts` + Keyboard navigation. Examine for: + - Dead: Unused navigation handlers + - Deprecated: Old keyboard patterns + - Duplication: Navigation in components + - Smells: Focus management complexity + - Types: Navigation typing + +- [ ] **Task 99:** `src/renderer/hooks/useMainKeyboardHandler.ts` + Main keyboard handler. Examine for: + - Dead: Unused key handlers + - Deprecated: Old keyboard event patterns + - Duplication: Key handling scattered + - Smells: Handler priority, conflicts + - Types: Keyboard event typing + +- [ ] **Task 100:** `src/renderer/hooks/useModalManager.ts` + Modal management. Examine for: + - Dead: Unused modal operations + - Deprecated: Old modal patterns + - Duplication: Modal logic in context + - Smells: Modal stack management + - Types: Modal typing + +- [ ] **Task 101:** `src/renderer/hooks/usePlaybookManagement.ts` + Playbook management. Examine for: + - Dead: Unused playbook operations + - Deprecated: Old playbook patterns + - Duplication: Playbook logic elsewhere + - Smells: Playbook state management + - Types: Playbook typing + +- [ ] **Task 102:** `src/renderer/hooks/useRemoteIntegration.ts` + Remote integration. Examine for: + - Dead: Unused remote operations + - Deprecated: Old remote patterns + - Duplication: Remote logic scattered + - Smells: Connection management + - Types: Remote typing + +- [ ] **Task 103:** `src/renderer/hooks/useWebBroadcasting.ts` + Web broadcasting hook. Examine for: + - Dead: Unused broadcast operations + - Deprecated: Old broadcast patterns + - Duplication: Broadcast logic in services + - Smells: Broadcast reliability + - Types: Broadcast typing + +- [ ] **Task 104:** `src/renderer/hooks/useWorktreeValidation.ts` + Worktree validation. Examine for: + - Dead: Unused validation checks + - Deprecated: Old worktree patterns + - Duplication: Validation elsewhere + - Smells: Validation timing, errors + - Types: Validation typing + +- [ ] **Task 105:** Remaining hooks in `src/renderer/hooks/` + Examine ALL five categories for each: + - useAchievements.ts + - useActivityTracker.ts + - useAtMentionCompletion.ts + - useBatchedSessionUpdates.ts + - useCliActivityMonitoring.ts + - useClickOutside.ts + - useDebouncedPersistence.ts + - useExpandedSet.ts + - useFilteredAndSortedSessions.ts + - useFocusManager.ts + - useInputSync.ts + - useKeyboardShortcutHelpers.ts + - useLayerStack.ts + - useListNavigation.ts + - useLiveOverlay.ts + - useMobileLandscape.ts + - useModalLayer.ts + - useNavigationHistory.ts + - useScrollPosition.ts + - useSessionNavigation.ts + - useSessionPagination.ts + - useSessionViewer.ts + - useSortedSessions.ts + - useTabCompletion.ts + - useTemplateAutocomplete.ts + - useThemeStyles.ts + - useThrottle.ts + +--- diff --git a/src/__tests__/renderer/services/ipcWrapper.test.ts b/src/__tests__/renderer/services/ipcWrapper.test.ts index 303fda4c..b1f894b0 100644 --- a/src/__tests__/renderer/services/ipcWrapper.test.ts +++ b/src/__tests__/renderer/services/ipcWrapper.test.ts @@ -300,7 +300,7 @@ describe('ipcWrapper', () => { const createProcessMethod = createIpcMethodFactory('Process', 'rethrow'); // Simulating processService.spawn - const spawn = (sessionId: string, config: { cwd: string }) => + const spawn = (config: { cwd: string }) => createProcessMethod( async () => { // Simulate IPC call that returns void @@ -309,7 +309,7 @@ describe('ipcWrapper', () => { 'spawn' ); - await expect(spawn('session-1', { cwd: '/path' })).resolves.toBeUndefined(); + await expect(spawn({ cwd: '/path' })).resolves.toBeUndefined(); }); }); }); diff --git a/src/__tests__/renderer/services/process.test.ts b/src/__tests__/renderer/services/process.test.ts index 943ac1b9..c1e3da7a 100644 --- a/src/__tests__/renderer/services/process.test.ts +++ b/src/__tests__/renderer/services/process.test.ts @@ -34,52 +34,70 @@ beforeEach(() => { describe('processService', () => { describe('spawn', () => { - const testConfig: ProcessConfig = { + const baseConfig = { + toolType: 'claude-code', cwd: '/path/to/project', command: 'claude-code', args: ['--print'], - isTerminal: false, }; test('spawns a process with correct session ID and config', async () => { - mockProcess.spawn.mockResolvedValue(undefined); - - await processService.spawn('session-1', testConfig); - - expect(mockProcess.spawn).toHaveBeenCalledWith('session-1', testConfig); - expect(mockProcess.spawn).toHaveBeenCalledTimes(1); - }); - - test('spawns terminal process with isTerminal flag', async () => { - const terminalConfig: ProcessConfig = { - cwd: '/home/user', - command: '/bin/bash', - args: [], - isTerminal: true, + const testConfig: ProcessConfig = { + ...baseConfig, + sessionId: 'session-1', }; mockProcess.spawn.mockResolvedValue(undefined); - await processService.spawn('session-terminal', terminalConfig); + await processService.spawn(testConfig); - expect(mockProcess.spawn).toHaveBeenCalledWith('session-terminal', terminalConfig); + expect(mockProcess.spawn).toHaveBeenCalledWith(testConfig); + expect(mockProcess.spawn).toHaveBeenCalledTimes(1); + }); + + test('spawns terminal process with terminal tool type', async () => { + const terminalConfig: ProcessConfig = { + ...baseConfig, + sessionId: 'session-terminal', + toolType: 'terminal', + cwd: '/home/user', + command: '/bin/bash', + args: [], + }; + mockProcess.spawn.mockResolvedValue(undefined); + + await processService.spawn(terminalConfig); + + expect(mockProcess.spawn).toHaveBeenCalledWith(terminalConfig); }); test('throws error and logs when spawn fails', async () => { const error = new Error('Failed to spawn process'); + const testConfig: ProcessConfig = { + ...baseConfig, + sessionId: 'session-1', + }; mockProcess.spawn.mockRejectedValue(error); - await expect(processService.spawn('session-1', testConfig)).rejects.toThrow('Failed to spawn process'); + await expect(processService.spawn(testConfig)).rejects.toThrow('Failed to spawn process'); expect(console.error).toHaveBeenCalledWith('Process spawn error:', error); }); test('handles different session IDs', async () => { + const sessionConfigOne: ProcessConfig = { + ...baseConfig, + sessionId: 'ai-session-123', + }; + const sessionConfigTwo: ProcessConfig = { + ...baseConfig, + sessionId: 'terminal-session-456', + }; mockProcess.spawn.mockResolvedValue(undefined); - await processService.spawn('ai-session-123', testConfig); - await processService.spawn('terminal-session-456', testConfig); + await processService.spawn(sessionConfigOne); + await processService.spawn(sessionConfigTwo); - expect(mockProcess.spawn).toHaveBeenNthCalledWith(1, 'ai-session-123', testConfig); - expect(mockProcess.spawn).toHaveBeenNthCalledWith(2, 'terminal-session-456', testConfig); + expect(mockProcess.spawn).toHaveBeenNthCalledWith(1, sessionConfigOne); + expect(mockProcess.spawn).toHaveBeenNthCalledWith(2, sessionConfigTwo); }); }); @@ -445,16 +463,18 @@ describe('processService', () => { describe('type exports', () => { test('ProcessConfig interface has required properties', () => { const config: ProcessConfig = { + sessionId: 'session-1', + toolType: 'claude-code', cwd: '/path', command: 'cmd', args: ['arg1'], - isTerminal: false, }; + expect(config.sessionId).toBe('session-1'); + expect(config.toolType).toBe('claude-code'); expect(config.cwd).toBe('/path'); expect(config.command).toBe('cmd'); expect(config.args).toEqual(['arg1']); - expect(config.isTerminal).toBe(false); }); test('ProcessDataHandler type signature', () => { diff --git a/src/renderer/services/process.ts b/src/renderer/services/process.ts index a4d1beca..f517ca76 100644 --- a/src/renderer/services/process.ts +++ b/src/renderer/services/process.ts @@ -4,13 +4,9 @@ */ import { createIpcMethod } from './ipcWrapper'; +import type { ProcessConfig } from '../types'; -export interface ProcessConfig { - cwd: string; - command: string; - args: string[]; - isTerminal: boolean; -} +export type { ProcessConfig } from '../types'; export interface ProcessDataHandler { (sessionId: string, data: string): void; @@ -28,9 +24,9 @@ export const processService = { /** * Spawn a new process */ - spawn: (sessionId: string, config: ProcessConfig): Promise => + spawn: (config: ProcessConfig): Promise<{ pid: number; success: boolean }> => createIpcMethod({ - call: () => window.maestro.process.spawn(sessionId, config), + call: () => window.maestro.process.spawn(config), errorContext: 'Process spawn', rethrow: true, }), diff --git a/src/renderer/types/index.ts b/src/renderer/types/index.ts index 5631573c..b561f692 100644 --- a/src/renderer/types/index.ts +++ b/src/renderer/types/index.ts @@ -486,6 +486,17 @@ export interface ProcessConfig { args: string[]; prompt?: string; // For batch mode agents like Claude (passed as CLI argument) shell?: string; // Shell to use for terminal sessions (e.g., 'zsh', 'bash', 'fish') + images?: string[]; // Base64 data URLs for images + // Agent-specific spawn options (used to build args via agent config) + agentSessionId?: string; // For session resume (uses agent's resumeArgs builder) + readOnlyMode?: boolean; // For read-only/plan mode (uses agent's readOnlyArgs) + modelId?: string; // For model selection (uses agent's modelArgs builder) + yoloMode?: boolean; // For YOLO/full-access mode (uses agent's yoloModeArgs) + // Per-session overrides (take precedence over agent-level config) + sessionCustomPath?: string; + sessionCustomArgs?: string; + sessionCustomEnvVars?: Record; + sessionCustomModel?: string; } // Directory entry from fs:readDir @@ -550,4 +561,3 @@ export interface LeaderboardSubmitResponse { longestRun: LeaderboardRankingInfo | null; // null if no longestRunMs submitted }; } -