mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
dropped Aider across the code base and documentation
This commit is contained in:
@@ -9,10 +9,9 @@ Agent support documentation for the Maestro codebase. For the main guide, see [[
|
||||
| `claude-code` | Claude Code | **Active** | Primary agent, `--print --verbose --output-format stream-json` |
|
||||
| `codex` | OpenAI Codex | **Active** | Full support, `--json`, YOLO mode default |
|
||||
| `opencode` | OpenCode | **Active** | Multi-provider support (75+ LLMs), stub session storage |
|
||||
| `factory-droid` | Factory Droid | **Active** | Factory's AI coding assistant, `-o stream-json` |
|
||||
| `terminal` | Terminal | Internal | Hidden from UI, used for shell sessions |
|
||||
|
||||
Additional `ToolType` values (`aider`, `claude`) are defined in types but not yet implemented in `agent-detector.ts`.
|
||||
|
||||
## Agent Capabilities
|
||||
|
||||
Each agent declares capabilities that control UI feature availability. See `src/main/agent-capabilities.ts` for the full interface.
|
||||
|
||||
@@ -10,7 +10,7 @@ Maestro is a cross-platform desktop app for orchestrating your fleet of AI agent
|
||||
|
||||
Collaborate with AI to create detailed specification documents, then let Auto Run execute them automatically, each task in a fresh session with clean context. Allowing for long-running unattended sessions, my current record is nearly 24 hours of continuous runtime.
|
||||
|
||||
Run multiple agents in parallel with a Linear/Superhuman-level responsive interface. Currently supporting **Claude Code**, **OpenAI Codex**, and **OpenCode** with plans for additional agentic coding tools (Aider, Gemini CLI, Qwen3 Coder) based on user demand.
|
||||
Run multiple agents in parallel with a Linear/Superhuman-level responsive interface. Currently supporting **Claude Code**, **OpenAI Codex**, **OpenCode**, and **Factory Droid** with plans for additional agentic coding tools (Gemini CLI, Qwen3 Coder) based on user demand.
|
||||
|
||||
<div align="center">
|
||||
<a href="https://youtu.be/fmwwTOg7cyA?si=dJ89K54tGflKa5G4">
|
||||
@@ -79,7 +79,7 @@ Run multiple agents in parallel with a Linear/Superhuman-level responsive interf
|
||||
|
||||
Additional interactions: Drag nodes to reposition, scroll to zoom, use mini-map for overview.
|
||||
|
||||
> **Note**: Maestro supports Claude Code, OpenAI Codex, and OpenCode. Support for additional agents (Aider, Gemini CLI, Qwen3 Coder) may be added in future releases based on community demand.
|
||||
> **Note**: Maestro supports Claude Code, OpenAI Codex, OpenCode, and Factory Droid. Support for additional agents (Gemini CLI, Qwen3 Coder) may be added in future releases based on community demand.
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
||||
@@ -34,4 +34,4 @@ icon: sparkles
|
||||
- 📊 **[Usage Dashboard](./usage-dashboard)** - Comprehensive analytics for tracking AI usage patterns. View aggregated statistics, compare agent performance, analyze activity heatmaps, and export data to CSV. Access via `Opt+Cmd+U` / `Alt+Ctrl+U`.
|
||||
- 🏆 **[Achievements](./achievements)** - Level up from Apprentice to Titan of the Baton based on cumulative Auto Run time. 11 conductor-themed ranks to unlock.
|
||||
|
||||
> **Note**: Maestro currently supports Claude Code, Codex (OpenAI), and OpenCode as fully-integrated providers. Support for additional providers (Aider, Gemini CLI, Qwen3 Coder) is planned for future releases based on community demand.
|
||||
> **Note**: Maestro currently supports Claude Code, Codex (OpenAI), OpenCode, and Factory Droid as fully-integrated providers. Support for additional providers (Gemini CLI, Qwen3 Coder) is planned for future releases based on community demand.
|
||||
|
||||
@@ -10,7 +10,7 @@ Maestro is a cross-platform desktop app for orchestrating your fleet of AI agent
|
||||
|
||||
Collaborate with AI to create detailed specification documents, then let Auto Run execute them automatically, each task in a fresh session with clean context. Allowing for long-running unattended sessions, my current record is nearly 24 hours of continuous runtime.
|
||||
|
||||
Run multiple agents in parallel with a Linear/Superhuman-level responsive interface. Currently supporting **Claude Code**, **Codex** (OpenAI), and **OpenCode** with plans for additional agentic coding tools (Aider, Gemini CLI, Qwen3 Coder) based on user demand.
|
||||
Run multiple agents in parallel with a Linear/Superhuman-level responsive interface. Currently supporting **Claude Code**, **Codex** (OpenAI), **OpenCode**, and **Factory Droid** with plans for additional agentic coding tools (Gemini CLI, Qwen3 Coder) based on user demand.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ Download the latest release for your platform from the [Releases](https://github
|
||||
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) — Anthropic's AI coding assistant (fully integrated)
|
||||
- [Codex](https://github.com/openai/codex) — OpenAI's coding agent (fully integrated)
|
||||
- [OpenCode](https://github.com/sst/opencode) — Open-source AI coding assistant (fully integrated)
|
||||
- [Aider](https://github.com/paul-gauthier/aider), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Qwen3 Coder](https://github.com/QwenLM/Qwen-Agent) — Planned support
|
||||
- [Factory Droid](https://docs.factory.ai/cli) — Factory's AI coding assistant (fully integrated)
|
||||
- [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Qwen3 Coder](https://github.com/QwenLM/Qwen-Agent) — Planned support
|
||||
- Git (optional, for git-aware features)
|
||||
|
||||
## WSL2 Users (Windows Subsystem for Linux)
|
||||
|
||||
@@ -34,7 +34,7 @@ Commands support **template variables** that are automatically substituted at ru
|
||||
| `{{AGENT_GROUP}}` | Agent's group name (if grouped) |
|
||||
| `{{AGENT_SESSION_ID}}` | Agent session ID (for conversation continuity) |
|
||||
| `{{TAB_NAME}}` | Custom tab name (alias: `SESSION_NAME`) |
|
||||
| `{{TOOL_TYPE}}` | Agent type (claude-code, codex, opencode, aider) |
|
||||
| `{{TOOL_TYPE}}` | Agent type (claude-code, codex, opencode, factory-droid) |
|
||||
|
||||
### Path Variables
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('list-agents command', () => {
|
||||
it('should display agents in human-readable format', () => {
|
||||
const mockSessions: SessionInfo[] = [
|
||||
mockSession({ id: 'a1', name: 'Agent One', toolType: 'claude-code' }),
|
||||
mockSession({ id: 'a2', name: 'Agent Two', toolType: 'aider' }),
|
||||
mockSession({ id: 'a2', name: 'Agent Two', toolType: 'factory-droid' }),
|
||||
];
|
||||
vi.mocked(readSessions).mockReturnValue(mockSessions);
|
||||
|
||||
@@ -423,7 +423,7 @@ describe('list-agents command', () => {
|
||||
});
|
||||
|
||||
it('should handle all tool types', () => {
|
||||
const toolTypes = ['claude-code', 'aider', 'terminal', 'gemini-cli', 'qwen3-coder'];
|
||||
const toolTypes = ['claude-code', 'factory-droid', 'terminal', 'gemini-cli', 'qwen3-coder'];
|
||||
const mockSessions: SessionInfo[] = toolTypes.map((toolType, i) =>
|
||||
mockSession({ id: `agent-${i}`, name: `Agent ${i}`, toolType: toolType as any })
|
||||
);
|
||||
|
||||
@@ -526,7 +526,7 @@ describe('jsonl output', () => {
|
||||
const agent = {
|
||||
id: 'agent-456',
|
||||
name: 'Grouped Agent',
|
||||
toolType: 'aider',
|
||||
toolType: 'factory-droid',
|
||||
cwd: '/path',
|
||||
groupId: 'group-123',
|
||||
};
|
||||
@@ -576,7 +576,7 @@ describe('jsonl output', () => {
|
||||
});
|
||||
|
||||
it('should handle different tool types', () => {
|
||||
const toolTypes = ['claude-code', 'aider', 'terminal', 'gemini-cli', 'qwen3-coder'];
|
||||
const toolTypes = ['claude-code', 'factory-droid', 'terminal', 'gemini-cli', 'qwen3-coder'];
|
||||
|
||||
toolTypes.forEach((toolType, index) => {
|
||||
consoleSpy.mockClear();
|
||||
|
||||
@@ -341,7 +341,7 @@ describe('storage service', () => {
|
||||
const result = readAgentConfigs();
|
||||
|
||||
expect(result['claude-code']).toEqual({ customPath: '/custom/path' });
|
||||
expect(result['aider']).toEqual({ setting: 'value' });
|
||||
expect(result['factory-droid']).toEqual({ setting: 'value' });
|
||||
});
|
||||
|
||||
it('should return empty object when file does not exist', () => {
|
||||
@@ -389,7 +389,7 @@ describe('storage service', () => {
|
||||
})
|
||||
);
|
||||
|
||||
const result = getAgentCustomPath('aider');
|
||||
const result = getAgentCustomPath('factory-droid');
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -277,7 +277,7 @@ describe('agent-detector', () => {
|
||||
|
||||
const agents = await detector.detectAgents();
|
||||
|
||||
// Should have all 7 agents (terminal, claude-code, codex, gemini-cli, qwen3-coder, opencode, aider)
|
||||
// Should have all 7 agents (terminal, claude-code, codex, gemini-cli, qwen3-coder, opencode, factory-droid)
|
||||
expect(agents.length).toBe(7);
|
||||
|
||||
const agentIds = agents.map((a) => a.id);
|
||||
@@ -287,7 +287,7 @@ describe('agent-detector', () => {
|
||||
expect(agentIds).toContain('gemini-cli');
|
||||
expect(agentIds).toContain('qwen3-coder');
|
||||
expect(agentIds).toContain('opencode');
|
||||
expect(agentIds).toContain('aider');
|
||||
expect(agentIds).toContain('factory-droid');
|
||||
});
|
||||
|
||||
it('should mark agents as available when binary is found', async () => {
|
||||
|
||||
@@ -316,7 +316,7 @@ describe('agent-output-parser', () => {
|
||||
expect(isValidToolType('codex')).toBe(true);
|
||||
expect(isValidToolType('terminal')).toBe(true);
|
||||
expect(isValidToolType('claude')).toBe(true);
|
||||
expect(isValidToolType('aider')).toBe(true);
|
||||
expect(isValidToolType('factory-droid')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid agent IDs', () => {
|
||||
|
||||
@@ -825,8 +825,8 @@ describe('error-patterns', () => {
|
||||
],
|
||||
};
|
||||
|
||||
registerErrorPatterns('aider', customPatterns);
|
||||
const patterns = getErrorPatterns('aider');
|
||||
registerErrorPatterns('factory-droid', customPatterns);
|
||||
const patterns = getErrorPatterns('factory-droid');
|
||||
expect(patterns).toBe(customPatterns);
|
||||
});
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ describe('DEFAULT_CONTEXT_WINDOWS', () => {
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['claude']).toBe(200000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['codex']).toBe(200000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['opencode']).toBe(128000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['aider']).toBe(128000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['factory-droid']).toBe(200000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['terminal']).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ vi.mock('../../../renderer/services/contextGroomer', () => ({
|
||||
'claude-code': 'Claude Code',
|
||||
opencode: 'OpenCode',
|
||||
codex: 'OpenAI Codex',
|
||||
aider: 'Aider',
|
||||
factory-droid: 'Factory Droid',
|
||||
terminal: 'Terminal',
|
||||
};
|
||||
return names[toolType] || toolType;
|
||||
|
||||
@@ -37,7 +37,7 @@ vi.mock('../../../renderer/services/contextGroomer', () => ({
|
||||
'claude-code': 'Claude Code',
|
||||
opencode: 'OpenCode',
|
||||
codex: 'OpenAI Codex',
|
||||
aider: 'Aider',
|
||||
factory-droid: 'Factory Droid',
|
||||
terminal: 'Terminal',
|
||||
};
|
||||
return names[toolType] || toolType;
|
||||
|
||||
@@ -103,7 +103,7 @@ describe('AgentComparisonChart', () => {
|
||||
|
||||
// Use getAllByText since agent names appear in both bar labels and legend
|
||||
expect(screen.getAllByText('claude-code').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getAllByText('aider').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getAllByText('factory-droid').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getAllByText('terminal').length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
@@ -167,7 +167,7 @@ describe('AgentComparisonChart', () => {
|
||||
|
||||
// In duration mode, claude-code has highest duration (2000000), then aider (1600000), then terminal (500000)
|
||||
expect(agentNames[0]).toBe('claude-code');
|
||||
expect(agentNames[1]).toBe('aider');
|
||||
expect(agentNames[1]).toBe('factory-droid');
|
||||
expect(agentNames[2]).toBe('terminal');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,7 +76,7 @@ function generateManyAgentsData(numAgents: number): StatsAggregation {
|
||||
const byAgent: Record<string, { count: number; duration: number }> = {};
|
||||
const agentNames = [
|
||||
'claude-code',
|
||||
'aider',
|
||||
'factory-droid',
|
||||
'opencode',
|
||||
'gpt-engineer',
|
||||
'cursor',
|
||||
|
||||
@@ -885,7 +885,7 @@ describe('transfer edge cases', () => {
|
||||
});
|
||||
|
||||
it('handles all supported agent types as targets', async () => {
|
||||
const targetAgents: ToolType[] = ['opencode', 'aider', 'codex', 'claude'];
|
||||
const targetAgents: ToolType[] = ['opencode', 'factory-droid', 'codex', 'claude'];
|
||||
|
||||
for (const targetAgent of targetAgents) {
|
||||
vi.clearAllMocks();
|
||||
|
||||
@@ -466,7 +466,6 @@ describe('AGENT_ARTIFACTS', () => {
|
||||
it('should define artifacts for all agent types', () => {
|
||||
const expectedAgents: ToolType[] = [
|
||||
'claude-code',
|
||||
'aider',
|
||||
'opencode',
|
||||
'codex',
|
||||
'factory-droid',
|
||||
@@ -496,14 +495,6 @@ describe('AGENT_ARTIFACTS', () => {
|
||||
expect(artifacts).toContain('opus');
|
||||
});
|
||||
|
||||
it('should include aider-specific commands', () => {
|
||||
const artifacts = AGENT_ARTIFACTS['aider'];
|
||||
expect(artifacts).toContain('/add');
|
||||
expect(artifacts).toContain('/drop');
|
||||
expect(artifacts).toContain('/commit');
|
||||
expect(artifacts).toContain('Aider');
|
||||
});
|
||||
|
||||
it('should include codex-specific references', () => {
|
||||
const artifacts = AGENT_ARTIFACTS['codex'];
|
||||
expect(artifacts).toContain('Codex');
|
||||
@@ -521,9 +512,9 @@ describe('AGENT_TARGET_NOTES', () => {
|
||||
it('should define notes for all agent types', () => {
|
||||
const expectedAgents: ToolType[] = [
|
||||
'claude-code',
|
||||
'aider',
|
||||
'opencode',
|
||||
'codex',
|
||||
'factory-droid',
|
||||
'claude',
|
||||
'terminal',
|
||||
];
|
||||
@@ -542,11 +533,10 @@ describe('AGENT_TARGET_NOTES', () => {
|
||||
expect(notes).toContain('edit files');
|
||||
});
|
||||
|
||||
it('should mention git workflow in aider notes', () => {
|
||||
const notes = AGENT_TARGET_NOTES['aider'];
|
||||
expect(notes).toContain('git');
|
||||
expect(notes).toContain('/add');
|
||||
expect(notes).toContain('/drop');
|
||||
it('should mention Factory in factory-droid notes', () => {
|
||||
const notes = AGENT_TARGET_NOTES['factory-droid'];
|
||||
expect(notes).toContain('Factory');
|
||||
expect(notes).toContain('AI coding assistant');
|
||||
});
|
||||
|
||||
it('should mention reasoning models in codex notes', () => {
|
||||
@@ -564,9 +554,9 @@ describe('AGENT_TARGET_NOTES', () => {
|
||||
describe('getAgentDisplayName', () => {
|
||||
it('should return correct display names for all agents', () => {
|
||||
expect(getAgentDisplayName('claude-code')).toBe('Claude Code');
|
||||
expect(getAgentDisplayName('aider')).toBe('Aider');
|
||||
expect(getAgentDisplayName('opencode')).toBe('OpenCode');
|
||||
expect(getAgentDisplayName('codex')).toBe('OpenAI Codex');
|
||||
expect(getAgentDisplayName('factory-droid')).toBe('Factory Droid');
|
||||
expect(getAgentDisplayName('claude')).toBe('Claude');
|
||||
expect(getAgentDisplayName('terminal')).toBe('Terminal');
|
||||
});
|
||||
@@ -580,14 +570,14 @@ describe('getAgentDisplayName', () => {
|
||||
|
||||
describe('buildContextTransferPrompt', () => {
|
||||
it('should include source and target agent names', () => {
|
||||
const prompt = buildContextTransferPrompt('claude-code', 'aider');
|
||||
const prompt = buildContextTransferPrompt('claude-code', 'opencode');
|
||||
|
||||
expect(prompt).toContain('Claude Code');
|
||||
expect(prompt).toContain('Aider');
|
||||
expect(prompt).toContain('OpenCode');
|
||||
});
|
||||
|
||||
it('should include source agent artifacts', () => {
|
||||
const prompt = buildContextTransferPrompt('claude-code', 'aider');
|
||||
const prompt = buildContextTransferPrompt('claude-code', 'opencode');
|
||||
|
||||
// Should include Claude Code artifacts as bullet points
|
||||
expect(prompt).toContain('"/clear"');
|
||||
@@ -597,12 +587,11 @@ describe('buildContextTransferPrompt', () => {
|
||||
});
|
||||
|
||||
it('should include target agent notes', () => {
|
||||
const prompt = buildContextTransferPrompt('claude-code', 'aider');
|
||||
const prompt = buildContextTransferPrompt('claude-code', 'opencode');
|
||||
|
||||
// Should include Aider target notes
|
||||
expect(prompt).toContain('git repositories');
|
||||
expect(prompt).toContain('/add');
|
||||
expect(prompt).toContain('/drop');
|
||||
// Should include OpenCode target notes
|
||||
expect(prompt).toContain('multi-model');
|
||||
expect(prompt).toContain('AI coding assistant');
|
||||
});
|
||||
|
||||
it('should handle agents with no artifacts', () => {
|
||||
@@ -623,7 +612,7 @@ describe('buildContextTransferPrompt', () => {
|
||||
});
|
||||
|
||||
it('should work for all agent type combinations', () => {
|
||||
const agents: ToolType[] = ['claude-code', 'aider', 'opencode', 'codex', 'factory-droid', 'claude', 'terminal'];
|
||||
const agents: ToolType[] = ['claude-code', 'opencode', 'codex', 'factory-droid', 'claude', 'terminal'];
|
||||
|
||||
for (const source of agents) {
|
||||
for (const target of agents) {
|
||||
|
||||
@@ -95,10 +95,11 @@ describe('estimateContextUsage', () => {
|
||||
expect(result).toBe(8);
|
||||
});
|
||||
|
||||
it('should use aider default context window (128k)', () => {
|
||||
it('should use factory-droid default context window (200k)', () => {
|
||||
const stats = createStats({ contextWindow: 0 });
|
||||
const result = estimateContextUsage(stats, 'aider');
|
||||
expect(result).toBe(8);
|
||||
const result = estimateContextUsage(stats, 'factory-droid');
|
||||
// (10000 + 0 + 0) / 200000 = 5%
|
||||
expect(result).toBe(5);
|
||||
});
|
||||
|
||||
it('should return null for terminal agent', () => {
|
||||
@@ -289,7 +290,7 @@ describe('DEFAULT_CONTEXT_WINDOWS', () => {
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['claude']).toBe(200000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['codex']).toBe(200000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['opencode']).toBe(128000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['aider']).toBe(128000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['factory-droid']).toBe(200000);
|
||||
expect(DEFAULT_CONTEXT_WINDOWS['terminal']).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -171,9 +171,9 @@ describe('sessionValidation', () => {
|
||||
];
|
||||
// Different provider (aider) also gets a warning now
|
||||
const result = validateNewSession(
|
||||
'Aider Agent',
|
||||
'Factory Droid Agent',
|
||||
'/Users/test/project',
|
||||
'aider',
|
||||
'factory-droid',
|
||||
existingSessions
|
||||
);
|
||||
expect(result.valid).toBe(true);
|
||||
@@ -269,7 +269,7 @@ describe('sessionValidation', () => {
|
||||
createMockSession({
|
||||
name: 'Agent 2',
|
||||
projectRoot: '/Users/test/project',
|
||||
toolType: 'aider',
|
||||
toolType: 'factory-droid',
|
||||
}),
|
||||
];
|
||||
const result = validateNewSession(
|
||||
@@ -299,7 +299,7 @@ describe('sessionValidation', () => {
|
||||
projectRoot: '/path/two',
|
||||
toolType: 'claude-code',
|
||||
}),
|
||||
createMockSession({ name: 'Session 3', projectRoot: '/path/three', toolType: 'aider' }),
|
||||
createMockSession({ name: 'Session 3', projectRoot: '/path/three', toolType: 'factory-droid' }),
|
||||
];
|
||||
|
||||
// Unique name and directory - no warning
|
||||
@@ -331,7 +331,7 @@ describe('sessionValidation', () => {
|
||||
const diffProviderResult = validateNewSession(
|
||||
'Session 4',
|
||||
'/path/two',
|
||||
'aider',
|
||||
'factory-droid',
|
||||
existingSessions
|
||||
);
|
||||
expect(diffProviderResult.valid).toBe(true);
|
||||
@@ -372,10 +372,10 @@ describe('sessionValidation', () => {
|
||||
createMockSession({
|
||||
name: 'Existing',
|
||||
projectRoot: '/path',
|
||||
toolType: 'aider',
|
||||
toolType: 'factory-droid',
|
||||
}),
|
||||
];
|
||||
const result = validateNewSession('New', '/path', 'aider', existingSessions);
|
||||
const result = validateNewSession('New', '/path', 'factory-droid', existingSessions);
|
||||
expect(result.valid).toBe(true);
|
||||
expect(result.warning).toBeDefined();
|
||||
expect(result.warning).toContain('Existing');
|
||||
|
||||
@@ -183,7 +183,7 @@ describe('substituteTemplateVariables', () => {
|
||||
|
||||
it('should replace {{TOOL_TYPE}} with session.toolType', () => {
|
||||
const context = createTestContext({
|
||||
session: createTestSession({ toolType: 'aider' }),
|
||||
session: createTestSession({ toolType: 'factory-droid' }),
|
||||
});
|
||||
const result = substituteTemplateVariables('Tool: {{TOOL_TYPE}}', context);
|
||||
expect(result).toBe('Tool: aider');
|
||||
|
||||
@@ -246,35 +246,6 @@ export const AGENT_CAPABILITIES: Record<string, AgentCapabilities> = {
|
||||
supportsContextExport: false, // Not yet investigated - PLACEHOLDER
|
||||
},
|
||||
|
||||
/**
|
||||
* Aider - AI pair programming in your terminal
|
||||
* https://github.com/paul-gauthier/aider
|
||||
*
|
||||
* PLACEHOLDER: Most capabilities set to false until Aider integration is
|
||||
* implemented. Update this configuration when integrating the agent.
|
||||
*/
|
||||
aider: {
|
||||
supportsResume: false, // Not yet investigated
|
||||
supportsReadOnlyMode: false, // Not yet investigated
|
||||
supportsJsonOutput: false, // Not yet investigated
|
||||
supportsSessionId: false, // Not yet investigated
|
||||
supportsImageInput: true, // Aider supports vision models
|
||||
supportsImageInputOnResume: false, // Not yet investigated
|
||||
supportsSlashCommands: true, // Aider has /commands
|
||||
supportsSessionStorage: false, // Not yet investigated
|
||||
supportsCostTracking: true, // Aider tracks costs
|
||||
supportsUsageStats: true, // Aider shows token usage
|
||||
supportsBatchMode: false, // Not yet investigated
|
||||
requiresPromptToStart: false, // Not yet investigated
|
||||
supportsStreaming: true, // Likely streams
|
||||
supportsResultMessages: false, // Not yet investigated
|
||||
supportsModelSelection: true, // --model flag
|
||||
supportsStreamJsonInput: false,
|
||||
supportsThinkingDisplay: false, // Not yet investigated
|
||||
supportsContextMerge: false, // Not yet investigated - PLACEHOLDER
|
||||
supportsContextExport: false, // Not yet investigated - PLACEHOLDER
|
||||
},
|
||||
|
||||
/**
|
||||
* OpenCode - Open source coding assistant
|
||||
* https://github.com/opencode-ai/opencode
|
||||
|
||||
@@ -172,13 +172,6 @@ export const AGENT_DEFINITIONS: Omit<AgentConfig, 'available' | 'path' | 'capabi
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'aider',
|
||||
name: 'Aider',
|
||||
binaryName: 'aider',
|
||||
command: 'aider',
|
||||
args: [], // Base args (placeholder - to be configured when implemented)
|
||||
},
|
||||
{
|
||||
id: 'factory-droid',
|
||||
name: 'Factory Droid',
|
||||
@@ -512,7 +505,7 @@ export class AgentDetector {
|
||||
// User local programs
|
||||
path.join(localAppData, 'Programs'),
|
||||
path.join(localAppData, 'Microsoft', 'WindowsApps'),
|
||||
// Python/pip user installs (for Aider)
|
||||
// Python/pip user installs
|
||||
path.join(appData, 'Python', 'Scripts'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python312', 'Scripts'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python311', 'Scripts'),
|
||||
@@ -624,13 +617,6 @@ export class AgentDetector {
|
||||
path.join(appData, 'npm', 'gemini.cmd'),
|
||||
path.join(localAppData, 'npm', 'gemini.cmd'),
|
||||
],
|
||||
aider: [
|
||||
// pip installation
|
||||
path.join(appData, 'Python', 'Scripts', 'aider.exe'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python312', 'Scripts', 'aider.exe'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python311', 'Scripts', 'aider.exe'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python310', 'Scripts', 'aider.exe'),
|
||||
],
|
||||
droid: [
|
||||
// Factory Droid installation paths
|
||||
path.join(home, '.factory', 'bin', 'droid.exe'),
|
||||
@@ -720,15 +706,6 @@ export class AgentDetector {
|
||||
// Add paths from Node version managers (nvm, fnm, volta, etc.)
|
||||
...versionManagerPaths.map((p) => path.join(p, 'gemini')),
|
||||
],
|
||||
aider: [
|
||||
// pip installation
|
||||
path.join(home, '.local', 'bin', 'aider'),
|
||||
// Homebrew paths
|
||||
'/opt/homebrew/bin/aider',
|
||||
'/usr/local/bin/aider',
|
||||
// Add paths from Node version managers (in case installed via npm)
|
||||
...versionManagerPaths.map((p) => path.join(p, 'aider')),
|
||||
],
|
||||
droid: [
|
||||
// Factory Droid installation paths
|
||||
path.join(home, '.factory', 'bin', 'droid'),
|
||||
|
||||
@@ -31,7 +31,7 @@ export interface WindowsDiagnosticsInfo {
|
||||
codex: AgentProbeResult;
|
||||
opencode: AgentProbeResult;
|
||||
gemini: AgentProbeResult;
|
||||
aider: AgentProbeResult;
|
||||
droid: AgentProbeResult;
|
||||
};
|
||||
whereResults?: {
|
||||
// Results from 'where' command for each agent
|
||||
@@ -39,7 +39,7 @@ export interface WindowsDiagnosticsInfo {
|
||||
codex: WhereResult;
|
||||
opencode: WhereResult;
|
||||
gemini: WhereResult;
|
||||
aider: WhereResult;
|
||||
droid: WhereResult;
|
||||
};
|
||||
npmInfo?: {
|
||||
npmGlobalPrefix: string | null; // npm config get prefix (sanitized)
|
||||
@@ -105,7 +105,7 @@ export async function collectWindowsDiagnostics(): Promise<WindowsDiagnosticsInf
|
||||
codex: await probeAgentPaths('codex'),
|
||||
opencode: await probeAgentPaths('opencode'),
|
||||
gemini: await probeAgentPaths('gemini'),
|
||||
aider: await probeAgentPaths('aider'),
|
||||
droid: await probeAgentPaths('droid'),
|
||||
};
|
||||
|
||||
// Run 'where' command for each agent
|
||||
@@ -114,7 +114,7 @@ export async function collectWindowsDiagnostics(): Promise<WindowsDiagnosticsInf
|
||||
codex: await runWhereCommand('codex'),
|
||||
opencode: await runWhereCommand('opencode'),
|
||||
gemini: await runWhereCommand('gemini'),
|
||||
aider: await runWhereCommand('aider'),
|
||||
droid: await runWhereCommand('droid'),
|
||||
};
|
||||
|
||||
// Collect npm info
|
||||
@@ -179,11 +179,13 @@ async function probeAgentPaths(binaryName: string): Promise<AgentProbeResult> {
|
||||
path.join(appData, 'npm', 'opencode.cmd'),
|
||||
],
|
||||
gemini: [path.join(appData, 'npm', 'gemini.cmd'), path.join(localAppData, 'npm', 'gemini.cmd')],
|
||||
aider: [
|
||||
path.join(appData, 'Python', 'Scripts', 'aider.exe'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python312', 'Scripts', 'aider.exe'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python311', 'Scripts', 'aider.exe'),
|
||||
path.join(localAppData, 'Programs', 'Python', 'Python310', 'Scripts', 'aider.exe'),
|
||||
droid: [
|
||||
path.join(home, '.factory', 'bin', 'droid.exe'),
|
||||
path.join(localAppData, 'Factory', 'droid.exe'),
|
||||
path.join(appData, 'Factory', 'droid.exe'),
|
||||
path.join(home, '.local', 'bin', 'droid.exe'),
|
||||
path.join(appData, 'npm', 'droid.cmd'),
|
||||
path.join(localAppData, 'npm', 'droid.cmd'),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ const VALID_TOOL_TYPES: ToolType[] = [
|
||||
'codex',
|
||||
'terminal',
|
||||
'claude',
|
||||
'aider',
|
||||
'factory-droid',
|
||||
];
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import { logger } from '../utils/logger';
|
||||
const VALID_TOOL_TYPES = new Set<string>([
|
||||
'claude',
|
||||
'claude-code',
|
||||
'aider',
|
||||
'opencode',
|
||||
'codex',
|
||||
'terminal',
|
||||
|
||||
@@ -46,7 +46,6 @@ export const DEFAULT_CONTEXT_WINDOWS: Record<ToolType, number> = {
|
||||
claude: 200000, // Legacy Claude
|
||||
codex: 200000, // OpenAI o3/o4-mini context window
|
||||
opencode: 128000, // OpenCode (depends on model, 128k is conservative default)
|
||||
aider: 128000, // Aider (varies by model, 128k is conservative default)
|
||||
terminal: 0, // Terminal has no context window
|
||||
'factory-droid': 200000, // Factory Droid (Claude Opus 4.5 default context)
|
||||
};
|
||||
|
||||
@@ -1490,7 +1490,7 @@ export function EditAgentModal({
|
||||
'claude-code': 'Claude Code',
|
||||
codex: 'Codex',
|
||||
opencode: 'OpenCode',
|
||||
aider: 'Aider',
|
||||
'factory-droid': 'Factory Droid',
|
||||
};
|
||||
const agentName = agentNameMap[session.toolType] || session.toolType;
|
||||
|
||||
|
||||
@@ -90,9 +90,10 @@ function formatAgentName(toolType: ToolType): string {
|
||||
'claude-code': 'Claude Code',
|
||||
opencode: 'OpenCode',
|
||||
'openai-codex': 'OpenAI Codex',
|
||||
codex: 'Codex',
|
||||
'gemini-cli': 'Gemini CLI',
|
||||
'qwen3-coder': 'Qwen3 Coder',
|
||||
aider: 'Aider',
|
||||
'factory-droid': 'Factory Droid',
|
||||
terminal: 'Terminal',
|
||||
};
|
||||
return names[toolType] || toolType;
|
||||
|
||||
@@ -68,16 +68,9 @@ export const AGENT_TILES: AgentTile[] = [
|
||||
name: 'Factory Droid',
|
||||
supported: true,
|
||||
description: "Factory's AI coding assistant",
|
||||
brandColor: '#8B5CF6', // Purple/violet
|
||||
brandColor: '#3B82F6', // Factory blue
|
||||
},
|
||||
// Coming soon agents at the bottom
|
||||
{
|
||||
id: 'aider',
|
||||
name: 'Aider',
|
||||
supported: false,
|
||||
description: 'Coming soon',
|
||||
brandColor: '#14B8A6', // Teal
|
||||
},
|
||||
{
|
||||
id: 'gemini-cli',
|
||||
name: 'Gemini CLI',
|
||||
@@ -94,9 +87,9 @@ export const AGENT_TILES: AgentTile[] = [
|
||||
},
|
||||
];
|
||||
|
||||
// Grid dimensions for keyboard navigation (3 cols for 7 items)
|
||||
// Grid dimensions for keyboard navigation (3 cols for 6 items)
|
||||
const GRID_COLS = 3;
|
||||
const GRID_ROWS = 3;
|
||||
const GRID_ROWS = 2;
|
||||
|
||||
/**
|
||||
* Get SVG logo for an agent with brand colors
|
||||
@@ -155,33 +148,6 @@ export function AgentLogo({
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'aider':
|
||||
// Aider - chat bubble with code brackets
|
||||
return (
|
||||
<svg
|
||||
className="w-12 h-12"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={{ opacity }}
|
||||
>
|
||||
{/* Chat bubble with code brackets */}
|
||||
<path
|
||||
d="M8 12C8 9.79 9.79 8 12 8H36C38.21 8 40 9.79 40 12V28C40 30.21 38.21 32 36 32H20L12 40V32H12C9.79 32 8 30.21 8 28V12Z"
|
||||
stroke={color}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M18 16L14 20L18 24M30 16L34 20L30 24"
|
||||
stroke={color}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'gemini-cli':
|
||||
// Gemini - Google's sparkle/star logo
|
||||
return (
|
||||
@@ -254,6 +220,60 @@ export function AgentLogo({
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'factory-droid':
|
||||
// Factory Droid - pinwheel/flower logo
|
||||
return (
|
||||
<svg
|
||||
className="w-12 h-12"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={{ opacity }}
|
||||
>
|
||||
{/* Factory Droid pinwheel logo - 6 petals radiating from center */}
|
||||
<circle cx="24" cy="24" r="3" fill={color} />
|
||||
{/* Petals - elliptical shapes radiating outward */}
|
||||
<ellipse cx="24" cy="12" rx="4" ry="8" fill={color} fillOpacity="0.9" />
|
||||
<ellipse
|
||||
cx="34.4"
|
||||
cy="18"
|
||||
rx="4"
|
||||
ry="8"
|
||||
fill={color}
|
||||
fillOpacity="0.9"
|
||||
transform="rotate(60 34.4 18)"
|
||||
/>
|
||||
<ellipse
|
||||
cx="34.4"
|
||||
cy="30"
|
||||
rx="4"
|
||||
ry="8"
|
||||
fill={color}
|
||||
fillOpacity="0.9"
|
||||
transform="rotate(120 34.4 30)"
|
||||
/>
|
||||
<ellipse cx="24" cy="36" rx="4" ry="8" fill={color} fillOpacity="0.9" />
|
||||
<ellipse
|
||||
cx="13.6"
|
||||
cy="30"
|
||||
rx="4"
|
||||
ry="8"
|
||||
fill={color}
|
||||
fillOpacity="0.9"
|
||||
transform="rotate(60 13.6 30)"
|
||||
/>
|
||||
<ellipse
|
||||
cx="13.6"
|
||||
cy="18"
|
||||
rx="4"
|
||||
ry="8"
|
||||
fill={color}
|
||||
fillOpacity="0.9"
|
||||
transform="rotate(120 13.6 18)"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
default:
|
||||
return (
|
||||
<div className="w-12 h-12 rounded-full border-2" style={{ borderColor: color, opacity }} />
|
||||
|
||||
@@ -41,7 +41,6 @@ export const AGENT_ICONS: Record<string, string> = {
|
||||
|
||||
// Open-source alternatives
|
||||
opencode: '📟',
|
||||
aider: '🛠️',
|
||||
|
||||
// Enterprise
|
||||
'factory-droid': '🏭',
|
||||
|
||||
@@ -74,8 +74,8 @@ function getAgentIcon(agentId: string): string {
|
||||
return '⬡';
|
||||
case 'opencode':
|
||||
return '📟';
|
||||
case 'aider':
|
||||
return '🛠️';
|
||||
case 'factory-droid':
|
||||
return '🏭';
|
||||
default:
|
||||
return '🔧';
|
||||
}
|
||||
|
||||
@@ -59,28 +59,6 @@ export const AGENT_ARTIFACTS: Record<ToolType, string[]> = {
|
||||
'Claude Code',
|
||||
'CLAUDE.md',
|
||||
],
|
||||
aider: [
|
||||
// Slash commands
|
||||
'/add',
|
||||
'/drop',
|
||||
'/commit',
|
||||
'/diff',
|
||||
'/undo',
|
||||
'/clear',
|
||||
'/run',
|
||||
'/voice',
|
||||
'/help',
|
||||
'/quit',
|
||||
'/ls',
|
||||
'/map',
|
||||
// Brand references
|
||||
'Aider',
|
||||
'aider',
|
||||
// Model references
|
||||
'gpt-4',
|
||||
'gpt-3.5',
|
||||
'GPT',
|
||||
],
|
||||
opencode: [
|
||||
// Slash commands
|
||||
'/help',
|
||||
@@ -145,12 +123,6 @@ export const AGENT_TARGET_NOTES: Record<ToolType, string> = {
|
||||
It can read and edit files, run terminal commands, search code, and interact with git.
|
||||
It uses slash commands like /compact, /clear, /cost for session management.
|
||||
It can handle large codebases and multi-file changes.
|
||||
`,
|
||||
aider: `
|
||||
Aider is an AI pair programming tool.
|
||||
It works with git repositories and can make commits.
|
||||
It uses /add to include files in context and /drop to remove them.
|
||||
It focuses on code changes and git workflow.
|
||||
`,
|
||||
opencode: `
|
||||
OpenCode is a multi-model AI coding assistant.
|
||||
@@ -186,7 +158,6 @@ export const AGENT_TARGET_NOTES: Record<ToolType, string> = {
|
||||
export function getAgentDisplayName(agentType: ToolType): string {
|
||||
const names: Record<ToolType, string> = {
|
||||
'claude-code': 'Claude Code',
|
||||
aider: 'Aider',
|
||||
opencode: 'OpenCode',
|
||||
codex: 'OpenAI Codex',
|
||||
'factory-droid': 'Factory Droid',
|
||||
|
||||
@@ -457,8 +457,8 @@ export interface Session {
|
||||
// Usage statistics from AI responses
|
||||
usageStats?: UsageStats;
|
||||
inputMode: 'terminal' | 'ai';
|
||||
// AI process PID (for non-batch agents like Aider)
|
||||
// For Claude batch mode, this is 0 since processes spawn per-message
|
||||
// AI process PID (for agents with persistent processes)
|
||||
// For batch mode agents, this is 0 since processes spawn per-message
|
||||
aiPid: number;
|
||||
// Terminal uses runCommand() which spawns fresh shells per command
|
||||
// This field is kept for backwards compatibility but is always 0
|
||||
|
||||
@@ -17,7 +17,6 @@ export const DEFAULT_CONTEXT_WINDOWS: Record<ToolType, number> = {
|
||||
claude: 200000, // Legacy Claude
|
||||
codex: 200000, // OpenAI o3/o4-mini context window
|
||||
opencode: 128000, // OpenCode (depends on model, 128k is conservative default)
|
||||
aider: 128000, // Aider (varies by model, 128k is conservative default)
|
||||
'factory-droid': 200000, // Factory Droid (varies by model, defaults to Claude Opus)
|
||||
terminal: 0, // Terminal has no context window
|
||||
};
|
||||
|
||||
@@ -111,7 +111,6 @@ export function getProviderDisplayName(toolType: ToolType): string {
|
||||
const displayNames: Record<ToolType, string> = {
|
||||
'claude-code': 'Claude Code',
|
||||
claude: 'Claude',
|
||||
aider: 'Aider',
|
||||
opencode: 'OpenCode',
|
||||
codex: 'Codex',
|
||||
'factory-droid': 'Factory Droid',
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* {{AGENT_SESSION_ID}} - Agent session ID (for conversation continuity)
|
||||
* {{AGENT_HISTORY_PATH}} - Path to agent's history JSON file (for task recall)
|
||||
* {{TAB_NAME}} - Custom tab name (alias: SESSION_NAME)
|
||||
* {{TOOL_TYPE}} - Agent type (claude-code, aider, etc.)
|
||||
* {{TOOL_TYPE}} - Agent type (claude-code, codex, opencode, factory-droid)
|
||||
*
|
||||
* Path Variables:
|
||||
* {{CWD}} - Current working directory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Shared type definitions for Maestro CLI and Electron app
|
||||
// These types are used by both the CLI tool and the renderer process
|
||||
|
||||
export type ToolType = 'claude' | 'claude-code' | 'aider' | 'opencode' | 'codex' | 'terminal' | 'factory-droid';
|
||||
export type ToolType = 'claude' | 'claude-code' | 'opencode' | 'codex' | 'terminal' | 'factory-droid';
|
||||
|
||||
/**
|
||||
* ThinkingMode controls how AI reasoning/thinking content is displayed.
|
||||
|
||||
Reference in New Issue
Block a user