mirror of
https://github.com/stablyai/orca.git
synced 2026-11-06 03:57:35 +00:00
* feat(omp): open OMP in the structured chat over ACP
OMP joins Grok and OpenCode on the ACP lane: `omp acp`, with the user's
environment passed through and the chat pinned to PI_CODING_AGENT_DIR
(default ~/.omp/agent), the directory OMP's terminal chats read. A create
and every launch ask `omp --version` of the binary the Command setting
resolves to; stable releases from 17.0.5 run the chat, older ones keep the
terminal-backed chat. Like every ACP agent it runs only with the updated
structured native chat setting on.
* fix(omp): show a shell command's output and exit code in its row
OMP's ACP server sends a command's result as rawOutput {content, details}
with a non-zero exit at details.exitCode, and repeats it as content behind
a "$ <command>" echo. The shared reader takes content text first, so the
row's output began with the command and carried no exit code. The OMP
dialect drops the echo, moves the result text to stdout without OMP's
"Wall time" and "Command exited with code N" notice lines, and maps
details.exitCode. Recordings of omp acp 17.0.5 (exit 3, exit 0, Stop
mid-command) replay through the adapter.
119 lines
3.7 KiB
TypeScript
119 lines
3.7 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import {
|
|
isStableCliVersionFrom,
|
|
isStableCliVersionOnLine,
|
|
probeAgentCliVersion
|
|
} from './agent-cli-version-probe'
|
|
|
|
const { runProcess } = vi.hoisted(() => ({ runProcess: vi.fn() }))
|
|
vi.mock('../shared/child-process/run-process', () => ({ runProcess }))
|
|
|
|
const INPUT = { program: '/opt/bin/agent', cwd: '/repo', env: { PATH: '/opt/bin' } }
|
|
const anyVersion = (): boolean => true
|
|
|
|
function prints(stdout: string, result: Record<string, unknown> = {}): void {
|
|
runProcess.mockResolvedValue({
|
|
code: 0,
|
|
signal: null,
|
|
stdout,
|
|
stderr: '',
|
|
timedOut: false,
|
|
...result
|
|
})
|
|
}
|
|
|
|
describe('probeAgentCliVersion', () => {
|
|
beforeEach(() => runProcess.mockReset())
|
|
|
|
it('asks the program for its version, bounded, where and as the launch would run it', async () => {
|
|
prints('1.18.31\n')
|
|
const seen: string[] = []
|
|
expect(await probeAgentCliVersion(INPUT, (version) => (seen.push(version), true))).toBe(true)
|
|
expect(seen).toEqual(['1.18.31'])
|
|
expect(runProcess).toHaveBeenCalledWith({
|
|
...INPUT,
|
|
args: ['--version'],
|
|
timeoutMs: 5_000,
|
|
maxOutputBytes: 4_096,
|
|
killOnOutputLimit: true
|
|
})
|
|
})
|
|
|
|
it('reads a version printed with a name or a v prefix', async () => {
|
|
prints('opencode v2.0.21\n')
|
|
const seen: string[] = []
|
|
await probeAgentCliVersion(INPUT, (version) => (seen.push(version), true))
|
|
expect(seen).toEqual(['2.0.21'])
|
|
})
|
|
|
|
it('reads a version printed after the program name and a slash', async () => {
|
|
prints('omp/17.0.5\n')
|
|
const seen: string[] = []
|
|
await probeAgentCliVersion(INPUT, (version) => (seen.push(version), true))
|
|
expect(seen).toEqual(['17.0.5'])
|
|
})
|
|
|
|
it.each([
|
|
['a non-zero exit', { code: 1 }],
|
|
['a timeout', { timedOut: true }],
|
|
['oversized output', { outputTruncated: true }]
|
|
])('cannot tell after %s', async (_label, result) => {
|
|
prints('1.18.31\n', result)
|
|
expect(await probeAgentCliVersion(INPUT, anyVersion)).toBe(false)
|
|
})
|
|
|
|
it('cannot tell when the output names no version, or the program does not start', async () => {
|
|
prints('usage: agent [options]\n')
|
|
expect(await probeAgentCliVersion(INPUT, anyVersion)).toBe(false)
|
|
runProcess.mockImplementationOnce(() => {
|
|
throw new Error('spawn ENOENT')
|
|
})
|
|
expect(await probeAgentCliVersion(INPUT, anyVersion)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('probeAgentCliVersion refusal', () => {
|
|
beforeEach(() => runProcess.mockReset())
|
|
|
|
it('says why it refused, with what the binary printed', async () => {
|
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
prints('', { code: 1, stderr: 'Error: EACCES mkdir /x\n' })
|
|
await probeAgentCliVersion(INPUT, anyVersion)
|
|
prints('2.0.21\n')
|
|
await probeAgentCliVersion(INPUT, () => false)
|
|
expect(warn.mock.calls.map(([line]) => line)).toEqual([
|
|
'[agent-cli-version] /opt/bin/agent --version: exited 1: Error: EACCES mkdir /x',
|
|
'[agent-cli-version] /opt/bin/agent --version: 2.0.21 is not a supported release'
|
|
])
|
|
warn.mockRestore()
|
|
})
|
|
})
|
|
|
|
describe('isStableCliVersionOnLine', () => {
|
|
const line = { major: 1, floor: '1.18.31' }
|
|
|
|
it.each([
|
|
['1.18.31', true],
|
|
['1.19.2', true],
|
|
['1.18.30', false],
|
|
['2.0.21', false],
|
|
['1.18.31-beta.1', false],
|
|
['11.0.0', false]
|
|
])('%s -> %s', (version, supported) => {
|
|
expect(isStableCliVersionOnLine(version, line)).toBe(supported)
|
|
})
|
|
})
|
|
|
|
describe('isStableCliVersionFrom', () => {
|
|
it.each([
|
|
['17.0.5', true],
|
|
['17.2.12', true],
|
|
['18.4.5', true],
|
|
['17.0.4', false],
|
|
['16.9.0', false],
|
|
['18.0.0-beta.1', false]
|
|
])('%s -> %s', (version, supported) => {
|
|
expect(isStableCliVersionFrom(version, '17.0.5')).toBe(supported)
|
|
})
|
|
})
|