mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
gss
This commit is contained in:
362
CONTRIBUTING.md
362
CONTRIBUTING.md
@@ -1,19 +1,20 @@
|
|||||||
# Contributing to Maestro
|
# Contributing to Maestro
|
||||||
|
|
||||||
Thank you for your interest in contributing to Maestro! This document provides guidelines, setup instructions, and architectural information for developers.
|
Thank you for your interest in contributing to Maestro! This document provides guidelines, setup instructions, and practical guidance for developers.
|
||||||
|
|
||||||
|
For architecture details, see [ARCHITECTURE.md](ARCHITECTURE.md). For quick reference while coding, see [CLAUDE.md](CLAUDE.md).
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Development Setup](#development-setup)
|
- [Development Setup](#development-setup)
|
||||||
- [Project Structure](#project-structure)
|
- [Project Structure](#project-structure)
|
||||||
- [Tech Stack](#tech-stack)
|
|
||||||
- [Development Scripts](#development-scripts)
|
- [Development Scripts](#development-scripts)
|
||||||
- [Architecture](#architecture)
|
- [Common Development Tasks](#common-development-tasks)
|
||||||
- [Code Style](#code-style)
|
- [Code Style](#code-style)
|
||||||
|
- [Debugging Guide](#debugging-guide)
|
||||||
- [Commit Messages](#commit-messages)
|
- [Commit Messages](#commit-messages)
|
||||||
- [Pull Request Process](#pull-request-process)
|
- [Pull Request Process](#pull-request-process)
|
||||||
- [Building for Release](#building-for-release)
|
- [Building for Release](#building-for-release)
|
||||||
- [GitHub Actions Workflow](#github-actions-workflow)
|
|
||||||
|
|
||||||
## Development Setup
|
## Development Setup
|
||||||
|
|
||||||
@@ -43,162 +44,254 @@ npm run dev
|
|||||||
maestro/
|
maestro/
|
||||||
├── src/
|
├── src/
|
||||||
│ ├── main/ # Electron main process (Node.js backend)
|
│ ├── main/ # Electron main process (Node.js backend)
|
||||||
│ │ ├── utils/ # Shared utilities
|
│ │ ├── index.ts # Entry point, IPC handlers
|
||||||
│ │ └── ... # Process management, IPC, web server
|
│ │ ├── process-manager.ts
|
||||||
|
│ │ ├── preload.ts # Secure IPC bridge
|
||||||
|
│ │ └── utils/ # Shared utilities
|
||||||
│ └── renderer/ # React frontend (UI)
|
│ └── renderer/ # React frontend (UI)
|
||||||
│ ├── components/ # React components (UI elements, modals, panels)
|
│ ├── App.tsx # Main coordinator
|
||||||
│ ├── hooks/ # Custom React hooks (reusable state logic)
|
│ ├── components/ # React components
|
||||||
│ ├── services/ # Business logic services (git, process management)
|
│ ├── hooks/ # Custom React hooks
|
||||||
|
│ ├── services/ # IPC wrappers (git, process)
|
||||||
|
│ ├── contexts/ # React contexts
|
||||||
|
│ ├── constants/ # Themes, shortcuts, priorities
|
||||||
│ ├── types/ # TypeScript definitions
|
│ ├── types/ # TypeScript definitions
|
||||||
│ ├── utils/ # Frontend utilities
|
│ └── utils/ # Frontend utilities
|
||||||
│ └── constants/ # App constants (themes, shortcuts, emojis)
|
|
||||||
├── build/ # Application icons
|
├── build/ # Application icons
|
||||||
├── .github/workflows/ # CI/CD automation
|
├── .github/workflows/ # CI/CD automation
|
||||||
└── dist/ # Build output (generated)
|
└── dist/ # Build output (generated)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
|
|
||||||
### Backend (Electron Main Process)
|
|
||||||
|
|
||||||
- **Electron 28+** - Desktop application framework
|
|
||||||
- **TypeScript** - Type-safe JavaScript
|
|
||||||
- **node-pty** - Terminal emulation for shell sessions
|
|
||||||
- **Fastify** - High-performance web server for remote access
|
|
||||||
- **electron-store** - Persistent settings storage
|
|
||||||
|
|
||||||
### Frontend (Renderer Process)
|
|
||||||
|
|
||||||
- **React 18** - UI framework
|
|
||||||
- **TypeScript** - Type-safe JavaScript
|
|
||||||
- **Tailwind CSS** - Utility-first CSS framework
|
|
||||||
- **Vite** - Fast build tool and dev server
|
|
||||||
- **Lucide React** - Icon library
|
|
||||||
- **marked** - Markdown rendering
|
|
||||||
- **react-syntax-highlighter** - Code syntax highlighting
|
|
||||||
- **ansi-to-html** - Terminal ANSI escape code rendering
|
|
||||||
- **dompurify** - HTML sanitization for XSS prevention
|
|
||||||
- **emoji-mart** - Emoji picker component
|
|
||||||
|
|
||||||
## Development Scripts
|
## Development Scripts
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start dev server with hot reload
|
npm run dev # Start dev server with hot reload
|
||||||
npm run dev
|
npm run build # Full production build
|
||||||
|
npm run build:main # Build main process only
|
||||||
# Build main process only (Electron backend)
|
npm run build:renderer # Build renderer only
|
||||||
npm run build:main
|
npm start # Start built application
|
||||||
|
npm run clean # Clean build artifacts
|
||||||
# Build renderer only (React frontend)
|
npm run package # Package for all platforms
|
||||||
npm run build:renderer
|
npm run package:mac # Package for macOS
|
||||||
|
npm run package:win # Package for Windows
|
||||||
# Full production build
|
npm run package:linux # Package for Linux
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Start built application
|
|
||||||
npm start
|
|
||||||
|
|
||||||
# Clean build artifacts and cache
|
|
||||||
npm run clean
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Architecture
|
## Common Development Tasks
|
||||||
|
|
||||||
### Process Management
|
### Adding a New UI Feature
|
||||||
|
|
||||||
Maestro uses a dual-process architecture where **each session runs two processes simultaneously**:
|
1. **Plan the state** - Determine if it's per-session or global
|
||||||
|
2. **Add state management** - In `useSettings.ts` (global) or session state
|
||||||
|
3. **Create persistence** - Use wrapper function pattern for global settings
|
||||||
|
4. **Implement UI** - Follow Tailwind + theme color pattern
|
||||||
|
5. **Add keyboard shortcuts** - In `shortcuts.ts` and `App.tsx`
|
||||||
|
6. **Test focus flow** - Ensure Escape key navigation works
|
||||||
|
|
||||||
1. **AI Agent Process** - Runs Claude Code as a child process
|
### Adding a New Modal
|
||||||
2. **Terminal Process** - Runs a PTY shell session for command execution
|
|
||||||
|
|
||||||
This architecture enables seamless switching between AI and terminal modes without process restarts. All processes are managed through IPC (Inter-Process Communication) with secure context isolation.
|
1. Create component in `src/renderer/components/`
|
||||||
|
2. Add priority in `src/renderer/constants/modalPriorities.ts`:
|
||||||
|
```typescript
|
||||||
|
MY_MODAL: 600,
|
||||||
|
```
|
||||||
|
3. Register with layer stack (see [ARCHITECTURE.md](ARCHITECTURE.md#layer-stack-system))
|
||||||
|
4. Use proper ARIA attributes:
|
||||||
|
```typescript
|
||||||
|
<div role="dialog" aria-modal="true" aria-label="My Modal">
|
||||||
|
```
|
||||||
|
|
||||||
### Security Model
|
### Adding Keyboard Shortcuts
|
||||||
|
|
||||||
Maestro implements strict security measures:
|
1. Add definition in `src/renderer/constants/shortcuts.ts`:
|
||||||
|
```typescript
|
||||||
|
myShortcut: { id: 'myShortcut', label: 'My Action', keys: ['Meta', 'k'] },
|
||||||
|
```
|
||||||
|
|
||||||
- **Context isolation enabled** - Renderer has no direct Node.js access
|
2. Add handler in `App.tsx` keyboard event listener:
|
||||||
- **No node integration in renderer** - No `require()` in renderer process
|
```typescript
|
||||||
- **Secure IPC via preload script** - Minimal API exposed via `contextBridge`
|
else if (isShortcut(e, 'myShortcut')) {
|
||||||
- **No shell injection** - Uses `execFile` instead of `exec`
|
e.preventDefault();
|
||||||
- **Input sanitization** - All user inputs are validated
|
// Handler code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Main Process (Backend)
|
**Supported modifiers:** `Meta` (Cmd/Win), `Ctrl`, `Alt`, `Shift`
|
||||||
|
**Arrow keys:** `ArrowLeft`, `ArrowRight`, `ArrowUp`, `ArrowDown`
|
||||||
|
|
||||||
Located in `src/main/`:
|
### Adding a New Setting
|
||||||
|
|
||||||
- `index.ts` - Application entry point, IPC handler registration, window management
|
1. Add state in `useSettings.ts`:
|
||||||
- `process-manager.ts` - Core primitive for spawning and managing CLI processes
|
```typescript
|
||||||
- `web-server.ts` - Fastify-based HTTP/WebSocket server for remote access
|
const [mySetting, setMySettingState] = useState(defaultValue);
|
||||||
- `agent-detector.ts` - Auto-detects available AI tools via PATH
|
```
|
||||||
- `preload.ts` - Secure IPC bridge via contextBridge
|
|
||||||
|
|
||||||
### Renderer Process (Frontend)
|
2. Create wrapper function:
|
||||||
|
```typescript
|
||||||
|
const setMySetting = (value) => {
|
||||||
|
setMySettingState(value);
|
||||||
|
window.maestro.settings.set('mySetting', value);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Located in `src/renderer/`:
|
3. Load in useEffect:
|
||||||
|
```typescript
|
||||||
|
const saved = await window.maestro.settings.get('mySetting');
|
||||||
|
if (saved !== undefined) setMySettingState(saved);
|
||||||
|
```
|
||||||
|
|
||||||
- `App.tsx` - Main UI coordinator
|
4. Add to return object and export.
|
||||||
- `main.tsx` - Renderer entry point
|
|
||||||
- `components/` - React components (modals, panels, UI elements)
|
### Adding a Slash Command
|
||||||
- `hooks/` - Custom React hooks for reusable state logic
|
|
||||||
- `services/` - Business logic services (clean wrappers around IPC calls)
|
Add to `src/renderer/slashCommands.ts`:
|
||||||
- `constants/` - Application constants (themes, shortcuts, etc.)
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
command: '/mycommand',
|
||||||
|
description: 'Does something useful',
|
||||||
|
terminalOnly: false, // Optional: restrict to terminal mode
|
||||||
|
execute: (context) => {
|
||||||
|
const { activeSessionId, setSessions } = context;
|
||||||
|
// Your logic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding a New Theme
|
||||||
|
|
||||||
|
Add to `src/renderer/constants/themes.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
'my-theme': {
|
||||||
|
id: 'my-theme',
|
||||||
|
name: 'My Theme',
|
||||||
|
mode: 'dark', // or 'light'
|
||||||
|
colors: {
|
||||||
|
bgMain: '#...',
|
||||||
|
bgSidebar: '#...',
|
||||||
|
bgActivity: '#...',
|
||||||
|
border: '#...',
|
||||||
|
textMain: '#...',
|
||||||
|
textDim: '#...',
|
||||||
|
accent: '#...',
|
||||||
|
accentDim: 'rgba(...)',
|
||||||
|
accentText: '#...',
|
||||||
|
success: '#...',
|
||||||
|
warning: '#...',
|
||||||
|
error: '#...',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then add the ID to `ThemeId` type in `src/renderer/types/index.ts`.
|
||||||
|
|
||||||
|
### Adding an IPC Handler
|
||||||
|
|
||||||
|
1. Add handler in `src/main/index.ts`:
|
||||||
|
```typescript
|
||||||
|
ipcMain.handle('myNamespace:myAction', async (_, arg1, arg2) => {
|
||||||
|
// Implementation
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Expose in `src/main/preload.ts`:
|
||||||
|
```typescript
|
||||||
|
myNamespace: {
|
||||||
|
myAction: (arg1, arg2) => ipcRenderer.invoke('myNamespace:myAction', arg1, arg2),
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Add types to `MaestroAPI` interface in preload.ts.
|
||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
### TypeScript
|
### TypeScript
|
||||||
|
|
||||||
- All code must be TypeScript with strict mode enabled
|
- Strict mode enabled
|
||||||
- Define interfaces for all data structures
|
- Interface definitions for all data structures
|
||||||
- Export types via `preload.ts` for renderer types
|
- Export types via `preload.ts` for renderer
|
||||||
|
|
||||||
### React Components
|
### React Components
|
||||||
|
|
||||||
- Use functional components with hooks
|
- Functional components with hooks
|
||||||
- Keep components small and focused
|
- Keep components focused and small
|
||||||
- Use Tailwind CSS for styling
|
- Use Tailwind for layout, inline styles for theme colors
|
||||||
- Maintain keyboard accessibility
|
- Maintain keyboard accessibility
|
||||||
- Use inline styles for theme colors, Tailwind for layout
|
- Use `tabIndex={-1}` + `outline-none` for programmatic focus
|
||||||
|
|
||||||
### Architecture Guidelines
|
### Security
|
||||||
|
|
||||||
**Main Process:**
|
- **Always use `execFileNoThrow`** for external commands (never shell-based execution)
|
||||||
- Keep IPC handlers simple and focused
|
- Keep context isolation enabled
|
||||||
- Use TypeScript interfaces for all data structures
|
|
||||||
- Handle errors gracefully
|
|
||||||
- No blocking operations
|
|
||||||
|
|
||||||
**Renderer Process:**
|
|
||||||
- Use React hooks
|
|
||||||
- Keep components small and focused
|
|
||||||
- Use Tailwind for styling
|
|
||||||
- Maintain keyboard accessibility
|
|
||||||
|
|
||||||
**Security:**
|
|
||||||
- Never expose Node.js APIs to renderer
|
|
||||||
- Use preload script for all IPC
|
- Use preload script for all IPC
|
||||||
- Sanitize all user inputs
|
- Sanitize all user inputs
|
||||||
- Use `execFile` instead of `exec`
|
- Use `spawn()` with `shell: false`
|
||||||
|
|
||||||
|
## Debugging Guide
|
||||||
|
|
||||||
|
### Focus Not Working
|
||||||
|
|
||||||
|
1. Add `tabIndex={0}` or `tabIndex={-1}` to element
|
||||||
|
2. Add `outline-none` class to hide focus ring
|
||||||
|
3. Use `ref={(el) => el?.focus()}` for auto-focus
|
||||||
|
4. Check for `e.stopPropagation()` blocking events
|
||||||
|
|
||||||
|
### Settings Not Persisting
|
||||||
|
|
||||||
|
1. Ensure wrapper function calls `window.maestro.settings.set()`
|
||||||
|
2. Check loading code in `useSettings.ts` useEffect
|
||||||
|
3. Verify the key name matches in both save and load
|
||||||
|
|
||||||
|
### Modal Escape Not Working
|
||||||
|
|
||||||
|
1. Register modal with layer stack (don't handle Escape locally)
|
||||||
|
2. Check priority in `modalPriorities.ts`
|
||||||
|
3. Use ref pattern to avoid re-registration:
|
||||||
|
```typescript
|
||||||
|
const onCloseRef = useRef(onClose);
|
||||||
|
onCloseRef.current = onClose;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Theme Colors Not Applying
|
||||||
|
|
||||||
|
1. Use `style={{ color: theme.colors.textMain }}` instead of Tailwind color classes
|
||||||
|
2. Check theme prop is passed to component
|
||||||
|
3. Never use hardcoded hex colors for themed elements
|
||||||
|
|
||||||
|
### Process Output Not Showing
|
||||||
|
|
||||||
|
1. Check session ID matches (with `-ai` or `-terminal` suffix)
|
||||||
|
2. Verify `onData` listener is registered
|
||||||
|
3. Check process spawned successfully (check pid > 0)
|
||||||
|
4. Look for errors in DevTools console
|
||||||
|
|
||||||
|
### DevTools
|
||||||
|
|
||||||
|
Open via Quick Actions (`Cmd+K` → "Toggle DevTools") or set `DEBUG=true` env var.
|
||||||
|
|
||||||
## Commit Messages
|
## Commit Messages
|
||||||
|
|
||||||
Use conventional commits:
|
Use conventional commits:
|
||||||
|
|
||||||
- `feat:` - New features
|
```
|
||||||
- `fix:` - Bug fixes
|
feat: new feature
|
||||||
- `docs:` - Documentation changes
|
fix: bug fix
|
||||||
- `refactor:` - Code refactoring
|
docs: documentation changes
|
||||||
- `test:` - Test additions/changes
|
refactor: code refactoring
|
||||||
- `chore:` - Build process or tooling changes
|
test: test additions/changes
|
||||||
|
chore: build process or tooling changes
|
||||||
|
```
|
||||||
|
|
||||||
Example: `feat: add context usage visualization`
|
Example: `feat: add context usage visualization`
|
||||||
|
|
||||||
## Pull Request Process
|
## Pull Request Process
|
||||||
|
|
||||||
1. Create a feature branch from `main`
|
1. Create a feature branch from `main`
|
||||||
2. Make your changes
|
2. Make your changes following the code style
|
||||||
3. Add tests if applicable
|
3. Test thoroughly (keyboard navigation, themes, focus)
|
||||||
4. Update documentation
|
4. Update documentation if needed
|
||||||
5. Submit PR with clear description
|
5. Submit PR with clear description
|
||||||
6. Wait for review
|
6. Wait for review
|
||||||
|
|
||||||
@@ -206,16 +299,14 @@ Example: `feat: add context usage visualization`
|
|||||||
|
|
||||||
### 1. Prepare Icons
|
### 1. Prepare Icons
|
||||||
|
|
||||||
Place your application icons in the `build/` directory:
|
Place icons in `build/` directory:
|
||||||
|
|
||||||
- `icon.icns` - macOS (512x512 or 1024x1024)
|
- `icon.icns` - macOS (512x512 or 1024x1024)
|
||||||
- `icon.ico` - Windows (256x256)
|
- `icon.ico` - Windows (256x256)
|
||||||
- `icon.png` - Linux (512x512)
|
- `icon.png` - Linux (512x512)
|
||||||
|
|
||||||
### 2. Update Version
|
### 2. Update Version
|
||||||
|
|
||||||
Update version in `package.json`:
|
Update in `package.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"version": "0.1.0"
|
"version": "0.1.0"
|
||||||
@@ -225,42 +316,25 @@ Update version in `package.json`:
|
|||||||
### 3. Build Distributables
|
### 3. Build Distributables
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build for all platforms
|
npm run package # All platforms
|
||||||
npm run package
|
npm run package:mac # macOS (.dmg, .zip)
|
||||||
|
npm run package:win # Windows (.exe)
|
||||||
# Platform-specific builds
|
npm run package:linux # Linux (.AppImage, .deb, .rpm)
|
||||||
npm run package:mac # Creates .dmg and .zip
|
|
||||||
npm run package:win # Creates .exe installer
|
|
||||||
npm run package:linux # Creates .AppImage, .deb, .rpm
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Output will be in the `release/` directory.
|
Output in `release/` directory.
|
||||||
|
|
||||||
## GitHub Actions Workflow
|
### GitHub Actions
|
||||||
|
|
||||||
The project includes automated builds via GitHub Actions:
|
Create a release tag to trigger automated builds:
|
||||||
|
|
||||||
1. **Create a release tag:**
|
|
||||||
```bash
|
|
||||||
git tag v0.1.0
|
|
||||||
git push origin v0.1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **GitHub Actions will automatically:**
|
|
||||||
- Build for macOS, Windows, and Linux
|
|
||||||
- Create release artifacts
|
|
||||||
- Publish a GitHub Release with downloads
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run tests (when available)
|
git tag v0.1.0
|
||||||
npm test
|
git push origin v0.1.0
|
||||||
|
|
||||||
# Type checking
|
|
||||||
npm run build:main
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
GitHub Actions will build for all platforms and create a release.
|
||||||
|
|
||||||
## Questions?
|
## Questions?
|
||||||
|
|
||||||
Open a GitHub Discussion or reach out in Issues.
|
Open a GitHub Discussion or create an Issue.
|
||||||
|
|||||||
Reference in New Issue
Block a user