mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
## CHANGES
- Added `dev:prod-data` to develop against real production sessions safely 🧪 - Dev mode now defaults to an isolated `maestro-dev` data directory 🗂️ - App can explicitly opt into production userData via `USE_PROD_DATA=1` 🔀 - Contributor docs now clearly map dev commands to their data directories 📚 - Reduced dev/production database lock conflicts when running side-by-side 🔒 - Tab hover overlay redesigned to look like a clean “open folder” panel 🗃️ - Removed tab title tooltip to streamline the tab interaction feel ✂️ - Toast logging now captures whether audio/TTS notifications were enabled 🎙️ - Toast logs include the exact audio command used for notifications 🧾 - TTS playback now reuses captured audio state for consistent behavior 🔊
This commit is contained in:
19
CLAUDE.md
19
CLAUDE.md
@@ -27,15 +27,16 @@ Maestro is an Electron desktop app for managing multiple AI coding assistants (C
|
||||
## Quick Commands
|
||||
|
||||
```bash
|
||||
npm run dev # Development with hot reload
|
||||
npm run dev:web # Web interface development
|
||||
npm run build # Full production build
|
||||
npm run clean # Clean build artifacts
|
||||
npm run lint # TypeScript type checking (all configs)
|
||||
npm run lint:eslint # ESLint code quality checks
|
||||
npm run package # Package for all platforms
|
||||
npm run test # Run test suite
|
||||
npm run test:watch # Run tests in watch mode
|
||||
npm run dev # Development with hot reload (isolated data, can run alongside production)
|
||||
npm run dev:prod-data # Development using production data (close production app first)
|
||||
npm run dev:web # Web interface development
|
||||
npm run build # Full production build
|
||||
npm run clean # Clean build artifacts
|
||||
npm run lint # TypeScript type checking (all configs)
|
||||
npm run lint:eslint # ESLint code quality checks
|
||||
npm run package # Package for all platforms
|
||||
npm run test # Run test suite
|
||||
npm run test:watch # Run tests in watch mode
|
||||
```
|
||||
|
||||
## Architecture at a Glance
|
||||
|
||||
@@ -97,7 +97,8 @@ maestro/
|
||||
## Development Scripts
|
||||
|
||||
```bash
|
||||
npm run dev # Start dev server with hot reload
|
||||
npm run dev # Start dev server with hot reload (isolated data directory)
|
||||
npm run dev:prod-data # Start dev server using production data (requires closing production app)
|
||||
npm run dev:demo # Start in demo mode (fresh settings, isolated data)
|
||||
npm run dev:web # Start web interface dev server
|
||||
npm run build # Full production build (main + renderer + web + CLI)
|
||||
@@ -114,6 +115,21 @@ npm run package:win # Package for Windows
|
||||
npm run package:linux # Package for Linux
|
||||
```
|
||||
|
||||
### Development Data Directories
|
||||
|
||||
By default, `npm run dev` uses an isolated data directory (`~/Library/Application Support/maestro-dev/`) separate from production. This allows you to run both dev and production instances simultaneously—useful when using the production Maestro to work on the dev instance.
|
||||
|
||||
| Command | Data Directory | Can Run Alongside Production? |
|
||||
|---------|---------------|-------------------------------|
|
||||
| `npm run dev` | `maestro-dev/` | ✅ Yes |
|
||||
| `npm run dev:prod-data` | `maestro/` (production) | ❌ No - close production first |
|
||||
| `npm run dev:demo` | `/tmp/maestro-demo/` | ✅ Yes |
|
||||
|
||||
**When to use each:**
|
||||
- **`npm run dev`** — Default for most development. Start fresh or use dev-specific test data.
|
||||
- **`npm run dev:prod-data`** — Test with your real sessions and settings. Must close production app first to avoid database lock conflicts.
|
||||
- **`npm run dev:demo`** — Screenshots, demos, or testing with completely fresh state.
|
||||
|
||||
### Demo Mode
|
||||
|
||||
Use demo mode to run Maestro with a fresh, isolated data directory - useful for demos, testing, or screenshots without affecting your real settings:
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "concurrently \"npm run dev:main\" \"npm run dev:renderer\"",
|
||||
"dev:prod-data": "USE_PROD_DATA=1 concurrently \"npm run dev:main:prod-data\" \"npm run dev:renderer\"",
|
||||
"dev:demo": "MAESTRO_DEMO_DIR=/tmp/maestro-demo npm run dev",
|
||||
"dev:main": "npm run build:prompts && tsc -p tsconfig.main.json && NODE_ENV=development electron .",
|
||||
"dev:main:prod-data": "npm run build:prompts && tsc -p tsconfig.main.json && NODE_ENV=development USE_PROD_DATA=1 electron .",
|
||||
"dev:renderer": "vite",
|
||||
"dev:web": "vite --config vite.config.web.mts",
|
||||
"build": "npm run build:prompts && npm run build:main && npm run build:renderer && npm run build:web && npm run build:cli",
|
||||
|
||||
@@ -101,10 +101,13 @@ if (DEMO_MODE) {
|
||||
|
||||
// Development mode: use a separate data directory to allow running alongside production
|
||||
// This prevents database lock conflicts (e.g., Service Worker storage)
|
||||
if (isDevelopment && !DEMO_MODE) {
|
||||
// Set USE_PROD_DATA=1 to use the production data directory instead (requires closing production app)
|
||||
if (isDevelopment && !DEMO_MODE && !process.env.USE_PROD_DATA) {
|
||||
const devDataPath = path.join(app.getPath('userData'), '..', 'maestro-dev');
|
||||
app.setPath('userData', devDataPath);
|
||||
console.log(`[DEV MODE] Using data directory: ${devDataPath}`);
|
||||
} else if (isDevelopment && process.env.USE_PROD_DATA) {
|
||||
console.log(`[DEV MODE] Using production data directory: ${app.getPath('userData')}`);
|
||||
}
|
||||
|
||||
// Type definitions
|
||||
|
||||
@@ -333,7 +333,6 @@ function Tab({
|
||||
onDragOver={onDragOver}
|
||||
onDragEnd={onDragEnd}
|
||||
onDrop={onDrop}
|
||||
title={tab.name || tab.agentSessionId || 'New tab'}
|
||||
>
|
||||
{/* Busy indicator - pulsing dot for tabs in write mode */}
|
||||
{tab.state === 'busy' && (
|
||||
@@ -429,23 +428,16 @@ function Tab({
|
||||
setIsHovered(false);
|
||||
}}
|
||||
>
|
||||
{/* Connector tab that visually bridges the gap between tab and overlay */}
|
||||
{/* Main overlay content - connects directly to tab like an open folder */}
|
||||
<div
|
||||
className="shadow-xl overflow-hidden"
|
||||
style={{
|
||||
width: overlayPosition.tabWidth || 100,
|
||||
height: '6px',
|
||||
backgroundColor: theme.colors.bgSidebar,
|
||||
borderLeft: `1px solid ${theme.colors.border}`,
|
||||
borderRight: `1px solid ${theme.colors.border}`,
|
||||
marginBottom: '-1px' // Overlap with main overlay to hide seam
|
||||
}}
|
||||
/>
|
||||
{/* Main overlay content */}
|
||||
<div
|
||||
className="rounded-b-lg rounded-tr-lg shadow-xl border overflow-hidden"
|
||||
style={{
|
||||
backgroundColor: theme.colors.bgSidebar,
|
||||
borderColor: theme.colors.border,
|
||||
borderBottom: `1px solid ${theme.colors.border}`,
|
||||
borderBottomLeftRadius: '8px',
|
||||
borderBottomRightRadius: '8px',
|
||||
minWidth: '220px'
|
||||
}}
|
||||
>
|
||||
@@ -642,7 +634,7 @@ function Tab({
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
)}
|
||||
|
||||
@@ -87,7 +87,10 @@ export function ToastProvider({ children, defaultDuration: initialDuration = 20
|
||||
setToasts(prev => [...prev, newToast]);
|
||||
}
|
||||
|
||||
// Log toast to system logs
|
||||
// Capture audio feedback state for logging
|
||||
const { enabled: audioEnabled, command: audioCommand } = audioFeedbackRef.current;
|
||||
|
||||
// Log toast to system logs (include audio notification info)
|
||||
window.maestro.logger.toast(toast.title, {
|
||||
type: toast.type,
|
||||
message: toast.message,
|
||||
@@ -95,13 +98,19 @@ export function ToastProvider({ children, defaultDuration: initialDuration = 20
|
||||
project: toast.project,
|
||||
taskDuration: toast.taskDuration,
|
||||
agentSessionId: toast.agentSessionId,
|
||||
tabName: toast.tabName
|
||||
tabName: toast.tabName,
|
||||
// Audio/TTS notification info
|
||||
audioNotification: audioEnabled && audioCommand ? {
|
||||
enabled: true,
|
||||
command: audioCommand
|
||||
} : {
|
||||
enabled: false
|
||||
}
|
||||
});
|
||||
|
||||
// Speak toast via TTS if audio feedback is enabled and command is configured
|
||||
const { enabled, command } = audioFeedbackRef.current;
|
||||
if (enabled && command) {
|
||||
window.maestro.notification.speak(toast.message, command).catch(err => {
|
||||
if (audioEnabled && audioCommand) {
|
||||
window.maestro.notification.speak(toast.message, audioCommand).catch(err => {
|
||||
console.error('[ToastContext] Failed to speak toast:', err);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user