From 7c3c5b8f72971fa89e11c32682b491e52ced9936 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Mon, 14 Sep 2026 23:29:42 +0200 Subject: [PATCH] fix(mobile): show the Codex shift-arrow keys only on codex sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two keys #408 adds to the mobile keyboard accessory bar send Shift+Left and Shift+Right, which are Codex bindings (edit the last queued message, step back through the prompt stack). They shipped on both agent layouts, so a claude, pi, grok, omp, deepseek or gemini session got two keys that do nothing. That was not only cosmetic: a tap goes through sendNavKey(), which adds the session to _echoPassthroughSessions and hands editing to plain PTY echo until Enter or Ctrl+C, so on a phone a dead key also switched off the local echo that makes typing feel instant there. The reveal now follows the shape the 🧠 key already uses. The buttons stay in both templates, carry an accessory-btn-codex marker class, and are display:none in styles.css until the bar element carries codex-enabled. The class has to live on the bar rather than on the keys because setMode() rebuilds the buttons' innerHTML on every layout switch. syncCodexKeys() toggles it from the active session's mode (the same lookup _isShellSession() uses) and is called at init and from refreshForActiveSession(), which selectSession() already invokes on every switch. A session's mode is readonly on the server and fixed at create, so no other event can change the answer; the welcome screen (no active session) reads as not codex and hides the keys. The frontend id-branching guard (test/cli-registry-no-id-branching.test.ts) scans only src/**/*.ts, so the mode comparison in a public JS file is in bounds, the same as the existing shell check beside it. Tests: the new describe block in test/mobile-shell-keyboard.test.ts pins the marker class in both templates, the CSS pair, the class for a codex session in both layouts, its absence for claude/shell/pi/omp/deepseek, the re-sync in both directions on a session switch, the no-session case, and the init + refresh wiring. All six positive assertions fail without the source change. README and the changeset now say the keys are Codex-only. Co-Authored-By: Claude Fable 5.1 --- .changeset/tidy-codex-shift-arrows.md | 2 +- README.md | 2 +- src/web/public/keyboard-accessory.js | 37 +++++++++++--- src/web/public/styles.css | 12 +++++ test/mobile-shell-keyboard.test.ts | 72 +++++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 8 deletions(-) diff --git a/.changeset/tidy-codex-shift-arrows.md b/.changeset/tidy-codex-shift-arrows.md index a46d4fce..ff430edf 100644 --- a/.changeset/tidy-codex-shift-arrows.md +++ b/.changeset/tidy-codex-shift-arrows.md @@ -2,4 +2,4 @@ "aicodeman": patch --- -Add Shift+Left and Shift+Right buttons to the default and extended mobile agent keyboard bars, enabling Codex queued-message editing and prompt-stack navigation. Flush locally buffered drafts before navigation and keep terminal focus after taps. +Add Shift+Left and Shift+Right buttons to the default and extended mobile agent keyboard bars, shown only on Codex sessions, enabling Codex queued-message editing and prompt-stack navigation. Flush locally buffered drafts before navigation and keep terminal focus after taps. diff --git a/README.md b/README.md index e53c540f..27ba7db2 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,7 @@ The most responsive AI coding agent experience on any phone. Full xterm.js termi Password typing on phoneQR code scan β€” instant auth -- **Keyboard accessory bar** β€” `⇧←` / `⇧→` send Shift+Left / Shift+Right in both default and extended agent layouts (Codex defaults: edit the last queued message / return through the prompt stack); `/init`, `/clear`, `/compact` quick-action buttons above the virtual keyboard; destructive commands require a double-press to confirm, so you never fire one by accident +- **Keyboard accessory bar** β€” `/init`, `/clear`, `/compact` quick-action buttons above the virtual keyboard; destructive commands require a double-press to confirm, so you never fire one by accident; on Codex sessions the bar also shows `⇧←` / `⇧→` (Shift+Left / Shift+Right: edit the last queued message / return through the prompt stack) - **Dedicated Enter button** β€” replays the keypress through the terminal, so text buffered by local echo is flushed first rather than stranded - **Swipe navigation & smart keyboard handling** β€” swipe left/right to switch sessions; toolbar and terminal shift up when the keyboard opens (`visualViewport` API) - **Built for phones** β€” safe-area insets for notch and home indicator, 44px touch targets, bottom-sheet case picker, native momentum scrolling diff --git a/src/web/public/keyboard-accessory.js b/src/web/public/keyboard-accessory.js index 4215cd35..9e954ff5 100644 --- a/src/web/public/keyboard-accessory.js +++ b/src/web/public/keyboard-accessory.js @@ -4,8 +4,10 @@ * Defines three exports: * * - KeyboardAccessoryBar (singleton object) β€” Quick action buttons shown above the virtual - * keyboard on mobile: arrow up/down, /init, Tab, Shift+Left/Right, paste, Esc, and dismiss (the extended - * bar adds /clear, /compact, Shift+Tab and more). Tab flushes any locally-buffered + * keyboard on mobile: arrow up/down, /init, Tab, paste, Esc, and dismiss (the extended + * bar adds /clear, /compact, Shift+Tab and more). Shift+Left/Right ship in both agent + * layouts but are revealed only on Codex sessions (`codex-enabled` marker class on the + * bar, synced on every session switch), since they are Codex bindings. Tab flushes any locally-buffered * prompt text to the PTY before sending \t, so completion applies to what was typed. * The paste button opens a dialog that handles both text paste and image attach * (native picker + best-effort image paste, routed through app._uploadAndInsertImages). @@ -661,8 +663,8 @@ const KeyboardAccessoryBar = { - - + +