diff --git a/src/__tests__/main/agent-detector.test.ts b/src/__tests__/main/agent-detector.test.ts index 0f09e259..8b58dacd 100644 --- a/src/__tests__/main/agent-detector.test.ts +++ b/src/__tests__/main/agent-detector.test.ts @@ -99,6 +99,7 @@ describe('agent-detector', () => { requiresPty: true, configOptions: [{ key: 'k', type: 'text', label: 'L', description: 'D', default: '' }], hidden: true, + defaultEnvVars: { TEST_VAR: 'test-value' }, capabilities: { supportsResume: true, supportsReadOnlyMode: false, @@ -119,6 +120,7 @@ describe('agent-detector', () => { expect(config.customPath).toBe('/custom/path'); expect(config.requiresPty).toBe(true); expect(config.hidden).toBe(true); + expect(config.defaultEnvVars).toEqual({ TEST_VAR: 'test-value' }); expect(config.capabilities.supportsResume).toBe(true); }); diff --git a/src/main/agent-detector.ts b/src/main/agent-detector.ts index fa2cdd4e..364dcfa0 100644 --- a/src/main/agent-detector.ts +++ b/src/main/agent-detector.ts @@ -47,6 +47,7 @@ export interface AgentConfig { imageArgs?: (imagePath: string) => string[]; // Function to build image attachment args (e.g., ['-i', imagePath] for Codex) promptArgs?: (prompt: string) => string[]; // Function to build prompt args (e.g., ['-p', prompt] for OpenCode) noPromptSeparator?: boolean; // If true, don't add '--' before the prompt in batch mode (OpenCode doesn't support it) + defaultEnvVars?: Record; // Default environment variables for this agent (merged with user customEnvVars) } const AGENT_DEFINITIONS: Omit[] = [ @@ -122,8 +123,9 @@ const AGENT_DEFINITIONS: Omit] [--agent plan] -- "prompt" - // The 'run' subcommand auto-approves all permissions (YOLO mode is implicit). + // Batch mode: opencode run --format json [--model provider/model] [--session ] [--agent plan] "prompt" + // YOLO mode (auto-approve all permissions) is enabled via OPENCODE_CONFIG_CONTENT env var. + // This prevents OpenCode from prompting for permission on external_directory access, which would hang in batch mode. batchModePrefix: ['run'], // OpenCode uses 'run' subcommand for batch mode jsonOutputArgs: ['--format', 'json'], // JSON output format resumeArgs: (sessionId: string) => ['--session', sessionId], // Resume with session ID @@ -131,6 +133,11 @@ const AGENT_DEFINITIONS: Omit ['--model', modelId], // Model selection (e.g., 'ollama/qwen3:8b') imageArgs: (imagePath: string) => ['-f', imagePath], // Image/file attachment: opencode run -f /path/to/image.png -- "prompt" noPromptSeparator: true, // OpenCode doesn't need '--' before prompt - yargs handles positional args + // Default env vars: enable YOLO mode (allow all permissions including external_directory) + // Users can override by setting customEnvVars in agent config + defaultEnvVars: { + OPENCODE_CONFIG_CONTENT: '{"permission":{"*":"allow","external_directory":"allow"}}', + }, // Agent-specific configuration options shown in UI configOptions: [ { diff --git a/src/main/utils/agent-args.ts b/src/main/utils/agent-args.ts index 5d0f0a75..82e01cfb 100644 --- a/src/main/utils/agent-args.ts +++ b/src/main/utils/agent-args.ts @@ -135,7 +135,20 @@ export function applyAgentConfigOverrides( customArgsSource = 'none'; } - const effectiveCustomEnvVars = overrides.sessionCustomEnvVars ?? agentConfigValues.customEnvVars as Record | undefined; + // Merge env vars: agent defaults (lowest) < agent config (medium) < session overrides (highest) + // User-configured vars override agent defaults; session vars override both + const userEnvVars = overrides.sessionCustomEnvVars ?? agentConfigValues.customEnvVars as Record | undefined; + const agentDefaultEnvVars = agent?.defaultEnvVars; + + // Start with agent defaults, then layer on user config + let effectiveCustomEnvVars: Record | undefined; + if (agentDefaultEnvVars || userEnvVars) { + effectiveCustomEnvVars = { + ...(agentDefaultEnvVars || {}), + ...(userEnvVars || {}), + }; + } + const hasEnvVars = effectiveCustomEnvVars && Object.keys(effectiveCustomEnvVars).length > 0; const customEnvSource: AgentConfigResolution['customEnvSource'] = overrides.sessionCustomEnvVars ? 'session'