mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-10 01:09:43 +02:00
fix(gemini): read Gemini CLI's composer bar and spinner line so a turn can end
A gemini session stayed "working" for good after its first turn. Its braille spinner trips the generic SPINNER_PATTERN and marks the pane working, but only a composer glyph arms the idle confirmation and gemini declared none, so it fell back to Claude's `❯`, which gemini never draws. Measured on live Gemini CLI 0.63.0 panes (capture-pane every 300 ms through real turns with a shell call at 40, 120 and 200 columns, YOLO and default approval mode, plus the raw PTY stream). The turns ran against a local stand-in for the Gemini API (GOOGLE_GEMINI_BASE_URL, which Codeman's custom endpoint support already sets), since the CLI's TUI does not depend on the backend and no account is needed for it: - The TUI repaints its whole bottom region every frame, composer included, and the composer sits between a `▄` bar and a `▀` bar; the submitted prompt is echoed between the same bars. The `▀` bar arms the idle check: every repaint carries it, tmux's reattach repaint too. The composer's prompt character is no good: it follows the approval mode (`*` in YOLO), and its `>` also starts the echoed prompt, which would make the submit verifier read a submitted prompt as stranded and press Enter again. - While a turn runs a line `⠦ Thinking... (esc to cancel, 6s)` animates about every 80 ms (largest gap mid-turn: 214 ms). The label can be any loading phrase, so the working line is the `(esc to cancel, <n>` suffix, or a spinner frame opening a line for when a long phrase wraps that suffix. Nothing at rest matches either. - A tool confirmation (default mode) replaces the composer, stops the spinner and the pane goes silent (3.9 s gap), so it reads as idle. Verified on an isolated instance from this branch: a YOLO turn emitted one session:working (+170 ms) and one session:idle (2.5 s after the last output); a default-mode turn went working -> idle while the confirmation waited -> working once allowed -> idle at the end; after a server restart four restored gemini panes went busy -> idle in about 4 s; a fresh launch settled in 3 s. The launch-settle and uncharacterised-CLI tests that used gemini as their example of a CLI without work detection now use grok and deepseek. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -266,7 +266,7 @@ Scoping needs no check of its own here: `setPaneExit()` already forces `paneExit
|
||||
|
||||
So: `_confirmIdle()` (session.ts) requires the pane to go quiet, and then asks the SCREEN via `capturePaneText()` + `CLAUDE_WORKING_LINE_PATTERN` before believing it; a sustained run of repaints (`session-activity.ts`, pure + unit tested) is what marks a turn as started, with the same screen probe vetoing keystroke echo. Idle now lands ~3-5s after a turn ends instead of 2s into one.
|
||||
|
||||
⚠️ **The composer glyph and the working line are per-CLI registry DATA** (`capabilities.workDetect`, #385), not Claude constants: claude declares `❯` plus the pattern above, codex declares `›` plus `[Ee]sc to interrupt`, pi declares its composer rule `─` plus the spinner it embeds there, opencode declares its composer bar `┃` plus its 8-cell footer spinner `[⬝■]{8}`, omp declares its input row `╰─` plus the spinner and elapsed time that replace the `π` in its status bar, and a CLI that declares neither falls back to Claude's pair, which is what every session used before the registry carried one. Before that, this whole mechanism was gated Claude-mode-only on the reasoning that an external CLI has no `❯`, which was true and still left every Codex session reporting `idle` for its entire life.
|
||||
⚠️ **The composer glyph and the working line are per-CLI registry DATA** (`capabilities.workDetect`, #385), not Claude constants: claude declares `❯` plus the pattern above, codex declares `›` plus `[Ee]sc to interrupt`, pi declares its composer rule `─` plus the spinner it embeds there, opencode declares its composer bar `┃` plus its 8-cell footer spinner `[⬝■]{8}`, omp declares its input row `╰─` plus the spinner and elapsed time that replace the `π` in its status bar, gemini declares its composer's bottom bar `▀` plus its `(esc to cancel, <n>s)` spinner line, and a CLI that declares neither falls back to Claude's pair, which is what every session used before the registry carried one. Before that, this whole mechanism was gated Claude-mode-only on the reasoning that an external CLI has no `❯`, which was true and still left every Codex session reporting `idle` for its entire life.
|
||||
|
||||
⚠️ `workingLine` is config-supplied (a user `clis.json` can set it) and the compiled pattern runs on the PTY hot path, so it goes through `compileVersionRegex()` in BOTH the schema refine and `_workingLinePattern()`: a nested quantifier there is a ReDoS against the event loop, and the helper returns null rather than throwing so the fallback is structural.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user