## CHANGES

- 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 🔒
This commit is contained in:
Pedram Amini
2025-12-17 12:18:41 -06:00
parent ad4af64604
commit 91ae547ab4
4 changed files with 74 additions and 15 deletions

View File

@@ -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": {

View File

@@ -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<string, string> = {};
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',

View File

@@ -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<string | null>,
getAllCustomArgs: () =>
ipcRenderer.invoke('agents:getAllCustomArgs') as Promise<Record<string, string>>,
// 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<string[]>,

View File

@@ -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<AgentSpawnResult>;
/** Spawn an agent with a prompt for the active session */
spawnAgentWithPrompt: (prompt: string) => Promise<AgentSpawnResult>;
/** 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<AgentSpawnResult>;
/** Ref to spawnBackgroundSynopsis for use in callbacks that need latest version */
spawnBackgroundSynopsisRef: React.MutableRefObject<typeof useAgentExecution extends (...args: infer _) => { 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<AgentSpawnResult> => {
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 });