mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* fix(pi): resolve OMP tab identity from the outer wrapper, not the wrapped pi (#6364) OMP runs as a `shell → omp → pi` process tree and Orca recognizes both `omp` and `pi` as distinct agents. The foreground-process readers scored the deepest `+` foreground descendant, so they returned the wrapped `pi` engine instead of the `omp` the user actually launched — and because the sampled `+` frame moves between omp and pi across command boundaries, the read oscillated and the tab icon/label flickered OMP↔Pi. It surfaced on Remote Host / SSH (only in a worktree, only while working) where a mirrored/restored pane has no client-side launchAgent to anchor identity, so the (host-read) foreground was the only pi/omp signal — and it was wrong. Fix the detection at its source so foregroundAgent is trustworthy everywhere (local tab icon, exit detection, and the remote mirror): - Add `resolveOuterWrapperForegroundProcess` (src/shared/foreground-wrapper-agent.ts): when the recognized foreground winner shares a `titleIdentityGroup` with a shallower recognized ancestor, return the shallowest — the outer wrapper. Stable regardless of which of omp/pi holds the foreground at the sample; bare Pi and cross-group reads (Codex, etc.) are unchanged. - Wire it into both readers: local `agent-foreground-process.ts` and the SSH relay `pty-shell-utils.ts`. Also harden the relay's fallback short-circuit so a pi-compatible process reported by node-pty rescans for the omp wrapper instead of trusting `pi` raw (never downgrading below the fallback). Also unify the host-side publish path onto the shared owner resolver: the mobile session snapshot builders now resolve pane ownership via `resolvePaneAgentOwner` ({launchAgent, hookAgent}) instead of a bespoke `launchAgent ?? foregroundAgent`, so the host stops being a divergent fourth identity path and the hook's host-stamped identity survives when launchAgent is dropped on a mirrored pane. Tests: unit coverage for the wrapper resolver, `shell→omp→pi` ps trees for both readers (outer omp, oscillating-frame, bare pi, node-pty pi fallback), and a host-snapshot regression that keeps an OMP hook labeled OMP when the wrapped pi child owns the foreground. * fix(pi): harden wrapper foreground ownership * fix(pi): preserve OMP ownership in daemon foreground reads * fix(pi): retain OMP owner when process scans fail
56 lines
2.0 KiB
TypeScript
56 lines
2.0 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { resolveOuterWrapperForegroundProcess } from './foreground-wrapper-agent'
|
|
|
|
describe('resolveOuterWrapperForegroundProcess', () => {
|
|
const omp = { agent: 'omp' as const, processName: 'omp' }
|
|
const pi = { agent: 'pi' as const, processName: 'pi' }
|
|
|
|
it('collapses a wrapped pi read onto the shallower omp wrapper', () => {
|
|
// Winner is the deeper pi (depth 2); omp is its wrapper at depth 1.
|
|
expect(
|
|
resolveOuterWrapperForegroundProcess(pi, { pid: 102, ppid: 101, command: 'pi' }, [
|
|
{ pid: 102, ppid: 101, command: 'pi' },
|
|
{ pid: 101, ppid: 100, command: 'omp' }
|
|
])
|
|
).toBe('omp')
|
|
})
|
|
|
|
it('keeps bare pi when no same-group wrapper is present', () => {
|
|
const barePi = { pid: 101, ppid: 100, command: 'pi' }
|
|
expect(resolveOuterWrapperForegroundProcess(pi, barePi, [barePi])).toBe('pi')
|
|
})
|
|
|
|
it('leaves a cross-group agent (codex) untouched even under a deeper same-name child', () => {
|
|
const codex = { agent: 'codex' as const, processName: 'codex' }
|
|
expect(
|
|
resolveOuterWrapperForegroundProcess(
|
|
codex,
|
|
{ pid: 102, ppid: 101, command: 'node /usr/bin/codex' },
|
|
[
|
|
{ pid: 102, ppid: 101, command: 'node /usr/bin/codex' },
|
|
{ pid: 101, ppid: 100, command: 'bash -l' }
|
|
]
|
|
)
|
|
).toBe('codex')
|
|
})
|
|
|
|
it('does not promote a deeper pi over an already-outer omp winner', () => {
|
|
expect(
|
|
resolveOuterWrapperForegroundProcess(omp, { pid: 101, ppid: 100, command: 'omp' }, [
|
|
{ pid: 101, ppid: 100, command: 'omp' },
|
|
{ pid: 102, ppid: 101, command: 'pi' }
|
|
])
|
|
).toBe('omp')
|
|
})
|
|
|
|
it('does not treat an unrelated shallower omp sibling as the pi wrapper', () => {
|
|
expect(
|
|
resolveOuterWrapperForegroundProcess(pi, { pid: 103, ppid: 102, command: 'pi' }, [
|
|
{ pid: 101, ppid: 100, command: 'omp' },
|
|
{ pid: 102, ppid: 100, command: 'node server.js' },
|
|
{ pid: 103, ppid: 102, command: 'pi' }
|
|
])
|
|
).toBe('pi')
|
|
})
|
|
})
|