Files
orca/src/shared/codex-cli-installation.test.ts
T
Brennan Benson c0e2b73395 feat(native-chat): require Codex 0.136.0 for chats (#26684)
* Require Codex 0.136.0 for native chats

* Add host-owned Codex install and update actions

* Bind Codex checks and maintenance to the selected installation

* Resolve Windows updater cleanup through system helpers

* Use one child environment for Codex checks and launch

* Expire Codex readiness and reconcile current host jobs

* Resolve Codex checks against the child command search path

* Restrict global npm repair to the selected Codex install layout

* Pin the host updater directory through Windows supervision

* Synchronize Codex maintenance fixtures on readiness

* Unify Codex notices and recover version-refused chats

* Route Codex recovery to the operation that remains

* Preserve Codex setup execution errors in the job log

* Preserve UTF-8 in Codex setup logs

* Remove unused Codex host installation detector

* Require host administration for Codex maintenance

* Show a missing Codex explanation once

* test(native-chat): give scripted Codex runtimes their installation fact; keep the registry out of the relay

Runtime tests that drive a scripted Codex app-server still ran the new
version check against whatever codex was on the machine's PATH: refused
on CI (no codex), and on a dev machine it ran the real codex --version.
A scripted transport now must state the Codex it stands for
(readCodexInstallation), asserted at install, and the tests get it from
one scriptedCodexTransport fixture.

The relay's Codex maintenance path reached @orca/windows-registry through
resolvePathEnvKey's re-export in windows-environment-path; import it from
its registry-free module instead.

Also update the catalog-probe test for the shared child environment.

* refactor(native-chat): drop the Update Codex action; keep Install for a missing Codex

A too-old Codex now gets only the plain message ("Codex X is too old for
chats. Update to 0.136.0 or newer.") with no button and no job. The
existing rechecks (window focus, the <=30 s expiry of a saved result)
retry the refused chat once the user has updated Codex themselves.

A missing Codex keeps the Install Codex button: `npm install -g
@openai/codex` with the npm on the chat's PATH, as a host-run job with
its log, then a recheck and recovery. A configured Command that is
missing gets the message only, since a global npm install would not
land at that path.

Removed: the `codex update` command and its 0.126 floor, manual
instructions, npm layout and launcher identity detection, the action
descriptor (install|update) and its titles, the legacy capability, and
the SSH relay maintenance path (structured chat never runs over SSH or
WSL), so the relay preflight handler is back to main's.

* refactor(native-chat): keep Install Codex in Settings only

When Codex isn't installed, main already hides Codex from the New tab menu,
so the in-chat Install button was almost never reachable. Settings → Agents
already shows "Codex isn't installed." with Install Codex.

- Chats and the new-workspace composer now only state "Codex isn't
  installed." (no button, no install job from the chat).
- The Install action, its busy spinner and the host-busy subscription move
  into the Settings Codex row, the only place that starts the job.
- The store no longer re-checks every other workspace context when a job
  finishes. A refused chat recovers through the same re-check a too-old
  Codex uses (window focus, or the <=30 s expiry of a saved result).
- The chat recovery key no longer includes the install job id.
- Tests: Settings drives the install; a new test proves a chat refused for
  a missing Codex recovers through focus after a Settings install, not
  through the job; the expiry recovery test covers missing and too old.

* refactor(codex): check chat compatibility when acquiring the child

* Restore workspace submit guard and simplify Codex maintenance

* Keep only the Codex chat minimum version
2026-10-12 14:30:27 -07:00

50 lines
1.9 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
CODEX_MINIMUM_SUPPORTED_VERSION,
codexCliInstallation,
readCodexInstallationProblem
} from './codex-cli-installation'
describe('Codex structured chat version floor', () => {
it.each([
['codex-cli 0.135.0', 'unsupported'],
['codex-cli 0.136.0', 'ready'],
['codex-cli v0.136.0', 'ready'],
['0.136.0-alpha.2', 'unsupported'],
['0.136.0+build.2', 'ready'],
['0.137.0-alpha.2', 'ready'],
['codex-cli 0.153.4\n', 'ready'],
['codex-cli 1.0.0', 'ready'],
['codex-cli unknown', 'unknown'],
['company-wrapper 0.1.0\ncodex-cli 0.136.0', 'ready'],
['company-wrapper 9.0.0\ncodex-cli 0.135.0', 'unsupported'],
['codex-cli 0.135.0\ncodex-cli 0.136.0', 'unknown'],
['wrapper 0.135.0', 'unknown'],
['0.135.0\n0.136.0', 'unknown'],
['', 'unknown']
])('%s is %s', (output, status) => {
expect(codexCliInstallation(true, output)).toMatchObject({
status,
minimumVersion: CODEX_MINIMUM_SUPPORTED_VERSION
})
})
it('distinguishes an absent binary from an unverifiable version', () => {
expect(codexCliInstallation(false, null)).toMatchObject({ status: 'missing', version: null })
expect(codexCliInstallation(true, null)).toMatchObject({ status: 'unknown', version: null })
})
it('admits only version facts that can safely be put in the refusal sentence', () => {
const problem = { installedVersion: '0.135.0', minimumVersion: '0.136.0' }
expect(readCodexInstallationProblem(problem)).toEqual(problem)
expect(readCodexInstallationProblem({ ...problem, installedVersion: null })).toEqual({
...problem,
installedVersion: null
})
expect(
readCodexInstallationProblem({ ...problem, installedVersion: '<script>' })
).toBeUndefined()
expect(readCodexInstallationProblem({ ...problem, minimumVersion: '' })).toBeUndefined()
})
})