Files
orca/src/shared/pi-agent-kind.ts
Wooseong KimandBrennan Benson 9e0a9ebc7d fix(pty): do not create unused Pi/OMP home dirs on bare shells (#10198)
* fix(pty): do not create unused Pi/OMP home dirs on bare shells

Bare terminals used to materialize ~/.pi/agent and ~/.omp/agent (and install
managed extensions) for possible later shell-launched agents. Users who never
use those agents still saw the directories recreated after deletion.

Only create the default agent home when launching that agent explicitly, or
when the home already exists. Bare-shell OMP status still uses the userData
fallback so typed `omp` keeps the shell wrapper extension.

Closes #10196

* fix(relay): OMP bare-shell status fallback without ~/.omp

CodeRabbit: relay materializePi returned null on bare shells with a missing
OMP home, so SSH PTYs never set ORCA_OMP_STATUS_EXTENSION. Local already
wrote a userData-managed status extension in that case.

Write the status file under ~/.orca-relay/omp-managed-status-extension and
return MaterializePiResult so relay.ts can export ORCA_OMP_STATUS_EXTENSION
without ORCA_OMP_SOURCE_AGENT_DIR or creating ~/.omp. Also fix the local
withOrcaManagedExtensionMarker typo on the bare-shell path.

* fix(pty): only materialize Pi home for Pi launches

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-30 12:57:45 -07:00

70 lines
2.7 KiB
TypeScript

import { TUI_AGENT_CONFIG } from './tui-agent-config'
import { getCommandTokenPathBasename, getFirstCommandToken } from './command-token-scanner'
/**
* Pi-compatible agent kinds. Both Pi and OMP (omp.sh) consume the same
* `PI_CODING_AGENT_DIR` env contract and the same extension API, but each
* defaults its on-disk config dir to a different `~/.<kind>/agent` path.
* Orca's managed extension installer needs to know which agent is being
* launched so it targets the user's actual source dir for THAT agent, with no
* cross-agent fallback
* (otherwise switching agents in the same workspace silently shadows the
* other agent's user extensions).
*/
export type PiAgentKind = 'pi' | 'omp'
/**
* True when `agentType` names a Pi-compatible (goal/mission) kind. These agents
* emit milestone `agent_end` events between steps while still working, so they
* are treated differently from agents that only signal completion at turn end.
*/
export function isPiCompatibleAgentType(
agentType: string | null | undefined
): agentType is PiAgentKind {
return agentType === 'pi' || agentType === 'omp'
}
function getLaunchBinary(command: string): string {
return getCommandTokenPathBasename(getFirstCommandToken(command))
.toLowerCase()
.replace(/\.(?:cmd|exe|sh)$/, '')
}
const PI_LAUNCH_BINARY = getLaunchBinary(TUI_AGENT_CONFIG.pi.launchCmd)
const OMP_LAUNCH_BINARY = getLaunchBinary(TUI_AGENT_CONFIG.omp.launchCmd)
export function detectExplicitPiAgentKindFromCommand(
command: string | undefined
): PiAgentKind | null {
const binary = getLaunchBinary(command ?? '')
if (binary === OMP_LAUNCH_BINARY) {
return 'omp'
}
return binary === PI_LAUNCH_BINARY ? 'pi' : null
}
/**
* Identify the Pi-compatible agent kind a launch command targets.
*
* Returns 'omp' when the command launches OMP (`omp` / `omp.sh`), otherwise
* defaults to 'pi'. Defaulting to 'pi' preserves prior behavior for the
* non-launch case (e.g. bare shells that may later invoke `pi`) where Orca
* prepared Pi integration by default.
*
* NEVER cross-fall-back: a missing source dir for the resolved kind means
* "create that kind's extension dir only" - the other agent's dir MUST NOT
* be substituted.
*/
export function detectPiAgentKindFromCommand(command: string | undefined): PiAgentKind {
const explicitKind = detectExplicitPiAgentKindFromCommand(command)
if (explicitKind) {
return explicitKind
}
// Why: PI launches and the no-command (bare-shell) fallback both resolve to
// 'pi'. A bare shell that later invokes `pi` keeps the historical default;
// if it later invokes `omp`, the status extension re-routes at runtime based
// on the executable name so attribution still lands on OMP.
return 'pi'
}