diff --git a/src/main/ipc/pty.test.ts b/src/main/ipc/pty.test.ts index 35d386eb473..d98e1c41a30 100644 --- a/src/main/ipc/pty.test.ts +++ b/src/main/ipc/pty.test.ts @@ -752,6 +752,7 @@ describe('registerPtyHandlers', () => { getSettings?: () => { enableGitHubAttribution?: boolean agentStatusHooksEnabled?: boolean + disabledTuiAgents?: readonly string[] httpProxyUrl?: string httpProxyBypassRules?: string }, @@ -1081,6 +1082,42 @@ describe('registerPtyHandlers', () => { ) }) + it('skips Pi managed extensions when Pi is disabled in Settings > Agents', async () => { + // Why: #7814 — global agentStatusHooksEnabled must not install orca-*.ts + // into ~/.pi when the user turned Pi off per-agent. + const env = await spawnAndGetEnv( + undefined, + { PI_CODING_AGENT_DIR: '/tmp/user-pi-agent' }, + undefined, + () => ({ disabledTuiAgents: ['pi'] }) + ) + expect(piBuildPtyEnvMock).not.toHaveBeenCalledWith( + expect.any(String), + expect.anything(), + 'pi' + ) + // OMP shadow prep still runs for non-omp launches unless omp is disabled. + expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'omp') + expect(env.ORCA_PI_SOURCE_AGENT_DIR).toBeUndefined() + }) + + it('skips OMP managed extensions when OMP is disabled in Settings > Agents', async () => { + const env = await spawnAndGetEnv( + undefined, + { PI_CODING_AGENT_DIR: '/tmp/user-omp-agent' }, + undefined, + () => ({ disabledTuiAgents: ['omp'] }), + 'omp' + ) + expect(piBuildPtyEnvMock).not.toHaveBeenCalledWith( + expect.any(String), + expect.anything(), + 'omp' + ) + expect(env.ORCA_OMP_STATUS_EXTENSION).toBeUndefined() + expect(env.ORCA_OMP_SOURCE_AGENT_DIR).toBeUndefined() + }) + it('threads command: "omp" through to piBuildPtyEnv and emits OMP status metadata', async () => { // Why: OMP launches must emit OMP-named Orca shadow vars (ORCA_OMP_*), // not Pi-named ones. The PI_CODING_AGENT_DIR binary var is unavoidable diff --git a/src/main/ipc/pty.ts b/src/main/ipc/pty.ts index 305ebabfc14..7947f438c59 100644 --- a/src/main/ipc/pty.ts +++ b/src/main/ipc/pty.ts @@ -52,6 +52,7 @@ import { wslHookRelayManager } from '../agent-hooks/wsl-hook-relay-manager' import { isAgentStatusHooksEnabled } from '../agent-hooks/managed-agent-hook-controls' import { piTitlebarExtensionService } from '../pi/titlebar-extension-service' import { detectPiAgentKindFromCommand, type PiAgentKind } from '../../shared/pi-agent-kind' +import { isTuiAgentEnabled } from '../../shared/tui-agent-selection' import { isPwshAvailable } from '../pwsh' import { LocalPtyProvider } from '../providers/local-pty-provider' import type { IPtyProvider, PtySpawnOptions, PtySpawnResult } from '../providers/types' @@ -559,6 +560,10 @@ export type BuildPtyHostEnvOptions = { * hook relay ensure + guest endpoint repoint; only read when isWsl. */ wslDistro?: string | null agentStatusHooksEnabled: boolean + /** Per-user disabled agents from Settings > Agents. Used to avoid installing + * managed Pi/OMP extensions (writing orca-*.ts files into ~/.pi or ~/.omp) + * for agents the user has explicitly disabled. */ + disabledTuiAgents?: readonly unknown[] | null networkProxySettings?: NetworkProxySettings } @@ -936,13 +941,18 @@ export function buildPtyHostEnv( if (opts.agentStatusHooksEnabled) { clearPiAgentShadowEnv(baseEnv, 'pi') clearPiAgentShadowEnv(baseEnv, 'omp') - if (piAgentKind === 'pi') { + // Why: only install Orca-managed extensions (writing orca-*.ts files into + // the agent's ~/.pi/agent/extensions or ~/.omp/...) for agents the user + // has enabled in Settings > Agents. Respecting disabledTuiAgents prevents + // polluting the config dir of agents the user explicitly turned off + // (see bug #7814). + if (piAgentKind === 'pi' && isTuiAgentEnabled('pi', opts.disabledTuiAgents)) { const piEnv = piTitlebarExtensionService.buildPtyEnv(id, preexistingPiAgentDir, 'pi') Object.assign(baseEnv, piEnv) exposePiManagedExtensionEnv(baseEnv, 'pi', piEnv) } - if (shouldPrepareOmpShadow) { + if (shouldPrepareOmpShadow && isTuiAgentEnabled('omp', opts.disabledTuiAgents)) { const ompEnv = piTitlebarExtensionService.buildPtyEnv(id, preexistingOmpAgentDir, 'omp') Object.assign(baseEnv, ompEnv) exposePiManagedExtensionEnv(baseEnv, 'omp', ompEnv) @@ -1546,6 +1556,7 @@ export function registerPtyHandlers( isWsl: ctx?.isWsl, wslDistro: ctx?.wslDistro ?? null, agentStatusHooksEnabled: isAgentStatusHooksEnabled(getSettings?.()), + disabledTuiAgents: getSettings?.()?.disabledTuiAgents, networkProxySettings: getSettings?.() }) // Why: agents need their own terminal handle at process start so they @@ -3029,6 +3040,7 @@ export function registerPtyHandlers( isWsl: shouldSkipCodexHomeEnvForWindowsShell(daemonShellOverride, cwd), wslDistro: codexSelectionTarget.runtime === 'wsl' ? codexSelectionTarget.wslDistro : null, agentStatusHooksEnabled: isAgentStatusHooksEnabled(getSettings?.()), + disabledTuiAgents: getSettings?.()?.disabledTuiAgents, networkProxySettings: getSettings?.() }) promoteAgentTeamsShimPath(env, requestedAgentTeamsPath) @@ -3884,6 +3896,7 @@ export function registerPtyHandlers( wslDistro: codexSelectionTarget.runtime === 'wsl' ? codexSelectionTarget.wslDistro : null, agentStatusHooksEnabled: isAgentStatusHooksEnabled(getSettings?.()), + disabledTuiAgents: getSettings?.()?.disabledTuiAgents, networkProxySettings: getSettings?.() }) promoteAgentTeamsShimPath(env, requestedAgentTeamsPath)