refactor(agent-hooks): separate Pi and OMP home fix

This commit is contained in:
Brennan Benson
2026-07-29 17:46:31 -07:00
parent c004d38d8c
commit eb3e6ff9b5
7 changed files with 79 additions and 244 deletions
+30 -82
View File
@@ -18,8 +18,8 @@ import { PtyWriteUnavailableError } from '../providers/pty-write-unavailable-err
const isWindowsHost = process.platform === 'win32'
const posixOnlyIt = isWindowsHost ? it.skip : it
const expectedOmpStatusExtension = posix.join(
'/tmp/orca-user-data',
'omp-managed-status-extension',
'/tmp/default-omp-agent',
'extensions',
'orca-agent-status.ts'
)
function expectedAttributionShimDir(): string {
@@ -413,31 +413,15 @@ describe('registerPtyHandlers', () => {
ORCA_AGENT_HOOK_TOKEN: 'agent-token'
})
piBuildPtyEnvMock.mockImplementation(
(
_ptyId: string,
existingAgentDir?: string,
kind?: string,
options?: { materializeDefaultHome?: boolean }
) => {
if (kind === 'omp') {
if (!existingAgentDir && options?.materializeDefaultHome === false) {
return {
ORCA_OMP_STATUS_EXTENSION:
'/tmp/orca-user-data/omp-managed-status-extension/orca-agent-status.ts'
(_ptyId: string, existingAgentDir?: string, kind?: string) =>
kind === 'omp'
? {
ORCA_OMP_SOURCE_AGENT_DIR: existingAgentDir ?? '/tmp/default-omp-agent',
ORCA_OMP_STATUS_EXTENSION: `${existingAgentDir ?? '/tmp/default-omp-agent'}/extensions/orca-agent-status.ts`
}
: {
ORCA_PI_SOURCE_AGENT_DIR: existingAgentDir ?? '/tmp/default-pi-agent'
}
}
return {
ORCA_OMP_SOURCE_AGENT_DIR: existingAgentDir ?? '/tmp/default-omp-agent',
ORCA_OMP_STATUS_EXTENSION: `${existingAgentDir ?? '/tmp/default-omp-agent'}/extensions/orca-agent-status.ts`
}
}
if (!existingAgentDir && options?.materializeDefaultHome === false) {
return {}
}
return {
ORCA_PI_SOURCE_AGENT_DIR: existingAgentDir ?? '/tmp/default-pi-agent'
}
}
)
isPwshAvailableMock.mockReturnValue(false)
spawnMock.mockReturnValue({
@@ -2440,21 +2424,15 @@ describe('registerPtyHandlers', () => {
it('installs Pi managed extensions without redirecting Orca terminal PTY homes', async () => {
const env = await spawnAndGetEnv(undefined, { PI_CODING_AGENT_DIR: '/tmp/user-pi-agent' })
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/tmp/user-pi-agent',
'pi',
{ materializeDefaultHome: false }
)
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'omp', {
materializeDefaultHome: false
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), '/tmp/user-pi-agent', 'pi')
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'omp')
expect(env.PI_CODING_AGENT_DIR).toBe('/tmp/user-pi-agent')
expect(env.ORCA_PI_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_PI_SOURCE_AGENT_DIR).toBe('/tmp/user-pi-agent')
expect(env.ORCA_OMP_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_OMP_STATUS_EXTENSION).toBe(expectedOmpStatusExtension)
expect(env.ORCA_OMP_SOURCE_AGENT_DIR).toBeUndefined()
expect(env.ORCA_OMP_STATUS_EXTENSION).toBe(
'/tmp/default-omp-agent/extensions/orca-agent-status.ts'
)
})
it('threads command: "omp" through to piBuildPtyEnv and emits OMP status metadata', async () => {
@@ -2469,8 +2447,7 @@ describe('registerPtyHandlers', () => {
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/tmp/user-omp-agent',
'omp',
{ materializeDefaultHome: true }
'omp'
)
expect(env.PI_CODING_AGENT_DIR).toBe('/tmp/user-omp-agent')
expect(env.ORCA_OMP_CODING_AGENT_DIR).toBeUndefined()
@@ -2498,8 +2475,7 @@ describe('registerPtyHandlers', () => {
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/tmp/user-omp-agent',
'omp',
{ materializeDefaultHome: true }
'omp'
)
expect(env.ORCA_OMP_STATUS_EXTENSION).toBe(
'/tmp/user-omp-agent/extensions/orca-agent-status.ts'
@@ -2512,12 +2488,7 @@ describe('registerPtyHandlers', () => {
PI_CODING_AGENT_DIR: '/tmp/parent-orca-pi-overlay',
ORCA_PI_SOURCE_AGENT_DIR: '/tmp/user-pi-agent'
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/tmp/user-pi-agent',
'pi',
{ materializeDefaultHome: false }
)
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), '/tmp/user-pi-agent', 'pi')
expect(env.PI_CODING_AGENT_DIR).toBe('/tmp/parent-orca-pi-overlay')
expect(env.ORCA_PI_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_PI_SOURCE_AGENT_DIR).toBe('/tmp/user-pi-agent')
@@ -2536,9 +2507,7 @@ describe('registerPtyHandlers', () => {
'omp'
)
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'omp', {
materializeDefaultHome: true
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'omp')
expect(env.ORCA_OMP_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_OMP_SOURCE_AGENT_DIR).toBe('/tmp/default-omp-agent')
expect(env.ORCA_PI_CODING_AGENT_DIR).toBeUndefined()
@@ -2558,9 +2527,7 @@ describe('registerPtyHandlers', () => {
'pi'
)
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'pi', {
materializeDefaultHome: true
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'pi')
expect(env.ORCA_PI_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_PI_SOURCE_AGENT_DIR).toBe('/tmp/default-pi-agent')
expect(env.ORCA_OMP_CODING_AGENT_DIR).toBeUndefined()
@@ -2602,8 +2569,7 @@ describe('registerPtyHandlers', () => {
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/home/tester/.config/pi-agent',
'pi',
{ materializeDefaultHome: false }
'pi'
)
expect(env.PI_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_PI_CODING_AGENT_DIR).toBeUndefined()
@@ -3005,15 +2971,8 @@ describe('registerPtyHandlers', () => {
it('installs Pi managed extensions without redirecting homes on the daemon path', async () => {
const env = await daemonSpawnAndGetEnv({ PI_CODING_AGENT_DIR: '/user/.pi/agent' })
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/user/.pi/agent',
'pi',
{ materializeDefaultHome: false }
)
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'omp', {
materializeDefaultHome: false
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), '/user/.pi/agent', 'pi')
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(expect.any(String), undefined, 'omp')
expect(env.PI_CODING_AGENT_DIR).toBe('/user/.pi/agent')
expect(env.ORCA_PI_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_PI_SOURCE_AGENT_DIR).toBe('/user/.pi/agent')
@@ -3033,8 +2992,7 @@ describe('registerPtyHandlers', () => {
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/user/.omp/agent',
'omp',
{ materializeDefaultHome: true }
'omp'
)
expect(env.PI_CODING_AGENT_DIR).toBe('/user/.omp/agent')
expect(env.ORCA_OMP_CODING_AGENT_DIR).toBeUndefined()
@@ -3061,8 +3019,7 @@ describe('registerPtyHandlers', () => {
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/user/.omp/agent',
'omp',
{ materializeDefaultHome: true }
'omp'
)
expect(env.ORCA_OMP_STATUS_EXTENSION).toBe(
'/user/.omp/agent/extensions/orca-agent-status.ts'
@@ -4003,9 +3960,7 @@ describe('registerPtyHandlers', () => {
expect(sessionId).toEqual(expect.any(String))
expect((sessionId ?? '').length).toBeGreaterThan(0)
expect(spawnOpts.isNewSession).toBe(true)
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(sessionId, undefined, 'pi', {
materializeDefaultHome: false
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(sessionId, undefined, 'pi')
})
it('respects a caller-provided sessionId instead of minting a new one', async () => {
@@ -4020,9 +3975,7 @@ describe('registerPtyHandlers', () => {
})
expect(daemonSpawn.mock.calls.at(-1)![0].sessionId).toBe('user-session-42')
expect(daemonSpawn.mock.calls.at(-1)![0].isNewSession).toBeUndefined()
expect(piBuildPtyEnvMock).toHaveBeenCalledWith('user-session-42', undefined, 'pi', {
materializeDefaultHome: false
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith('user-session-42', undefined, 'pi')
})
it('prefixes a minted sessionId with the worktreeId when provided', async () => {
@@ -4038,9 +3991,7 @@ describe('registerPtyHandlers', () => {
})
const sessionId = daemonSpawn.mock.calls.at(-1)![0].sessionId ?? ''
expect(sessionId).toMatch(/^wt-alpha@@[0-9a-f]{8}$/)
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(sessionId, undefined, 'pi', {
materializeDefaultHome: false
})
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(sessionId, undefined, 'pi')
})
it('reuses one attach-style daemon session for fresh-agent operation retries', async () => {
@@ -4119,8 +4070,7 @@ describe('registerPtyHandlers', () => {
expect(piBuildPtyEnvMock).toHaveBeenCalledWith(
expect.any(String),
'/ambient/pi/agent',
'pi',
{ materializeDefaultHome: false }
'pi'
)
expect(env.PI_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_PI_CODING_AGENT_DIR).toBeUndefined()
@@ -8906,13 +8856,11 @@ describe('registerPtyHandlers', () => {
'ORCA_CLI_COMMAND/u',
'ORCA_AGENT_HOOK_PORT/u',
'ORCA_AGENT_HOOK_TOKEN/u',
'ORCA_OMP_SOURCE_AGENT_DIR/p',
'ORCA_OMP_STATUS_EXTENSION/p',
'POWERLEVEL9K_DISABLE_CONFIGURATION_WIZARD'
])
)
expect(env.WSLENV?.split(':')).not.toEqual(
expect.arrayContaining(['ORCA_OMP_SOURCE_AGENT_DIR/p'])
)
})
it('forces managed ORCA_USER_DATA_PATH for WSL spawns even when the caller provides a stale root', async () => {
+2 -6
View File
@@ -1166,17 +1166,13 @@ export function buildPtyHostEnv(
clearPiAgentShadowEnv(baseEnv, 'pi')
clearPiAgentShadowEnv(baseEnv, 'omp')
if (piAgentKind === 'pi') {
const piEnv = piTitlebarExtensionService.buildPtyEnv(id, preexistingPiAgentDir, 'pi', {
materializeDefaultHome: hasLaunchCommand
})
const piEnv = piTitlebarExtensionService.buildPtyEnv(id, preexistingPiAgentDir, 'pi')
Object.assign(baseEnv, piEnv)
exposePiManagedExtensionEnv(baseEnv, 'pi', piEnv)
}
if (shouldPrepareOmpShadow) {
const ompEnv = piTitlebarExtensionService.buildPtyEnv(id, preexistingOmpAgentDir, 'omp', {
materializeDefaultHome: piAgentKind === 'omp'
})
const ompEnv = piTitlebarExtensionService.buildPtyEnv(id, preexistingOmpAgentDir, 'omp')
Object.assign(baseEnv, ompEnv)
exposePiManagedExtensionEnv(baseEnv, 'omp', ompEnv)
}
@@ -643,35 +643,6 @@ describe('PiTitlebarExtensionService', () => {
rmSync(fakeHome, { recursive: true, force: true })
}
})
it('bare-shell prep does not create missing ~/.pi or ~/.omp homes (#10196)', () => {
const fakeHome = mkdtempSync(join(tmpdir(), 'orca-no-eager-agent-home-'))
expect(existsSync(join(fakeHome, '.pi'))).toBe(false)
expect(existsSync(join(fakeHome, '.omp'))).toBe(false)
homedirOverride.current = fakeHome
try {
const svc = new PiTitlebarExtensionService()
const piEnv = svc.buildPtyEnv('pty-bare-pi', undefined, 'pi', {
materializeDefaultHome: false
})
const ompEnv = svc.buildPtyEnv('pty-bare-omp', undefined, 'omp', {
materializeDefaultHome: false
})
expect(piEnv).toEqual({})
expect(existsSync(join(fakeHome, '.pi'))).toBe(false)
expect(existsSync(join(fakeHome, '.omp'))).toBe(false)
expect(ompEnv.ORCA_OMP_SOURCE_AGENT_DIR).toBeUndefined()
expect(ompEnv.ORCA_OMP_STATUS_EXTENSION).toEqual(
expect.stringContaining('omp-managed-status-extension')
)
expect(existsSync(ompEnv.ORCA_OMP_STATUS_EXTENSION!)).toBe(true)
} finally {
homedirOverride.current = ''
rmSync(fakeHome, { recursive: true, force: true })
}
})
})
describe('isSafeDescendCandidate (Windows junction regression guard)', () => {
+1 -11
View File
@@ -169,8 +169,7 @@ export class PiTitlebarExtensionService {
buildPtyEnv(
ptyId: string,
existingAgentDir: string | undefined,
kind: PiAgentKind,
options?: { materializeDefaultHome?: boolean }
kind: PiAgentKind
): Record<string, string> {
const sourceAgentDir = existingAgentDir || getDefaultPiAgentDir(kind)
try {
@@ -181,15 +180,6 @@ export class PiTitlebarExtensionService {
// directory should not prevent the terminal from starting.
}
if (!existsSync(sourceAgentDir) && options?.materializeDefaultHome === false) {
if (kind === 'omp') {
const statusSource = withOrcaManagedExtensionMarker(getPiAgentStatusExtensionSource(kind))
const statusExtensionPath = this.writeOmpFallbackStatusExtension(statusSource)
return statusExtensionPath ? { ORCA_OMP_STATUS_EXTENSION: statusExtensionPath } : {}
}
return {}
}
if (kind === 'omp') {
migrateLegacyOmpOverlayState(sourceAgentDir, this.getSourceOverlayDir(sourceAgentDir, 'omp'))
}
+31 -59
View File
@@ -72,10 +72,9 @@ describe('PluginOverlayManager', () => {
it('installs Pi extension into the real agent extensions dir', () => {
manager.setSources({ piExtensionSource: '// pi extension' })
const result = manager.materializePi('tab-2:0')
expect(result?.sourceAgentDir).toBeDefined()
const file = join(result!.sourceAgentDir!, 'extensions', 'orca-agent-status.ts')
expect(result?.statusExtensionPath).toBe(file)
const dir = manager.materializePi('tab-2:0')
expect(dir).not.toBeNull()
const file = join(dir!, 'extensions', 'orca-agent-status.ts')
expect(existsSync(file)).toBe(true)
expect(readFileSync(file, 'utf8')).toContain('@orca-managed-pi-extension')
})
@@ -97,17 +96,17 @@ describe('PluginOverlayManager', () => {
ompExtensionSource: '// omp extension'
})
const piResult = manager.materializePi('tab-kind-pi:0', undefined, 'pi')
const ompResult = manager.materializePi('tab-kind-omp:0', undefined, 'omp')
const piDir = manager.materializePi('tab-kind-pi:0', undefined, 'pi')
const ompDir = manager.materializePi('tab-kind-omp:0', undefined, 'omp')
expect(piResult?.sourceAgentDir).toBeDefined()
expect(ompResult?.sourceAgentDir).toBeDefined()
expect(
readFileSync(join(piResult!.sourceAgentDir!, 'extensions', 'orca-agent-status.ts'), 'utf8')
).toContain('// pi extension')
expect(
readFileSync(join(ompResult!.sourceAgentDir!, 'extensions', 'orca-agent-status.ts'), 'utf8')
).toContain('// omp extension')
expect(piDir).not.toBeNull()
expect(ompDir).not.toBeNull()
expect(readFileSync(join(piDir!, 'extensions', 'orca-agent-status.ts'), 'utf8')).toContain(
'// pi extension'
)
expect(readFileSync(join(ompDir!, 'extensions', 'orca-agent-status.ts'), 'utf8')).toContain(
'// omp extension'
)
})
it('installs Orca status extension into the remote default Pi agent dir', () => {
@@ -130,10 +129,9 @@ describe('PluginOverlayManager', () => {
)
manager.setSources({ piExtensionSource: '// pi extension' })
const result = manager.materializePi('tab-pi:0')
const dir = result?.sourceAgentDir
const dir = manager.materializePi('tab-pi:0')
expect(dir).toBeDefined()
expect(dir).not.toBeNull()
expect(readFileSync(join(dir!, 'auth.json'), 'utf8')).toBe('secret token')
expect(readFileSync(join(dir!, 'skills', 'my-skill', 'SKILL.md'), 'utf8')).toBe(
'critical user skill'
@@ -173,10 +171,9 @@ describe('PluginOverlayManager', () => {
writeFileSync(join(customAgentDir, 'extensions', 'custom.ts'), 'custom extension')
manager.setSources({ piExtensionSource: '// pi extension' })
const result = manager.materializePi('tab-custom-pi:0', customAgentDir)
const dir = result?.sourceAgentDir
const dir = manager.materializePi('tab-custom-pi:0', customAgentDir)
expect(dir).toBeDefined()
expect(dir).not.toBeNull()
expect(readFileSync(join(dir!, 'auth.json'), 'utf8')).toBe('custom token')
expect(readFileSync(join(dir!, 'extensions', 'custom.ts'), 'utf8')).toBe('custom extension')
expect(readFileSync(join(dir!, 'extensions', 'orca-agent-status.ts'), 'utf8')).toContain(
@@ -187,9 +184,10 @@ describe('PluginOverlayManager', () => {
it('leaves lazy OMP agent.db in the real remote home on the relay', () => {
manager.setSources({ piExtensionSource: '// pi extension' })
const sourceDir = join(homeDir, '.omp', 'agent')
const first = manager.materializePi('tab-relay-omp-sqlite:0', undefined, 'omp')
const firstDir = manager.materializePi('tab-relay-omp-sqlite:0', undefined, 'omp')
expect(first?.sourceAgentDir).toBe(sourceDir)
expect(firstDir).not.toBeNull()
expect(firstDir).toBe(sourceDir)
const sourcePath = join(sourceDir, 'agent.db')
const content = 'agent.db relay credentials'
@@ -200,10 +198,10 @@ describe('PluginOverlayManager', () => {
expect(readFileSync(sourcePath, 'utf8')).toBe(content)
const second = manager.materializePi('tab-relay-omp-sqlite:0', undefined, 'omp')
const secondDir = manager.materializePi('tab-relay-omp-sqlite:0', undefined, 'omp')
expect(second?.sourceAgentDir).toBe(first?.sourceAgentDir)
expect(readFileSync(join(second!.sourceAgentDir!, 'agent.db'), 'utf8')).toBe(content)
expect(secondDir).toBe(firstDir)
expect(readFileSync(join(secondDir!, 'agent.db'), 'utf8')).toBe(content)
})
// Why: per-agent source dir. The renderer picks Pi or OMP per
@@ -224,9 +222,9 @@ describe('PluginOverlayManager', () => {
seedAgentDir('.omp', 'omp')
manager.setSources({ piExtensionSource: '// pi extension' })
const result = manager.materializePi('tab-relay-pi-both:0', undefined, 'pi')
const dir = result?.sourceAgentDir
const dir = manager.materializePi('tab-relay-pi-both:0', undefined, 'pi')
expect(dir).not.toBeNull()
expect(dir).toBe(join(homeDir, '.pi', 'agent'))
expect(readFileSync(join(dir!, 'auth.json'), 'utf8')).toBe('pi token')
const extensions = readdirSync(join(dir!, 'extensions')).sort()
@@ -240,9 +238,9 @@ describe('PluginOverlayManager', () => {
seedAgentDir('.omp', 'omp')
manager.setSources({ piExtensionSource: '// pi extension' })
const result = manager.materializePi('tab-relay-omp-both:0', undefined, 'omp')
const dir = result?.sourceAgentDir
const dir = manager.materializePi('tab-relay-omp-both:0', undefined, 'omp')
expect(dir).not.toBeNull()
expect(dir).toBe(join(homeDir, '.omp', 'agent'))
// Even though ~/.pi/agent exists, the OMP launch MUST mirror OMP's
// source dir. Cross-agent fallback would silently shadow the user's
@@ -261,41 +259,15 @@ describe('PluginOverlayManager', () => {
expect(existsSync(join(homeDir, '.omp'))).toBe(false)
manager.setSources({ piExtensionSource: '// pi extension' })
const result = manager.materializePi('tab-relay-omp-empty:0', undefined, 'omp')
const dir = result?.sourceAgentDir
const dir = manager.materializePi('tab-relay-omp-empty:0', undefined, 'omp')
expect(dir).not.toBeNull()
expect(dir).toBe(join(homeDir, '.omp', 'agent'))
// Pi-only home must NOT leak into the OMP home.
expect(existsSync(join(dir!, 'auth.json'))).toBe(false)
const extensions = readdirSync(join(dir!, 'extensions')).sort()
expect(extensions).toEqual(['orca-agent-status.ts'])
})
it('bare-shell prep does not create missing remote agent homes (#10196)', () => {
expect(existsSync(join(homeDir, '.pi'))).toBe(false)
expect(existsSync(join(homeDir, '.omp'))).toBe(false)
manager.setSources({
piExtensionSource: '// pi extension',
ompExtensionSource: '// omp extension'
})
expect(
manager.materializePi('tab-bare-pi:0', undefined, 'pi', {
materializeDefaultHome: false
})
).toBeNull()
const bareOmp = manager.materializePi('tab-bare-omp:0', undefined, 'omp', {
materializeDefaultHome: false
})
expect(bareOmp?.sourceAgentDir).toBeUndefined()
expect(bareOmp?.statusExtensionPath).toEqual(
expect.stringContaining(join('.orca-relay', 'omp-managed-status-extension'))
)
expect(existsSync(bareOmp!.statusExtensionPath!)).toBe(true)
expect(readFileSync(bareOmp!.statusExtensionPath!, 'utf8')).toContain('// omp extension')
expect(existsSync(join(homeDir, '.pi'))).toBe(false)
expect(existsSync(join(homeDir, '.omp'))).toBe(false)
})
})
it('does not override a missing preexisting Pi agent dir', () => {
@@ -311,8 +283,8 @@ describe('PluginOverlayManager', () => {
ompExtensionSource: 'omp'
})
const opencodeDir = manager.materializeOpenCode('tab-3:0')!
const piDir = manager.materializePi('tab-3:0', undefined, 'pi')!.sourceAgentDir!
const ompDir = manager.materializePi('tab-3:0', undefined, 'omp')!.sourceAgentDir!
const piDir = manager.materializePi('tab-3:0', undefined, 'pi')!
const ompDir = manager.materializePi('tab-3:0', undefined, 'omp')!
expect(piDir).not.toBe(ompDir)
expect(existsSync(opencodeDir)).toBe(true)
expect(existsSync(piDir)).toBe(true)
+7 -43
View File
@@ -41,7 +41,6 @@ const PI_OVERLAY_SUBDIR_BY_KIND: Record<PiAgentKind, string> = {
const OPENCODE_PLUGIN_FILE = 'orca-opencode-status.js'
const PI_EXTENSION_FILE = 'orca-agent-status.ts'
const PI_AGENT_SUBDIR = 'agent'
const OMP_MANAGED_STATUS_EXTENSION_DIR = 'omp-managed-status-extension'
const ORCA_MANAGED_EXTENSION_MARKER = '@orca-managed-pi-extension'
function withOrcaManagedPiExtensionMarker(source: string): string {
@@ -80,9 +79,8 @@ export type PluginSources = {
ompExtensionSource?: string
}
export type MaterializePiResult = {
sourceAgentDir?: string
statusExtensionPath?: string
export function getRelayPiStatusExtensionPath(agentDir: string): string {
return join(agentDir, 'extensions', PI_EXTENSION_FILE)
}
/** Presence of this file is what makes an overlay usable — a rebuild that failed
@@ -238,30 +236,10 @@ export class PluginOverlayManager {
}
}
private writeOmpManagedStatusExtension(extensionSource: string): string | null {
const fallbackDir = join(this.homeDir, RELAY_HOOKS_DIR, OMP_MANAGED_STATUS_EXTENSION_DIR)
try {
mkdirSync(fallbackDir, { recursive: true })
const fallbackPath = join(fallbackDir, PI_EXTENSION_FILE)
if (!this.canOverwritePiExtension(fallbackPath)) {
return null
}
writeFileSync(fallbackPath, extensionSource)
return fallbackPath
} catch (err) {
process.stderr.write(
`[plugin-overlay] failed to write OMP managed status extension: ${err instanceof Error ? err.message : String(err)}\n`
)
return null
}
}
materializePi(
id: string,
existingAgentDir?: string,
kind: PiAgentKind = 'pi',
options?: { materializeDefaultHome?: boolean }
): MaterializePiResult | null {
/** Install the Pi/OMP status extension into the remote real agent dir and
* return that directory. `kind` selects which Pi-compatible agent's default
* dir to use when `existingAgentDir` is not supplied. */
materializePi(id: string, existingAgentDir?: string, kind: PiAgentKind = 'pi'): string | null {
const extensionSource = this.getPiExtensionSource(kind)
if (!extensionSource || !isUsableId(id)) {
return null
@@ -271,17 +249,6 @@ export class PluginOverlayManager {
if (existingAgentDir && !existsSync(existingAgentDir)) {
return null
}
if (
!existingAgentDir &&
!existsSync(sourceAgentDir) &&
options?.materializeDefaultHome === false
) {
if (kind === 'omp') {
const statusExtensionPath = this.writeOmpManagedStatusExtension(extensionSource)
return statusExtensionPath ? { statusExtensionPath } : null
}
return null
}
const extensionsDir = join(sourceAgentDir, 'extensions')
mkdirSync(extensionsDir, { recursive: true })
const extensionPath = join(extensionsDir, PI_EXTENSION_FILE)
@@ -289,10 +256,7 @@ export class PluginOverlayManager {
return null
}
writeFileSync(extensionPath, extensionSource)
return {
sourceAgentDir,
statusExtensionPath: extensionPath
}
return sourceAgentDir
} catch (err) {
process.stderr.write(
`[plugin-overlay] failed to install ${kind} extension: ${err instanceof Error ? err.message : String(err)}\n`
+8 -14
View File
@@ -33,7 +33,7 @@ import { PortScanHandler } from './port-scan-handler'
import { AgentExecHandler } from './agent-exec-handler'
import { WorkspaceSessionHandler } from './workspace-session-handler'
import { endpointDirForRelaySocket, RelayAgentHookServer } from './agent-hook-server'
import { PluginOverlayManager } from './plugin-overlay'
import { PluginOverlayManager, getRelayPiStatusExtensionPath } from './plugin-overlay'
import {
AGENT_HOOK_INSTALL_PLUGINS_METHOD,
AGENT_HOOK_NOTIFICATION_METHOD,
@@ -585,11 +585,9 @@ async function main(): Promise<void> {
const shouldPrepareOmpShadow = kind === 'omp' || !hasLaunchCommand
if (kind === 'pi') {
const sourceDir = resolvePiSourceAgentDir(ctx.env, ctx.shell, 'pi')
const result = pluginOverlay.materializePi(overlayId, sourceDir, 'pi', {
materializeDefaultHome: hasLaunchCommand
})
if (result?.sourceAgentDir) {
env.ORCA_PI_SOURCE_AGENT_DIR = result.sourceAgentDir
const dir = pluginOverlay.materializePi(overlayId, sourceDir, 'pi')
if (dir) {
env.ORCA_PI_SOURCE_AGENT_DIR = dir
}
}
if (shouldPrepareOmpShadow) {
@@ -598,14 +596,10 @@ async function main(): Promise<void> {
kind === 'omp'
? resolvePiSourceAgentDir(ctx.env, ctx.shell, 'omp')
: ctx.env.ORCA_OMP_SOURCE_AGENT_DIR
const result = pluginOverlay.materializePi(overlayId, sourceDir, 'omp', {
materializeDefaultHome: kind === 'omp'
})
if (result?.statusExtensionPath) {
env.ORCA_OMP_STATUS_EXTENSION = result.statusExtensionPath
}
if (result?.sourceAgentDir) {
env.ORCA_OMP_SOURCE_AGENT_DIR = result.sourceAgentDir
const dir = pluginOverlay.materializePi(overlayId, sourceDir, 'omp')
if (dir) {
env.ORCA_OMP_STATUS_EXTENSION = getRelayPiStatusExtensionPath(dir)
env.ORCA_OMP_SOURCE_AGENT_DIR = dir
}
}
}