mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(omp): inherit login-shell directory settings for task launches
This commit is contained in:
@@ -160,7 +160,10 @@ export function buildPtyHostEnv(
|
||||
|
||||
if (shouldPrepareOmpShadow) {
|
||||
const ompEnv = piTitlebarExtensionService.buildPtyEnv(id, preexistingOmpAgentDir, 'omp', {
|
||||
materializeDefaultHome: explicitPiAgentKind === 'omp'
|
||||
materializeDefaultHome: explicitPiAgentKind === 'omp',
|
||||
...(baseEnv.PI_CONFIG_DIR !== undefined && !opts.isWsl
|
||||
? { configDirName: baseEnv.PI_CONFIG_DIR }
|
||||
: {})
|
||||
})
|
||||
Object.assign(baseEnv, ompEnv)
|
||||
exposePiManagedExtensionEnv(baseEnv, 'omp', ompEnv)
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { inheritOmpLaunchEnvironment } from './omp-launch-environment'
|
||||
import { resolveLoginShellEnvironment } from '../../../startup/login-shell-environment'
|
||||
|
||||
vi.mock('../../../startup/login-shell-environment', () => ({
|
||||
resolveLoginShellEnvironment: vi.fn()
|
||||
}))
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('process', { ...process, platform: 'darwin', env: {} })
|
||||
vi.mocked(resolveLoginShellEnvironment).mockReset().mockResolvedValue({
|
||||
XDG_DATA_HOME: '/login/data',
|
||||
XDG_STATE_HOME: '/login/state',
|
||||
XDG_CACHE_HOME: '/login/cache',
|
||||
PI_CONFIG_DIR: '.config/omp',
|
||||
PI_CODING_AGENT_DIR: '/pi/override',
|
||||
UNRELATED: 'ignore'
|
||||
})
|
||||
})
|
||||
afterEach(() => vi.unstubAllGlobals())
|
||||
|
||||
describe('OMP launch directory environment', () => {
|
||||
it.each([{ launchAgent: 'omp' }, { launchCommand: 'omp' }, {}])(
|
||||
'inherits login-shell category roots for %j',
|
||||
async (options) => {
|
||||
const env = {}
|
||||
await inheritOmpLaunchEnvironment(env, options)
|
||||
expect(env).toEqual({
|
||||
XDG_DATA_HOME: '/login/data',
|
||||
XDG_STATE_HOME: '/login/state',
|
||||
XDG_CACHE_HOME: '/login/cache',
|
||||
PI_CONFIG_DIR: '.config/omp'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it('uses the same login roots for merged local env and daemon pane deltas', async () => {
|
||||
const local = { XDG_DATA_HOME: '/old/data', PI_CONFIG_DIR: '.old-omp' }
|
||||
const daemon = {}
|
||||
await inheritOmpLaunchEnvironment(local, { launchAgent: 'omp', explicitEnv: {} })
|
||||
await inheritOmpLaunchEnvironment(daemon, { launchAgent: 'omp' })
|
||||
expect(local).toEqual(daemon)
|
||||
expect(local.XDG_DATA_HOME).toBe('/login/data')
|
||||
const overridden = { XDG_DATA_HOME: '/old/data' }
|
||||
await inheritOmpLaunchEnvironment(overridden, {
|
||||
launchAgent: 'omp',
|
||||
explicitEnv: { XDG_DATA_HOME: '/pane/data' }
|
||||
})
|
||||
expect(overridden.XDG_DATA_HOME).toBe('/pane/data')
|
||||
})
|
||||
|
||||
it('preserves explicit pane roots and intentionally empty values', async () => {
|
||||
const env = { XDG_DATA_HOME: '/pane/data', XDG_STATE_HOME: '' }
|
||||
await inheritOmpLaunchEnvironment(env, { launchAgent: 'omp' })
|
||||
expect(env.XDG_DATA_HOME).toBe('/pane/data')
|
||||
expect(env.XDG_STATE_HOME).toBe('')
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ isWsl: true, launchAgent: 'omp' },
|
||||
{ launchAgent: 'pi' },
|
||||
{ launchAgent: 'claude' },
|
||||
{ launchCommand: 'pi' },
|
||||
{ launchCommand: 'npm test' }
|
||||
])('does not probe a different execution environment for %j', async (options) => {
|
||||
const env = {}
|
||||
await inheritOmpLaunchEnvironment(env, options)
|
||||
expect(env).toEqual({})
|
||||
expect(resolveLoginShellEnvironment).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not import POSIX roots into native Windows', async () => {
|
||||
vi.stubGlobal('process', { ...process, platform: 'win32' })
|
||||
await inheritOmpLaunchEnvironment({}, { launchAgent: 'omp' })
|
||||
expect(resolveLoginShellEnvironment).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,38 @@
|
||||
import { detectExplicitPiAgentKindFromCommand } from '../../../../shared/pi-agent-kind'
|
||||
import { resolveSetupAgentSequenceLaunchCommand } from '../../../../shared/setup-agent-sequencing'
|
||||
import { resolveLoginShellEnvironment } from '../../../startup/login-shell-environment'
|
||||
|
||||
const OMP_DIRECTORY_ENV_KEYS = [
|
||||
'XDG_CONFIG_HOME',
|
||||
'XDG_DATA_HOME',
|
||||
'XDG_STATE_HOME',
|
||||
'XDG_CACHE_HOME',
|
||||
'PI_CONFIG_DIR'
|
||||
] as const
|
||||
|
||||
export async function inheritOmpLaunchEnvironment(
|
||||
env: Record<string, string>,
|
||||
options: {
|
||||
isWsl?: boolean
|
||||
launchAgent?: string
|
||||
launchCommand?: string
|
||||
explicitEnv?: Record<string, string>
|
||||
}
|
||||
): Promise<void> {
|
||||
if (options.isWsl || process.platform === 'win32') {
|
||||
return
|
||||
}
|
||||
const command = resolveSetupAgentSequenceLaunchCommand(env, options.launchCommand)
|
||||
const agent = options.launchAgent ?? detectExplicitPiAgentKindFromCommand(command)
|
||||
if (agent !== 'omp' && (options.launchAgent !== undefined || command?.trim())) {
|
||||
return
|
||||
}
|
||||
const shellEnv = await resolveLoginShellEnvironment()
|
||||
for (const key of OMP_DIRECTORY_ENV_KEYS) {
|
||||
// Explicit pane values, including empty values, take precedence over the login shell.
|
||||
const value = (options.explicitEnv ?? env)[key] ?? shellEnv[key] ?? process.env[key]
|
||||
if (value !== undefined) {
|
||||
env[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { inheritOmpLaunchEnvironment } from '../host-env/omp-launch-environment'
|
||||
import { getAppEnvironment } from '../../../../shared/app-environment'
|
||||
import { isTuiAgent } from '../../../../shared/tui-agent-config'
|
||||
import { isAgentStatusHooksEnabled } from '../../../agent-hooks/managed-agent-hook-controls'
|
||||
@@ -133,6 +134,11 @@ export async function assemblePtyIpcSpawnCodexEnv(ctx: PtyIpcSpawnState): Promis
|
||||
// Why: clone before mutating so injections don't leak back into args.env (renderer may reuse it).
|
||||
ctx.env = { ...ctx.baseEnv }
|
||||
try {
|
||||
await inheritOmpLaunchEnvironment(ctx.env, {
|
||||
isWsl: shouldSkipCodexHomeEnvForWindowsShell(ctx.effectiveShellOverride, ctx.cwd),
|
||||
launchAgent: args.launchAgent,
|
||||
launchCommand: ctx.launchCommand
|
||||
})
|
||||
buildPtyHostEnv(sessionIdForEnv, ctx.env, {
|
||||
isPackaged: getAppEnvironment().isPackaged(),
|
||||
resourcesPath: process.resourcesPath,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { inheritOmpLaunchEnvironment } from '../host-env/omp-launch-environment'
|
||||
import { getAppEnvironment } from '../../../../shared/app-environment'
|
||||
import type { OrcaRuntimeService } from '../../../runtime/orca-runtime'
|
||||
import type { GlobalSettings } from '../../../../shared/global-settings-types'
|
||||
@@ -55,6 +56,12 @@ export function configureLocalPtyProvider(args: {
|
||||
)
|
||||
const skipCodexHomeEnv = ctx?.isWsl === true && !selectedCodexHomePath
|
||||
const ptySettings = getSettings?.()
|
||||
await inheritOmpLaunchEnvironment(baseEnv, {
|
||||
explicitEnv: ctx?.explicitEnv,
|
||||
isWsl: ctx?.isWsl,
|
||||
launchAgent: ctx?.launchAgent,
|
||||
launchCommand: ctx?.command
|
||||
})
|
||||
const env = buildPtyHostEnv(id, baseEnv, {
|
||||
isPackaged: getAppEnvironment().isPackaged(),
|
||||
resourcesPath: process.resourcesPath,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { inheritOmpLaunchEnvironment } from '../host-env/omp-launch-environment'
|
||||
import { getAppEnvironment } from '../../../../shared/app-environment'
|
||||
import type { PtySpawnResult } from '../../../providers/types'
|
||||
import { LocalPtyProvider } from '../../../providers/local-pty-provider'
|
||||
@@ -258,6 +259,12 @@ export async function prepareRuntimePtySpawn(
|
||||
throw new Error('Invalid PTY session id')
|
||||
}
|
||||
try {
|
||||
ctx.env ??= {}
|
||||
await inheritOmpLaunchEnvironment(ctx.env, {
|
||||
isWsl: shouldSkipCodexHomeEnvForWindowsShell(ctx.daemonShellOverride, ctx.cwd),
|
||||
launchAgent: args.launchAgent,
|
||||
launchCommand: ctx.launchCommand
|
||||
})
|
||||
ctx.env = buildPtyHostEnv(ctx.sessionId, ctx.env ?? {}, {
|
||||
isPackaged: getAppEnvironment().isPackaged(),
|
||||
resourcesPath: process.resourcesPath,
|
||||
|
||||
@@ -98,6 +98,59 @@ describe('PiTitlebarExtensionService', () => {
|
||||
rmSync(join(userDataDir, 'omp-managed-status-extension'), { recursive: true, force: true })
|
||||
})
|
||||
|
||||
it.each([
|
||||
['pi', '.pi', 'ORCA_PI_SOURCE_AGENT_DIR'],
|
||||
['omp', '.omp', 'ORCA_OMP_SOURCE_AGENT_DIR'],
|
||||
['prime-agent', '.prime', 'ORCA_PRIME_AGENT_SOURCE_AGENT_DIR']
|
||||
] as const)('does not reinterpret XDG data as %s configuration', (kind, root, sourceKey) => {
|
||||
const fakeHome = mkdtempSync(join(tmpdir(), 'orca-agent-xdg-'))
|
||||
const dataHome = join(fakeHome, 'data')
|
||||
const dataAgentDir = join(dataHome, root.slice(1), 'agent')
|
||||
mkdirSync(dataAgentDir, { recursive: true })
|
||||
homedirOverride.current = fakeHome
|
||||
vi.stubEnv('XDG_DATA_HOME', dataHome)
|
||||
try {
|
||||
const env = new PiTitlebarExtensionService().buildPtyEnv('pty-xdg', undefined, kind)
|
||||
expect(env[sourceKey]).toBe(join(fakeHome, root, 'agent'))
|
||||
expect(readdirSync(dataAgentDir)).toEqual([])
|
||||
expect(env.PI_CODING_AGENT_DIR).toBeUndefined()
|
||||
} finally {
|
||||
vi.unstubAllEnvs()
|
||||
homedirOverride.current = ''
|
||||
rmSync(fakeHome, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('materializes OMP extensions under the launch config root without overriding data routing', () => {
|
||||
const fakeHome = mkdtempSync(join(tmpdir(), 'orca-omp-config-'))
|
||||
homedirOverride.current = fakeHome
|
||||
try {
|
||||
const service = new PiTitlebarExtensionService()
|
||||
const environment = { PI_CONFIG_DIR: '.config/omp', XDG_DATA_HOME: join(fakeHome, 'data') }
|
||||
const env = service.buildPtyEnv('pty-config', undefined, 'omp', {
|
||||
configDirName: environment.PI_CONFIG_DIR
|
||||
})
|
||||
const agentDir = join(fakeHome, '.config', 'omp', 'agent')
|
||||
expect(env.ORCA_OMP_SOURCE_AGENT_DIR).toBe(agentDir)
|
||||
expect(existsSync(join(agentDir, 'extensions', 'orca-agent-status.ts'))).toBe(true)
|
||||
expect(env.PI_CODING_AGENT_DIR).toBeUndefined()
|
||||
expect(existsSync(join(fakeHome, '.omp'))).toBe(false)
|
||||
expect(existsSync(environment.XDG_DATA_HOME)).toBe(false)
|
||||
expect(
|
||||
service.buildPtyEnv('pty-explicit', piHome, 'omp', {
|
||||
configDirName: environment.PI_CONFIG_DIR
|
||||
}).ORCA_OMP_SOURCE_AGENT_DIR
|
||||
).toBe(piHome)
|
||||
expect(
|
||||
service.buildPtyEnv('pty-pi', undefined, 'pi', { configDirName: environment.PI_CONFIG_DIR })
|
||||
.ORCA_PI_SOURCE_AGENT_DIR
|
||||
).toBe(join(fakeHome, '.pi', 'agent'))
|
||||
} finally {
|
||||
homedirOverride.current = ''
|
||||
rmSync(fakeHome, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
function expectPiHomeIntact(): void {
|
||||
expect(readFileSync(join(piHome, 'auth.json'), 'utf-8')).toBe('secret token')
|
||||
expect(readFileSync(join(piHome, 'skills', 'my-skill', 'SKILL.md'), 'utf-8')).toBe(
|
||||
|
||||
@@ -58,8 +58,9 @@ const AGENT_HOME_DIR_NAME: Record<PiAgentKind, string> = {
|
||||
'prime-agent': '.prime'
|
||||
}
|
||||
|
||||
function getDefaultPiAgentDir(kind: PiAgentKind): string {
|
||||
return join(homedir(), AGENT_HOME_DIR_NAME[kind], PI_AGENT_SUBDIR)
|
||||
function getDefaultPiAgentDir(kind: PiAgentKind, configDirName: string | undefined): string {
|
||||
const root = kind === 'omp' ? configDirName || AGENT_HOME_DIR_NAME.omp : AGENT_HOME_DIR_NAME[kind]
|
||||
return join(homedir(), root, PI_AGENT_SUBDIR)
|
||||
}
|
||||
|
||||
function toSafeOverlayDirName(ptyId: string): string {
|
||||
@@ -177,9 +178,11 @@ export class PiTitlebarExtensionService {
|
||||
ptyId: string,
|
||||
existingAgentDir: string | undefined,
|
||||
kind: PiAgentKind,
|
||||
options?: { materializeDefaultHome?: boolean }
|
||||
options?: { materializeDefaultHome?: boolean; configDirName?: string }
|
||||
): Record<string, string> {
|
||||
const sourceAgentDir = existingAgentDir || getDefaultPiAgentDir(kind)
|
||||
const sourceAgentDir =
|
||||
existingAgentDir ||
|
||||
getDefaultPiAgentDir(kind, options?.configDirName ?? process.env.PI_CONFIG_DIR)
|
||||
if (kind !== 'prime-agent') {
|
||||
try {
|
||||
this.safeRemoveOverlay(this.getPtyOverlayDir(ptyId, kind), kind)
|
||||
|
||||
@@ -179,6 +179,18 @@ describe('LocalPtyProvider', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('passes explicit pane environment separately from inherited process values', async () => {
|
||||
const buildSpawnEnv = vi.fn((_id: string, env: Record<string, string>) => env)
|
||||
provider.configure({ buildSpawnEnv })
|
||||
const env = { XDG_DATA_HOME: '/pane/data' }
|
||||
await provider.spawn({ cols: 80, rows: 24, env })
|
||||
expect(buildSpawnEnv).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.any(Object),
|
||||
expect.objectContaining({ explicitEnv: env })
|
||||
)
|
||||
})
|
||||
|
||||
it('invokes buildSpawnEnv callback to customize environment', async () => {
|
||||
const buildSpawnEnv = vi.fn((_id: string, env: Record<string, string>) => {
|
||||
env.CUSTOM_VAR = 'custom-value'
|
||||
|
||||
@@ -7,6 +7,7 @@ export type LocalPtyProviderOptions = {
|
||||
id: string,
|
||||
baseEnv: Record<string, string>,
|
||||
ctx?: {
|
||||
explicitEnv?: PtySpawnOptions['env']
|
||||
command?: string
|
||||
launchAgent?: PtySpawnOptions['launchAgent']
|
||||
codexHomePathOverride?: PtySpawnOptions['codexHomePathOverride']
|
||||
|
||||
@@ -61,6 +61,7 @@ export function buildLocalPtySpawnEnvironment(args: {
|
||||
return awaitCancelableLocalPtySpawn(
|
||||
id,
|
||||
getOptions().buildSpawnEnv!(id, spawnEnv, {
|
||||
explicitEnv: spawn.env ?? {},
|
||||
command: spawn.command,
|
||||
launchAgent: spawn.launchAgent,
|
||||
codexHomePathOverride: spawn.codexHomePathOverride,
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
import { chmod, mkdir, readFile, readdir, writeFile } from 'node:fs/promises'
|
||||
import { dirname, delimiter, join } from 'node:path'
|
||||
import { test as base, expect } from './helpers/orca-app'
|
||||
import { buildShellCommandFromArgv } from '../../src/shared/tui-agent-startup-shell'
|
||||
import { ensureTerminalVisible, waitForActiveWorktree, waitForSessionReady } from './helpers/store'
|
||||
import {
|
||||
execInTerminal,
|
||||
waitForActivePanePtyId,
|
||||
waitForActiveTerminalManager
|
||||
} from './helpers/terminal'
|
||||
|
||||
const test = base.extend({
|
||||
launchEnv: async ({ seedTestRepo }, run, testInfo) => {
|
||||
void seedTestRepo
|
||||
const shell = testInfo.outputPath('login-shell')
|
||||
const profileDir = testInfo.outputPath('profile')
|
||||
await mkdir(profileDir, { recursive: true })
|
||||
await writeFile(
|
||||
join(profileDir, '.zprofile'),
|
||||
`
|
||||
export PI_CONFIG_DIR="\${PI_CONFIG_DIR:-.omp-profile-proof}"
|
||||
export XDG_DATA_HOME="\${XDG_DATA_HOME:-$HOME/xdg-data}"
|
||||
export XDG_STATE_HOME="\${XDG_STATE_HOME:-$HOME/xdg-state}"
|
||||
export XDG_CACHE_HOME="\${XDG_CACHE_HOME:-$HOME/xdg-cache}"
|
||||
mkdir -p "$HOME/$PI_CONFIG_DIR/agent" "$XDG_DATA_HOME/omp" "$XDG_STATE_HOME/omp" "$XDG_CACHE_HOME/omp"
|
||||
`
|
||||
)
|
||||
await writeFile(
|
||||
shell,
|
||||
`#!/bin/sh
|
||||
case "$ORCA_E2E_HOME_DIR" in
|
||||
*/orca-e2e-userdata-*/home) ;;
|
||||
*) echo 'Refusing profile proof outside isolated E2E home' >&2; exit 73 ;;
|
||||
esac
|
||||
export HOME="$ORCA_E2E_HOME_DIR"
|
||||
export ZDOTDIR=${buildShellCommandFromArgv([profileDir], 'posix')}
|
||||
exec /bin/zsh "$@"
|
||||
`
|
||||
)
|
||||
await chmod(shell, 0o700)
|
||||
await run({
|
||||
PATH: [dirname(process.env.ORCA_OMP_PROOF_BINARY ?? '/usr/bin/omp'), process.env.PATH]
|
||||
.filter(Boolean)
|
||||
.join(delimiter),
|
||||
SHELL: shell,
|
||||
XDG_DATA_HOME: undefined,
|
||||
XDG_STATE_HOME: undefined,
|
||||
XDG_CACHE_HOME: undefined,
|
||||
XDG_CONFIG_HOME: undefined,
|
||||
PI_CONFIG_DIR: undefined
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('OMP launched by Orca uses login-profile data and config roots', async ({
|
||||
orcaPage,
|
||||
electronApp
|
||||
}, testInfo) => {
|
||||
test.skip(
|
||||
!process.env.ORCA_OMP_PROOF_BINARY || process.platform !== 'darwin',
|
||||
'Opt-in macOS OMP runtime proof'
|
||||
)
|
||||
await waitForSessionReady(orcaPage)
|
||||
const worktreeId = await waitForActiveWorktree(orcaPage)
|
||||
await ensureTerminalVisible(orcaPage)
|
||||
await waitForActiveTerminalManager(orcaPage)
|
||||
const ptyId = await waitForActivePanePtyId(orcaPage)
|
||||
const home = await electronApp.evaluate(({ app }) => app.getPath('home'))
|
||||
expect(await electronApp.evaluate(() => process.env.XDG_DATA_HOME)).toBeUndefined()
|
||||
const result = testInfo.outputPath('omp-paths.json')
|
||||
const probe = testInfo.outputPath('path-probe.ts')
|
||||
await writeFile(
|
||||
probe,
|
||||
`import { writeFileSync } from 'node:fs'
|
||||
export default function (api) {
|
||||
api.on('session_start', (_event, ctx) => {
|
||||
writeFileSync(process.env.ORCA_PATH_PROBE_OUTPUT || ${JSON.stringify(result)}, JSON.stringify({
|
||||
data: process.env.XDG_DATA_HOME, config: process.env.PI_CONFIG_DIR,
|
||||
source: process.env.ORCA_OMP_SOURCE_AGENT_DIR,
|
||||
status: process.env.ORCA_OMP_STATUS_EXTENSION,
|
||||
session: ctx.sessionManager.getSessionFile(), pid: process.pid
|
||||
}))
|
||||
})
|
||||
}`
|
||||
)
|
||||
await execInTerminal(
|
||||
orcaPage,
|
||||
ptyId,
|
||||
buildShellCommandFromArgv(['omp', '--no-extensions', '--extension', probe], 'posix')
|
||||
)
|
||||
await expect
|
||||
.poll(
|
||||
async () => {
|
||||
try {
|
||||
return JSON.parse(await readFile(result, 'utf8'))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
{ timeout: 45_000 }
|
||||
)
|
||||
.toEqual(
|
||||
expect.objectContaining({
|
||||
data: join(home, 'xdg-data'),
|
||||
config: '.omp-profile-proof',
|
||||
source: join(home, '.omp-profile-proof', 'agent'),
|
||||
status: expect.stringContaining(join('.omp-profile-proof', 'agent', 'extensions')),
|
||||
session: expect.stringContaining(join('xdg-data', 'omp', 'sessions'))
|
||||
})
|
||||
)
|
||||
await expect(orcaPage.locator('.xterm-screen').first()).toBeVisible()
|
||||
await orcaPage.screenshot({ path: testInfo.outputPath('omp-profile-root.png') })
|
||||
expect(await readdir(join(home, 'xdg-data', 'omp'))).toContain('agent.db')
|
||||
const overrideData = join(home, 'pane-data')
|
||||
await mkdir(join(overrideData, 'omp'), { recursive: true })
|
||||
const overrideResult = testInfo.outputPath('omp-pane-paths.json')
|
||||
const overridePty = await orcaPage.evaluate(
|
||||
async ({ command, worktreeId, home, overrideData, overrideResult }) => {
|
||||
const pane = await window.api.pty.spawn({
|
||||
cols: 100,
|
||||
rows: 30,
|
||||
cwd: home,
|
||||
worktreeId,
|
||||
initiallyHidden: true,
|
||||
launchAgent: 'omp',
|
||||
command,
|
||||
env: {
|
||||
XDG_DATA_HOME: overrideData,
|
||||
PI_CONFIG_DIR: '.omp-pane-config',
|
||||
ORCA_PATH_PROBE_OUTPUT: overrideResult
|
||||
}
|
||||
})
|
||||
return pane.id
|
||||
},
|
||||
{
|
||||
command: buildShellCommandFromArgv(['omp', '--no-extensions', '--extension', probe], 'posix'),
|
||||
worktreeId,
|
||||
home,
|
||||
overrideData,
|
||||
overrideResult
|
||||
}
|
||||
)
|
||||
try {
|
||||
await expect
|
||||
.poll(
|
||||
async () => {
|
||||
try {
|
||||
return JSON.parse(await readFile(overrideResult, 'utf8'))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
{ timeout: 45_000 }
|
||||
)
|
||||
.toEqual(
|
||||
expect.objectContaining({
|
||||
data: overrideData,
|
||||
config: '.omp-pane-config',
|
||||
source: join(home, '.omp-pane-config', 'agent'),
|
||||
session: expect.stringContaining(join('pane-data', 'omp', 'sessions'))
|
||||
})
|
||||
)
|
||||
expect(await readdir(join(overrideData, 'omp'))).toContain('agent.db')
|
||||
} finally {
|
||||
await orcaPage.evaluate((id) => window.api.pty.kill(id), overridePty)
|
||||
}
|
||||
const baselineResult = testInfo.outputPath('omp-login-baseline.json')
|
||||
const baselineCommand = buildShellCommandFromArgv(
|
||||
[
|
||||
'env',
|
||||
...[
|
||||
'XDG_DATA_HOME',
|
||||
'XDG_STATE_HOME',
|
||||
'XDG_CACHE_HOME',
|
||||
'PI_CONFIG_DIR',
|
||||
'ORCA_OMP_SOURCE_AGENT_DIR',
|
||||
'ORCA_OMP_STATUS_EXTENSION',
|
||||
'ORCA_PI_STATUS_OWNED',
|
||||
'ZDOTDIR',
|
||||
'ORCA_ORIG_ZDOTDIR'
|
||||
].flatMap((key) => ['-u', key]),
|
||||
`ORCA_PATH_PROBE_OUTPUT=${baselineResult}`,
|
||||
`HOME=${home}`,
|
||||
`ZDOTDIR=${testInfo.outputPath('profile')}`,
|
||||
'/bin/zsh',
|
||||
'-ilc',
|
||||
buildShellCommandFromArgv(
|
||||
[process.env.ORCA_OMP_PROOF_BINARY ?? '', '--no-extensions', '--extension', probe],
|
||||
'posix'
|
||||
)
|
||||
],
|
||||
'posix'
|
||||
)
|
||||
const baselinePty = await orcaPage.evaluate(
|
||||
async ({ command, worktreeId, home }) => {
|
||||
return (
|
||||
await window.api.pty.spawn({
|
||||
cols: 100,
|
||||
rows: 30,
|
||||
cwd: home,
|
||||
worktreeId,
|
||||
initiallyHidden: true,
|
||||
command
|
||||
})
|
||||
).id
|
||||
},
|
||||
{ command: baselineCommand, worktreeId, home }
|
||||
)
|
||||
try {
|
||||
await expect
|
||||
.poll(
|
||||
async () => {
|
||||
try {
|
||||
return JSON.parse(await readFile(baselineResult, 'utf8'))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
{ timeout: 45_000 }
|
||||
)
|
||||
.toEqual(
|
||||
expect.objectContaining({
|
||||
data: join(home, 'xdg-data'),
|
||||
config: '.omp-profile-proof',
|
||||
session: expect.stringContaining(join('xdg-data', 'omp', 'sessions'))
|
||||
})
|
||||
)
|
||||
} finally {
|
||||
await orcaPage.evaluate((id) => window.api.pty.kill(id), baselinePty)
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user