diff --git a/.gitignore b/.gitignore index 3fe49f5e..d50f4f67 100644 --- a/.gitignore +++ b/.gitignore @@ -33,11 +33,6 @@ scratch/ Thumbs.db # IDE -# .vscode/ is tracked for shared settings (settings.json, extensions.json) -# But ignore personal/local files -.vscode/* -!.vscode/settings.json -!.vscode/extensions.json .idea/ *.swp *.swo @@ -55,5 +50,6 @@ yarn-debug.log* yarn-error.log* #VS Code +.vscode/ .VSCodeCounter -.qodo \ No newline at end of file +.qodo diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 9c86b8bc..00000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "recommendations": [ - "esbenp.prettier-vscode", - "dbaeumer.vscode-eslint", - "editorconfig.editorconfig" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index d7b1963a..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - // Format on save with Prettier - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", - - // Use tabs (matches .prettierrc and .editorconfig) - "editor.tabSize": 2, - "editor.insertSpaces": false, - "editor.detectIndentation": false, - - // ESLint configuration - "eslint.enable": true, - "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], - - // Don't let ESLint format - let Prettier handle it - "eslint.format.enable": false, - - // File-specific formatters - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[typescriptreact]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - - // Recommended extensions - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, - - // Files to exclude from search/watch - "files.exclude": { - "dist": true, - "release": true, - "node_modules": true - }, - - // TypeScript settings - "typescript.tsdk": "node_modules/typescript/lib", - "typescript.enablePromptUseWorkspaceTsdk": true -} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc6f442f..36ce619b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ See [Performance Guidelines](#performance-guidelines) for specific practices. - [Project Structure](#project-structure) - [Development Scripts](#development-scripts) - [Testing](#testing) -- [Linting](#linting) +- [Linting & Pre-commit Hooks](#linting--pre-commit-hooks) - [Common Development Tasks](#common-development-tasks) - [Adding a New AI Agent](#adding-a-new-ai-agent) - [Code Style](#code-style) @@ -150,6 +150,25 @@ You can also specify a custom demo directory via environment variable: MAESTRO_DEMO_DIR=~/Desktop/my-demo npm run dev ``` +### Running Multiple Instances (Git Worktrees) + +When working with multiple git worktrees, you can run Maestro instances in parallel by specifying different ports using the `VITE_PORT` environment variable: + +```bash +# In the main worktree (uses default port 5173) +npm run dev + +# In worktree 2 (in another directory and terminal) +VITE_PORT=5174 npm run dev + +# In worktree 3 +VITE_PORT=5175 npm run dev +``` + +This allows you to develop and test different branches simultaneously without port conflicts. + +**Note:** The web interface dev server (`npm run dev:web`) uses a separate port (default 5174) and can be configured with `VITE_WEB_PORT` if needed. + ## Testing Run the test suite with Jest: diff --git a/docs/git-worktrees.md b/docs/git-worktrees.md index 8161b3cb..16c43255 100644 --- a/docs/git-worktrees.md +++ b/docs/git-worktrees.md @@ -121,3 +121,11 @@ The confirmation dialog shows the full path to the worktree directory so you kno - **Use a dedicated worktree folder** — Keep all worktrees in one place outside the main repo - **Clean up when done** — Remove worktree agents after merging PRs to avoid clutter - **Watch for Changes** — Enable file watching to keep the file tree in sync with worktree activity +- **Run multiple dev instances** — Use `VITE_PORT` environment variable to run Maestro in multiple worktrees simultaneously: + ```bash + # In main worktree + npm run dev + + # In worktree 2 (different terminal/directory) + VITE_PORT=5174 npm run dev + ``` diff --git a/src/__tests__/renderer/components/AboutModal.test.tsx b/src/__tests__/renderer/components/AboutModal.test.tsx index 9ae8b6e2..5576265b 100644 --- a/src/__tests__/renderer/components/AboutModal.test.tsx +++ b/src/__tests__/renderer/components/AboutModal.test.tsx @@ -1111,5 +1111,4 @@ describe('AboutModal', () => { expect(screen.getByText('$12,345,678.90')).toBeInTheDocument(); }); }); - }); diff --git a/src/__tests__/renderer/components/UsageDashboard/SummaryCards.test.tsx b/src/__tests__/renderer/components/UsageDashboard/SummaryCards.test.tsx index a9c176f0..cccb25b8 100644 --- a/src/__tests__/renderer/components/UsageDashboard/SummaryCards.test.tsx +++ b/src/__tests__/renderer/components/UsageDashboard/SummaryCards.test.tsx @@ -42,7 +42,6 @@ const mockData: StatsAggregation = { avgSessionDuration: 288000, byAgentByDay: {}, bySessionByDay: {}, - }; // Empty data for edge case testing @@ -61,7 +60,6 @@ const emptyData: StatsAggregation = { avgSessionDuration: 0, byAgentByDay: {}, bySessionByDay: {}, - }; // Data with large numbers @@ -83,7 +81,6 @@ const largeNumbersData: StatsAggregation = { avgSessionDuration: 7200000, byAgentByDay: {}, bySessionByDay: {}, - }; // Single agent data @@ -104,7 +101,6 @@ const singleAgentData: StatsAggregation = { avgSessionDuration: 360000, byAgentByDay: {}, bySessionByDay: {}, - }; // Only auto queries @@ -125,7 +121,6 @@ const onlyAutoData: StatsAggregation = { avgSessionDuration: 360000, byAgentByDay: {}, bySessionByDay: {}, - }; describe('SummaryCards', () => { diff --git a/src/__tests__/renderer/components/UsageDashboard/chart-accessibility.test.tsx b/src/__tests__/renderer/components/UsageDashboard/chart-accessibility.test.tsx index 3973e8d8..37bbff61 100644 --- a/src/__tests__/renderer/components/UsageDashboard/chart-accessibility.test.tsx +++ b/src/__tests__/renderer/components/UsageDashboard/chart-accessibility.test.tsx @@ -70,7 +70,6 @@ const mockStatsData: StatsAggregation = { avgSessionDuration: 288000, byAgentByDay: {}, bySessionByDay: {}, - }; describe('Chart Accessibility - AgentComparisonChart', () => { @@ -411,10 +410,9 @@ describe('Chart Accessibility - General ARIA Patterns', () => { sessionsByDay: [], avgSessionDuration: 0, byAgentByDay: {}, - bySessionByDay: {}, + bySessionByDay: {}, }; - render(); expect(screen.getByText(/no agent data available/i)).toBeInTheDocument(); }); diff --git a/src/__tests__/renderer/components/UsageDashboard/responsive-layout.test.tsx b/src/__tests__/renderer/components/UsageDashboard/responsive-layout.test.tsx index 6267e20b..6dcc0ceb 100644 --- a/src/__tests__/renderer/components/UsageDashboard/responsive-layout.test.tsx +++ b/src/__tests__/renderer/components/UsageDashboard/responsive-layout.test.tsx @@ -212,7 +212,6 @@ const createSampleData = () => ({ avgSessionDuration: 144000, byAgentByDay: {}, bySessionByDay: {}, - }); describe('UsageDashboard Responsive Layout', () => { diff --git a/src/__tests__/renderer/components/UsageDashboard/state-transition-animations.test.tsx b/src/__tests__/renderer/components/UsageDashboard/state-transition-animations.test.tsx index d3109777..ee73a056 100644 --- a/src/__tests__/renderer/components/UsageDashboard/state-transition-animations.test.tsx +++ b/src/__tests__/renderer/components/UsageDashboard/state-transition-animations.test.tsx @@ -159,10 +159,9 @@ beforeEach(() => { ], avgSessionDuration: 180000, byAgentByDay: {}, - bySessionByDay: {}, + bySessionByDay: {}, }); mockStats.getDatabaseSize.mockResolvedValue(1024 * 1024); // 1 MB - }); afterEach(() => { @@ -282,7 +281,7 @@ describe('Usage Dashboard State Transition Animations', () => { sessionsByDay: [], avgSessionDuration: 240000, byAgentByDay: {}, - bySessionByDay: {}, + bySessionByDay: {}, }; it('applies dashboard-card-enter class to metric cards', () => { @@ -589,5 +588,4 @@ describe('Usage Dashboard State Transition Animations', () => { expect(totalMaxDuration).toBeLessThan(1000); }); }); - }); diff --git a/src/__tests__/renderer/components/UsageDashboardModal.test.tsx b/src/__tests__/renderer/components/UsageDashboardModal.test.tsx index 4d82507f..3b902670 100644 --- a/src/__tests__/renderer/components/UsageDashboardModal.test.tsx +++ b/src/__tests__/renderer/components/UsageDashboardModal.test.tsx @@ -147,7 +147,6 @@ const createSampleData = () => ({ avgSessionDuration: 144000, byAgentByDay: {}, bySessionByDay: {}, - }); describe('UsageDashboardModal', () => { diff --git a/src/main/index.ts b/src/main/index.ts index e5b80162..c949ea7b 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -642,9 +642,10 @@ function createWindow() { logger.warn(`Failed to load electron-devtools-installer: ${err.message}`, 'Window') ); - mainWindow.loadURL('http://localhost:5173'); + const vitePort = process.env.VITE_PORT || '5173'; + mainWindow.loadURL(`http://localhost:${vitePort}`); // DevTools can be opened via Command-K menu instead of automatically on startup - logger.info('Loading development server', 'Window'); + logger.info(`Loading development server on port ${vitePort}`, 'Window'); } else { mainWindow.loadFile(path.join(__dirname, '../renderer/index.html')); logger.info('Loading production build', 'Window'); diff --git a/src/renderer/index.html b/src/renderer/index.html index 2a1a073a..dd23f837 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -211,8 +211,8 @@