diff --git a/docs/cli-registry.md b/docs/cli-registry.md index 655ecfac..bd086867 100644 --- a/docs/cli-registry.md +++ b/docs/cli-registry.md @@ -81,10 +81,11 @@ Two CLIs declare such a row today, and they put it in different places. Claude w chip on the last row of the screen, so it keeps the default one-row window and anchors on the `·` its footer joins items with. Codex pins `1 background terminal running · /ps to view · /stop to close` ABOVE its composer, which -puts the row third from the bottom once the status line and the composer are counted, so its -entry declares `watchingLines: 3` and matches that row end to end. Both were measured -against live panes rather than read out of a binary, which is the standard for adding a -third. +puts the row third from the bottom once the status line and the composer are counted, and +fourth on codex 0.162+ at rest, where a `← for agents · ? for shortcuts` hint row sits under +the status line (it disappears while a prompt is typed). So its entry declares +`watchingLines: 4` and matches that row end to end. Both were measured against live panes +rather than read out of a binary, which is the standard for adding a third. `awaitingLine` covers the quiet pane that is neither idle nor watching: a turn that ENDED to wait for workers the CLI will resume from by itself. When background agents or an diff --git a/src/config/cli-registry/stock.ts b/src/config/cli-registry/stock.ts index a235cae3..e5f5fb96 100644 --- a/src/config/cli-registry/stock.ts +++ b/src/config/cli-registry/stock.ts @@ -619,10 +619,15 @@ const CODEX: CliEntry = { // Measured against a live codex-cli 0.154.0 pane on 2026-09-22: the row appears when // the terminal starts, follows the composer down as the conversation grows, and is // gone after `/stop`. + // ⚠️ Codex 0.162.0 (measured 2026-10-09) draws a hint row under the status line at + // rest (` ← for agents · ? for shortcuts`) and drops it while a prompt is typed, so + // the chip is FOURTH from the bottom at rest and third while typing. A three-row + // window never saw it at rest, which is exactly when the idle probe reads it, so a + // session waiting on its terminal read as plainly idle. Four rows cover both. // ⚠️ This entry CANNOT promise what Claude's does, and the difference is Codex's - // layout rather than its pattern. The third row from the bottom is the chip only + // layout rather than its pattern. The fourth row from the bottom is the chip only // while a terminal runs; with none running it is the last row of the transcript, - // which the agent writes. Matching the complete row raises the bar — an assistant + // which the agent writes (and while a prompt is typed, the last two). Matching the complete row raises the bar — an assistant // message has to end with this exact line, to the character — but nothing here makes // forging it impossible, so do not read the Claude comment above as applying here. // What contains it is that codex declares `hooks: 'none'`: no hook event from a codex @@ -641,7 +646,7 @@ const CODEX: CliEntry = { promptGlyph: '›', workingLine: '[Ee]sc to interrupt', watchingLine: String.raw`^\s{0,4}(\d+ background terminals?) running · /ps to view · /stop to close$`, - watchingLines: 3, + watchingLines: 4, }, // The footer under the composer, measured on a live 0.147.0 pane: // ` gpt-5.6-terra default · ~/codeman-cases/th-scratch` (model, reasoning effort, diff --git a/src/config/cli-registry/types.ts b/src/config/cli-registry/types.ts index d17fb919..621edcad 100644 --- a/src/config/cli-registry/types.ts +++ b/src/config/cli-registry/types.ts @@ -365,8 +365,8 @@ export interface CliCapabilities { /** * How many rows at the FOOT of the screen that row can appear in, counting non-blank * rows only. Claude writes its chip on the last row and keeps the default; Codex pins - * its own above the composer, which puts it third from the bottom, so it declares - * more. Keep each number as small as that CLI's layout allows: every extra row is + * its own above the composer, which puts it third or fourth from the bottom (its hint + * row comes and goes), so it declares more. Keep each number as small as that CLI's layout allows: every extra row is * another row an agent might be able to write, and the label is what silences an * alert. See `watchingLabel()` in `session-activity.ts`. */ diff --git a/test/session-watching.test.ts b/test/session-watching.test.ts index dbdbbad7..2f935ba0 100644 --- a/test/session-watching.test.ts +++ b/test/session-watching.test.ts @@ -45,6 +45,33 @@ const CODEX_WITH_TERMINAL = [ CODEX_STATUS, '', ].join('\n'); +/** + * The same with codex-cli 0.162.0 (verbatim, 2026-10-09): a hint row now sits under the + * status line at rest, which pushes the terminal row to FOURTH from the bottom. While a + * prompt is typed the hint goes away and the row is third again. + */ +const CODEX_162_STATUS = ' GPT-6-Luna default · ~/codeman-cases/testcase'; +const CODEX_162_WITH_TERMINAL = [ + '• OK', + '', + ' Worked for 4s • 3:15 AM', + '', + ' 1 background terminal running · /ps to view · /stop to close', + '', + '', + '› Ask Codex to do anything', + '', + CODEX_162_STATUS, + ' ← for agents · ? for shortcuts', + '', +].join('\n'); +const CODEX_162_TYPING = [ + ' Worked for 4s • 3:15 AM', + ' 1 background terminal running · /ps to view · /stop to close', + '› typing probe', + CODEX_162_STATUS, + '', +].join('\n'); const CODEX_STOPPED = [ '• OK', '', @@ -392,6 +419,14 @@ describe('the row Codex draws', () => { expect(CODEX_TAIL).toBeGreaterThanOrEqual(3); }); + it("reads the row on codex 0.162's layout, at rest and while a prompt is typed", () => { + expect(watchingLabel(CODEX_162_WITH_TERMINAL, CODEX_WATCHING, CODEX_TAIL)).toBe('1 background terminal'); + expect(watchingLabel(CODEX_162_TYPING, CODEX_WATCHING, CODEX_TAIL)).toBe('1 background terminal'); + // The hint row is why three rows stopped being enough: at rest, the idle probe's + // moment, a three-row window ends at the composer. + expect(watchingLabel(CODEX_162_WITH_TERMINAL, CODEX_WATCHING, 3)).toBeNull(); + }); + it('refuses a mention that is not the whole row', () => { // The pattern matches Codex's row end to end, so prose about background terminals — // including prose quoting part of the row — is not enough. @@ -406,7 +441,7 @@ describe('the row Codex draws', () => { }); it('CAN be forged by Codex own output, and is contained by Codex having no hooks', () => { - // Codex's row is third from the bottom only while a terminal runs; with none running + // Codex's row is third or fourth from the bottom only while a terminal runs; with none running // that slot is the last row of the transcript, which the agent writes. Matching the // complete row raises the bar but closes nothing, so this test states the limitation // rather than a protection the code does not have.