mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* fix: recover from an alternate shell install, and close the relay echo gap #18768: a startup profile that `exec`s a second install of the same shell keeps the pid but loses the wrapper's ready marker, and the recovery probe rejected the replacement's different canonical path -- costing plain Codex the full 15s barrier. The probe now also accepts an install that the pane's own PATH resolves, so a binary merely named bash/zsh outside it stays rejected. #18767: the SSH relay left plain Codex on early startup delivery, displaying the launch twice under a slow profile. The shell is the host's to know, so the relay now folds it into the same rule the daemon uses, and the SSH background client waits for the marker on any Codex launch. Bracketed paste is now gated on an observed marker rather than on the intent to wait, so a fallback release on a host shell that never publishes one submits raw. The non-daemon local provider needs no change: it hands Codex to the wrapper's own prompt hook and never writes it into the PTY. * review: correct an overclaiming comment, announce a silent skip, drop a shim Readiness review of #18796. The delivery comment claimed waiting "costs nothing", which is only true on a host that arms the marker -- fish, sh, Windows and hosts predating #18767 release on the fallback instead. Say so. The alternate-install recovery tests skip on usrmerge hosts, where /usr/bin/bash resolves back to /bin/bash; announce that rather than reading as coverage that does not exist. Import the line-editor predicate from shared directly instead of through a re-export left on daemon/shell-ready.
120 lines
4.3 KiB
TypeScript
120 lines
4.3 KiB
TypeScript
import { mkdir, mkdtemp, rm, symlink } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { basename, dirname, join } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
parseDarwinExecutablePath,
|
|
resolveInstalledShellExecutablePaths,
|
|
resolveShellExecutablePath
|
|
} from './shell-process-readiness'
|
|
|
|
describe('shell process readiness', () => {
|
|
it('extracts the primary text image from macOS lsof output', () => {
|
|
expect(parseDarwinExecutablePath('p42\nftxt\nn/bin/zsh\nftxt\nn/usr/lib/zsh/zle.so\n')).toBe(
|
|
'/bin/zsh'
|
|
)
|
|
})
|
|
|
|
it.skipIf(process.platform === 'win32')(
|
|
'resolves bare shell commands through the spawn PATH',
|
|
async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'orca-shell-path-'))
|
|
const link = join(root, 'shell-name')
|
|
await symlink(process.execPath, link)
|
|
try {
|
|
await expect(resolveShellExecutablePath('shell-name', dirname(root), root)).resolves.toBe(
|
|
await resolveShellExecutablePath(process.execPath, dirname(root), root)
|
|
)
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true })
|
|
}
|
|
}
|
|
)
|
|
|
|
it.skipIf(process.platform === 'win32')(
|
|
'uses the POSIX exec default when PATH is unset',
|
|
async () => {
|
|
await expect(resolveShellExecutablePath('sh', process.cwd(), undefined)).resolves.toBe(
|
|
await resolveShellExecutablePath('/bin/sh', process.cwd(), '')
|
|
)
|
|
}
|
|
)
|
|
|
|
it.skipIf(process.platform === 'win32')(
|
|
'resolves relative shell paths against the PTY cwd',
|
|
async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'orca-relative-shell-'))
|
|
const bin = join(root, 'bin')
|
|
await symlink(dirname(process.execPath), bin)
|
|
try {
|
|
await expect(
|
|
resolveShellExecutablePath(`./bin/${basename(process.execPath)}`, root, '')
|
|
).resolves.toBe(await resolveShellExecutablePath(process.execPath, root, ''))
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true })
|
|
}
|
|
}
|
|
)
|
|
|
|
it.skipIf(process.platform === 'win32')(
|
|
'skips searchable directories that shadow a later PATH executable',
|
|
async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'orca-shadowed-shell-'))
|
|
const first = join(root, 'first')
|
|
const second = join(root, 'second')
|
|
await mkdir(join(first, 'shell-name'), { recursive: true })
|
|
await mkdir(second)
|
|
await symlink(process.execPath, join(second, 'shell-name'))
|
|
try {
|
|
await expect(
|
|
resolveShellExecutablePath('shell-name', root, `${first}:${second}`)
|
|
).resolves.toBe(await resolveShellExecutablePath(process.execPath, root, ''))
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true })
|
|
}
|
|
}
|
|
)
|
|
|
|
it.skipIf(process.platform === 'win32')(
|
|
'lists every PATH installation of a shell name, deduplicated and canonical',
|
|
async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'orca-installed-shells-'))
|
|
const first = join(root, 'first')
|
|
const second = join(root, 'second')
|
|
const missing = join(root, 'missing')
|
|
await mkdir(first)
|
|
await mkdir(second)
|
|
await symlink(process.execPath, join(first, 'shell-name'))
|
|
await symlink(process.execPath, join(second, 'shell-name'))
|
|
try {
|
|
const canonical = await resolveShellExecutablePath(process.execPath, root, '')
|
|
await expect(
|
|
resolveInstalledShellExecutablePaths('shell-name', root, `${first}:${missing}:${second}`)
|
|
).resolves.toEqual([canonical])
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true })
|
|
}
|
|
}
|
|
)
|
|
|
|
it.skipIf(process.platform === 'win32')(
|
|
'omits a same-name executable that no PATH entry reaches',
|
|
async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'orca-offpath-shell-'))
|
|
const onPath = join(root, 'bin')
|
|
const offPath = join(root, 'dropped')
|
|
await mkdir(onPath)
|
|
await mkdir(offPath)
|
|
await symlink(process.execPath, join(onPath, 'shell-name'))
|
|
await symlink(process.execPath, join(offPath, 'shell-name'))
|
|
try {
|
|
await expect(
|
|
resolveInstalledShellExecutablePaths('shell-name', root, onPath)
|
|
).resolves.not.toContain(join(offPath, 'shell-name'))
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true })
|
|
}
|
|
}
|
|
)
|
|
})
|