From 91ae547ab48323b3f7f992c607afbe01937dfbb2 Mon Sep 17 00:00:00 2001 From: Pedram Amini Date: Wed, 17 Dec 2025 12:18:41 -0600 Subject: [PATCH] ## CHANGES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Version bump from 0.8.8 to 0.9.0 release 🚀 - Added custom CLI arguments support for agents 🛠️ - New handlers for setting and getting custom args ⚙️ - Store custom arguments persistently in agent configs 💾 - Apply custom args to all agent invocations automatically 🔄 - Enhanced background synopsis with flexible agent type support 🎯 - Improved session resumption for any agent type compatibility 🔗 - Refactored spawn logic to support agent-specific resume args 🏗️ - Better abstraction for multi-agent background task execution 🤖 - Backwards compatible with claude-code as default agent 🔒 --- package.json | 2 +- src/main/ipc/handlers/agents.ts | 49 +++++++++++++++++++++++++ src/main/preload.ts | 7 ++++ src/renderer/hooks/useAgentExecution.ts | 31 +++++++++------- 4 files changed, 74 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 8bb13a75..cdaac911 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "maestro", - "version": "0.8.8", + "version": "0.9.0", "description": "Run AI coding agents autonomously for days.", "main": "dist/main/index.js", "author": { diff --git a/src/main/ipc/handlers/agents.ts b/src/main/ipc/handlers/agents.ts index 9e14b59e..0836fd23 100644 --- a/src/main/ipc/handlers/agents.ts +++ b/src/main/ipc/handlers/agents.ts @@ -270,6 +270,55 @@ export function registerAgentsHandlers(deps: AgentsHandlerDependencies): void { }) ); + // Set custom CLI arguments for an agent - arbitrary args appended to all agent invocations + ipcMain.handle( + 'agents:setCustomArgs', + withIpcErrorLogging( + handlerOpts('setCustomArgs', CONFIG_LOG_CONTEXT), + async (agentId: string, customArgs: string | null) => { + const allConfigs = agentConfigsStore.get('configs', {}); + if (!allConfigs[agentId]) { + allConfigs[agentId] = {}; + } + + if (customArgs && customArgs.trim()) { + allConfigs[agentId].customArgs = customArgs.trim(); + logger.info(`Set custom args for agent ${agentId}: ${customArgs}`, CONFIG_LOG_CONTEXT); + } else { + delete allConfigs[agentId].customArgs; + logger.info(`Cleared custom args for agent ${agentId}`, CONFIG_LOG_CONTEXT); + } + + agentConfigsStore.set('configs', allConfigs); + return true; + } + ) + ); + + // Get custom CLI arguments for an agent + ipcMain.handle( + 'agents:getCustomArgs', + withIpcErrorLogging(handlerOpts('getCustomArgs', CONFIG_LOG_CONTEXT), async (agentId: string) => { + const allConfigs = agentConfigsStore.get('configs', {}); + return allConfigs[agentId]?.customArgs || null; + }) + ); + + // Get all custom CLI arguments for agents + ipcMain.handle( + 'agents:getAllCustomArgs', + withIpcErrorLogging(handlerOpts('getAllCustomArgs', CONFIG_LOG_CONTEXT), async () => { + const allConfigs = agentConfigsStore.get('configs', {}); + const customArgs: Record = {}; + for (const [agentId, config] of Object.entries(allConfigs)) { + if (config && typeof config === 'object' && 'customArgs' in config && config.customArgs) { + customArgs[agentId] = config.customArgs as string; + } + } + return customArgs; + }) + ); + // Discover available models for an agent that supports model selection ipcMain.handle( 'agents:getModels', diff --git a/src/main/preload.ts b/src/main/preload.ts index a6e21ab1..7246ed53 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -394,6 +394,13 @@ contextBridge.exposeInMainWorld('maestro', { getCustomPath: (agentId: string) => ipcRenderer.invoke('agents:getCustomPath', agentId), getAllCustomPaths: () => ipcRenderer.invoke('agents:getAllCustomPaths'), + // Custom CLI arguments that are appended to all agent invocations + setCustomArgs: (agentId: string, customArgs: string | null) => + ipcRenderer.invoke('agents:setCustomArgs', agentId, customArgs), + getCustomArgs: (agentId: string) => + ipcRenderer.invoke('agents:getCustomArgs', agentId) as Promise, + getAllCustomArgs: () => + ipcRenderer.invoke('agents:getAllCustomArgs') as Promise>, // Discover available models for agents that support model selection (e.g., OpenCode with Ollama) getModels: (agentId: string, forceRefresh?: boolean) => ipcRenderer.invoke('agents:getModels', agentId, forceRefresh) as Promise, diff --git a/src/renderer/hooks/useAgentExecution.ts b/src/renderer/hooks/useAgentExecution.ts index 61761bf4..b47a24bd 100644 --- a/src/renderer/hooks/useAgentExecution.ts +++ b/src/renderer/hooks/useAgentExecution.ts @@ -1,5 +1,5 @@ import { useCallback, useRef } from 'react'; -import type { Session, SessionState, UsageStats, QueuedItem, LogEntry } from '../types'; +import type { Session, SessionState, UsageStats, QueuedItem, LogEntry, ToolType } from '../types'; import { getActiveTab } from '../utils/tabHelpers'; import { generateId } from '../utils/ids'; @@ -39,12 +39,13 @@ export interface UseAgentExecutionReturn { spawnAgentForSession: (sessionId: string, prompt: string, cwdOverride?: string) => Promise; /** Spawn an agent with a prompt for the active session */ spawnAgentWithPrompt: (prompt: string) => Promise; - /** Spawn a background synopsis agent (resumes an old Claude session) */ + /** Spawn a background synopsis agent (resumes an old agent session) */ spawnBackgroundSynopsis: ( sessionId: string, cwd: string, - resumeClaudeSessionId: string, - prompt: string + resumeAgentSessionId: string, + prompt: string, + toolType?: ToolType ) => Promise; /** Ref to spawnBackgroundSynopsis for use in callbacks that need latest version */ spawnBackgroundSynopsisRef: React.MutableRefObject { spawnBackgroundSynopsis: infer R } ? R : never>; @@ -323,22 +324,24 @@ export function useAgentExecution( }, [activeSession, spawnAgentForSession]); /** - * Spawn a background synopsis agent that resumes an old Claude session. + * Spawn a background synopsis agent that resumes an old agent session. * Used for generating summaries without affecting main session state. * * @param sessionId - The Maestro session ID (for logging/tracking) * @param cwd - Working directory for the agent - * @param resumeClaudeSessionId - The Claude session ID to resume + * @param resumeAgentSessionId - The agent session ID to resume * @param prompt - The prompt to send to the resumed session + * @param toolType - The agent type (defaults to claude-code for backwards compatibility) */ const spawnBackgroundSynopsis = useCallback(async ( sessionId: string, cwd: string, - resumeClaudeSessionId: string, - prompt: string + resumeAgentSessionId: string, + prompt: string, + toolType: ToolType = 'claude-code' ): Promise => { try { - const agent = await window.maestro.agents.get('claude-code'); + const agent = await window.maestro.agents.get(toolType); if (!agent) return { success: false }; // Use a unique target ID for background synopsis @@ -399,16 +402,16 @@ export function useAgentExecution( } }); - // Spawn with --resume to continue the old session + // Spawn with session resume - the IPC handler will use the agent's resumeArgs builder const commandToUse = agent.path || agent.command; - const spawnArgs = [...(agent.args || []), '--resume', resumeClaudeSessionId]; window.maestro.process.spawn({ sessionId: targetSessionId, - toolType: 'claude-code', + toolType, cwd, command: commandToUse, - args: spawnArgs, - prompt + args: agent.args || [], + prompt, + agentSessionId: resumeAgentSessionId, // This triggers the agent's resume mechanism }).catch(() => { cleanup(); resolve({ success: false });