## What changed
- Add a sign-in wizard behind `features.gcp_setup_wizard`, disabled by default, to collect a project ID, optional location, and optional credential file. Users can leave the credential file blank to use Application Default Credentials.
- Delegate credential validation and configuration persistence to the app-server, showing progress and allowing retries after errors.
- Share editable single-line fields with Bedrock setup and compact the sign-in menu when terminal height is limited.
## Testing
Add onboarding tests and snapshots covering feature gating, field editing, navigation, validation failures, successful configuration persistence, and compact menu rendering.
GitOrigin-RevId: 96eb31e847aa1c2d503176be68ff2e2efe4722fa
## What changed
- Retain mention targets, image paths, and collapsed paste contents when copying or deleting into the register. Pasting creates fresh element identities and image/paste labels.
- Preserve rich register contents across draft clears and composer replacement.
- Capture `Ctrl+Y` register contents for dot-repeat, restore exact mention bindings through undo/redo, and keep pasted rich objects atomic in Replace mode.
## Testing
Add composer tests and snapshots for repeated rich pastes, register handoff, undo/redo, Replace-mode Backspace, and selection replacement. Add a test ensuring register contents are omitted from debug output.
GitOrigin-RevId: d543d21fd542492af49cce01c2a673e6d3d01664
## What changed
- Allow selecting warning text while preserving wrapped URLs and hard line breaks when copying.
- Add mouse-wheel scrolling within the warning body and keep page navigation working after selection.
- Use the shared menu surface and show configured scroll hints only for directions with more content.
- Preserve painted backgrounds when rendering text selections.
## Testing
Add coverage for warning selection without changing the draft, paging after selection, wheel scrolling and directional hints, and selection boundaries in scrolled text containing tabs and wrapped words. Update warning panel snapshots.
GitOrigin-RevId: c4b77277a60b7b4af92043cb3761769ddc636454
## What changed
- Display the leading `/` in the prompt marker instead of the editable text, sharing prefix state with shell mode's `!`.
- Preserve command prefixes and text element offsets across submission, queuing, history, and external editing. Keep prefixes literal in plain-text composers.
- Track composer-owned slash command elements separately, omit them from exported draft elements, and refresh them when command availability changes.
- Let backward deletion at the start of the text remove the prompt prefix while preserving selected-text deletion and Vim Replace recovery.
## Testing
Add regression coverage for slash prompt cursor placement, prefix deletion, history search highlighting, dynamic command availability, and Vim Replace restoration, including Unicode text. Update rendering snapshots for the slash prompt marker.
GitOrigin-RevId: 0da42da8e98bf7885f9b0ba2c8d5ad4f44d6847e
## What changed
Apply `tui.copy_on_select` to composer mouse selections on release, including X11 PRIMARY publication when enabled. Keep editable selections highlighted so typing can replace the selected text, even when `tui.copy_on_select_clear_selection` is enabled.
Share clipboard destination handling across the transcript, footer, and composer. Apply automatic deselection to footer selections after confirmed delivery, and release composer and footer PRIMARY ownership on focus loss or resume. Update configuration descriptions to clarify the behavior across all three surfaces.
## Testing
Add composer tests covering copy on release, retained selection highlights, replacement by typing, PRIMARY ownership lifetime, and clipboard-only status reporting for pending copies.
GitOrigin-RevId: 46999a32170149193fca561741000e97dfc458cf
## Why
`Ctrl+V` previously attempted only image paste, so a text-only clipboard produced an image-paste error. `Shift+Insert` did not use the clipboard paste path.
## What changed
- On Windows, let `Ctrl+V` and `Shift+Insert` paste images first, then read clipboard text asynchronously when no image is available. Keep clipboard access errors distinct from missing images.
- Allow keyboard paste into composer selections and active history or Vim search queries, including inline mode with right-click paste disabled.
- Flush buffered typing before explicit paste to preserve input order. Discard pending clipboard text when the thread or editable target changes, while allowing shortcut releases and repeated paste shortcuts to leave the read pending.
## Testing
Extend shortcut and clipboard-worker tests to cover text fallback, multiline Unicode text, stale-read cancellation, shortcut releases and repeats, and read-only drafts. Add assertions for history-search preview stability and selection changes.
GitOrigin-RevId: 080c1c05a4587e325cea938a6e28c646b9ac5837
## Why
Startup recovery treated a buffered Vim Replace key as an insertion, so the recovered unsent text could differ from the eventual edit. Replacing the first character of `abcd` with `X` should recover `Xbcd`, not `Xabcd`.
## What changed
Preserve the distinction between held typed keys and buffered pastes when building recovery snapshots. Apply Vim Replace semantics to held keys, including mouse selections and the bash-mode prefix offset, without consuming live pending input. Keep buffered pastes literal so the live paste path retains responsibility for large-paste and image classification.
## Testing
Add regression tests for recovery after startup draft handoff and replacement of mouse-selected text with and without the bash-mode prefix. Verify that taking a recovery snapshot leaves live input unchanged and that flushing the held key produces the same text.
GitOrigin-RevId: 97fada635ad9f0f01042b8e96020372d6df9d951
## What changed
Replace the rename field with a single-line `TextArea` that honors configured editor bindings and the composer's Vim setting. Start renaming in insert mode and support Vim Escape recovery on legacy terminals.
Strip carriage returns and newlines from titles and pasted text, keep Vim linewise pastes inline, and scroll horizontally at grapheme boundaries to keep the cursor visible.
## Testing
Add single-line editor coverage for newline filtering, Vim commands, repeat edits, and inline yanks. Extend command-center tests to cover Vim renaming across status-filter changes and cursor placement in narrow layouts.
GitOrigin-RevId: 8d320d6b6de9f77e18292169418383929ca6ceda
## Why
Long drafts need to remain browsable while leaving room for the transcript. Remote image attachments also need to leave an editable prompt row visible.
## What changed
- Cap the fullscreen composer, including padding and hints, at two-thirds of the screen, with a minimum of eight rows when the screen allows.
- Support mouse-wheel browsing without moving the caret or changing transcript selection, search, or activity focus. Show arrows for hidden prompt rows and hide the cursor when the caret is offscreen.
- Resume caret following on editor input, paste, and external edits.
- Keep the selected remote image visible while reserving space for prompt text.
## Testing
Add regression tests and snapshots for fullscreen scrolling, caret restoration after navigation, paste and external edits, remote image navigation and deletion, resizing at scroll boundaries, and disconnected editing.
GitOrigin-RevId: 9a1e4ce14b3b3747e6d136207546327531339258
## Why
Pasting multiple lines into a blockquote previously left subsequent lines unquoted.
## What changed
- Continue the current line's `> ` prefix across pasted lines, including blank and trailing lines, in the TUI composer and embedded answer fields.
- Append two unquoted newlines so typing resumes in the next Markdown block. Preserve quoting when large paste placeholders expand on submission.
- Use a shared edit target for paste context and insertion so selection replacement uses the prefix at the replacement start.
- Keep shell input and provisional startup pastes literal.
## Testing
Add unit tests and rendering snapshots for blockquote pastes, embedded answers, cursor placement, selection replacement, and large-paste expansion. Add textarea tests for forward and backward selections, adjacent elements, and Vim Replace backspace recovery.
GitOrigin-RevId: 525a7951aa16a25d49cc3be98822d0dd0709de97
## Why
Native clipboard setup and writes can block, preventing the TUI from processing input or closing overlays while a copy is in progress.
## What changed
- Route clipboard copies through one session worker that retains native clipboard ownership. Keep terminal escape output on the UI thread.
- Show pending and busy status messages, reject additional copies without queuing them, and ask users to retry image paste after an active copy finishes.
- Abandon setup after five seconds and prevent late delivery. Keep the worker busy until the blocked call returns, and bound shutdown waiting for clipboard handoff.
- Match completions to their originating requests so stale results cannot clear newer selections or unexpectedly resume transcript following. Retain selections on automatic copies, failures, and unconfirmed delivery.
## Testing
Add regression tests for blocked backends, overlay exit, copy and paste ordering, setup expiry, bounded shutdown, completion status messages, and preservation of replaced or moved selections.
GitOrigin-RevId: 4ba1f8da258b9d0700b0edec9ac0ba699f536785
## What changed
Allow right-clicking inside the transcript or composer to copy its selected text using the existing clipboard status messages. Clear the selection only when the right-click copy is confirmed; retain it after failed or unconfirmed copies. Keyboard copies continue to retain composer selections.
Preserve the draft, cursor, and transcript reading position. Refresh composer layout before checking mouse coordinates, and respect modal and transcript input ownership.
## Testing
Add regression tests and snapshots covering copy outcomes, selection retention, reading position, editor bounds after layout changes, and input ownership.
GitOrigin-RevId: 322b303394378a20b2a25b3d218777c9ea65c92b
## What changed
- Support click-to-position, drag selection, double-click word selection, and triple-click logical line selection in the composer, respecting wrapping, scrolling, and atomic grapheme and placeholder boundaries.
- Copy selected draft text through the existing clipboard status flow without changing the draft or selection, before interrupt and exit shortcuts consume the key.
- Replace or delete selected text with editor input, flush buffered typing before mouse edits, and reconcile removed paste and image placeholders.
- Coordinate composer gestures with transcript selections, completion popups, and modals. Use generic retry messages for copy failures.
## Testing
Add coverage for Unicode and wrapped-text hit testing, selection highlighting and editing, multiclick dragging, placeholder cleanup, history navigation, and fullscreen copy and input ownership.
GitOrigin-RevId: 939ef461ec67855b3e87c3c7ddd8a60a3250c7cd
## What changed
- Add incremental, case-insensitive literal search across transcript details, loading older history as needed. Use `F3` to start Find, or `/` in the transcript pager, and navigate matches in either direction. Closing Find restores the previous presentation and reading position.
- Add clickable activity detail controls and `F4` keyboard focus for inspecting individual activity groups in the owned transcript. Preserve expansion state as live activity becomes history.
- Expose configurable `global.find_transcript`, `global.focus_activity`, and `pager.find` bindings under `tui.keymap`. Let new defaults yield to existing custom bindings and show available completions for pending chords.
## Testing
Add regression coverage for Unicode matching, bounded scanning, paginated and changing history, selection during search, composer input isolation, activity controls, and custom shortcut conflicts.
GitOrigin-RevId: 5bcbcdfbca7c5c296c635ec9b079ccd7a908e336
## What changed
- Add Vim Replace mode, entered with `R`, which overwrites graphemes and appends at the end of a line.
- Restore overwritten text with Backspace and record replace edits for undo and dot-repeat.
- Preserve composer behavior for attachments, completions, paste bursts, history previews, and external editor imports while replacing text.
- Expose `vim_normal.enter_replace_mode` in the configurable TUI keymap.
## Testing
- Add coverage for grapheme replacement, Backspace recovery, dot-repeat, custom bindings, atomic attachments, completions, paste handling, and history interactions.
GitOrigin-RevId: cb04e3adcce013c1eb7b82c994b00e944310c481
## Why
Composer drafts include attachments, mention targets, and deferred paste payloads in addition to visible text. Vim undo needs to restore that complete state as a single edit.
## What changed
- Add bounded, draft-level Vim undo history, with `u` as the configurable default binding in normal mode.
- Group complete Vim commands and insert sessions into undo steps, including direct composer changes such as pastes and attachments.
- Preserve undo, repeat, and search state when a reverse-history preview is canceled, and start fresh history when another prompt is accepted.
## Testing
- Cover grouped edits, custom bindings, history and search interactions, attachments, and large paste payloads.
GitOrigin-RevId: 12ecdb3c34a2d66f5d856aa2f82dc15bd91b230b
## What changed
- Start the composer in Vim Insert mode when Vim is enabled and return to
Insert mode after submissions and slash-command dispatch.
- Record the fresh Insert session as a Vim edit so `.` can repeat text entered
in a new draft.
- Keep `/` and `?` as Normal-mode composer searches, and let Backspace cancel
an empty search query and any pending operator without changing the draft.
## Testing
- Add coverage for startup, submitted and queued drafts, inline and goal slash
commands, repeatable edits, and canceled searches.
GitOrigin-RevId: 1a5ee30c44685d2b2a037e46c3ab4ab611024919
## What changed
- Add draft-local forward and backward literal search with `/` and `?`, plus
wrapped repeat navigation with `n` and `N`.
- Support search motions after delete, change, and yank operators, while keeping
queries separate from the draft and skipping atomic elements and partial
grapheme matches.
- Render and edit the query in the composer footer, highlight matches, and add
configurable `tui.keymap.vim_search` bindings to the keymap picker and schema.
## Testing
- Cover navigation, wrapping, operator composition, repeat behavior, Unicode
graphemes, atomic elements, query editing, paste handling, and rendering.
GitOrigin-RevId: 087b080ff8fd74e48456c6b899c07ea5eed38e0c
## What changed
- Add `gg` and `G` motions to jump to the first and last buffer lines.
- Support the motions with delete, change, and yank operators, including dot-repeat for edits.
- Expose normal-mode and operator-motion bindings in the configurable keymap while preserving conflicting user bindings.
## Testing
- Cover buffer jumps, operator combinations, repeat behavior, chord routing, and custom remapping.
GitOrigin-RevId: 24a9178cf7964053aaf9a8cd268c5434dda0778e
## What changed
- Add line-local `f`, `F`, `t`, and `T` motions to Vim normal mode.
- Support the motions with `c`, `d`, and `y`, including dot-repeat for changes.
- Expose separate configurable normal-mode and operator-motion bindings, while preserving existing custom keymaps that use the new defaults.
- Keep character targeting aligned to extended grapheme boundaries and skip embedded composer elements.
## Testing
- Cover forward and backward motion and operator ranges, missing and adjacent targets, cancellation, dot-repeat, custom bindings, shifted terminal key events, grapheme clusters, and embedded elements.
GitOrigin-RevId: 2610cf9a13538d9ae9b890c01417ca25316c1d60
## What changed
- Detect visible HTTP(S) URLs in the composer and attach the complete OSC 8 destination to every wrapped fragment, including when part of the URL is scrolled offscreen.
- Cache hyperlink metadata with the textarea wrap state while leaving masked input and destinations larger than 8 KiB unannotated.
- Make shared hyperlink mapping grapheme-aware, recognize Unicode whitespace boundaries, and scan URLs and trailing delimiters incrementally for large inputs.
## Testing
- Add coverage for wrapped and scrolled URLs, joined emoji, Unicode whitespace, preserved highlighting, masked input, cache invalidation, oversized destinations, and drafts containing many URLs.
GitOrigin-RevId: 40facdf2fe79438c91c82bff2d849c342f1ab28a
## What changed
- Bind `.` in Vim normal mode to repeat the last complete edit.
- Record semantic delete, change, replace, paste, and insert-mode actions so repeats preserve motions, text objects, inserted text, and editor actions across keymap changes.
- Expose `vim_normal.repeat_last_change` in the configurable keymap and keymap picker, including conflict handling for existing custom bindings.
## Testing
- Add coverage for repeating deletes, replacements, complete changes, pasted and literal text, insert-mode editor actions, custom bindings, unavailable motions, and cleared buffers.
GitOrigin-RevId: 3213df964811e7902377ff1d93641e59f4037914
## What changed
Return the initial wrapping ranges directly when the composer input produces a
single line and its byte length is less than the available width. This avoids
the additional grapheme and word-boundary pass for input that cannot wrap.
GitOrigin-RevId: 55d990a354fcc61e9a90d5796b4b39d16742cc50
## What changed
- Add the configurable `vim_normal.replace_char` action, bound to `r` by default, to replace the grapheme under the cursor while remaining in normal mode.
- Support change-operator motions such as `cw`, `c$`, `cj`, and `ck`, plus the repeated `cc` command for changing the current line.
- Let `Esc` cancel a pending replacement before it reaches composer-level handling.
- Preserve existing custom Vim bindings and chord prefixes when introducing the new default.
## Testing
- Cover replacement, grapheme boundaries, remapping and unbinding, change motions, cancellation, keymap conflicts, and keymap picker snapshots.
GitOrigin-RevId: 98feb4eeb57142c37adb73abfe58d1f703b9270d
## Why
Keeping overflowing separators with the following word can add whitespace-only
rows and make composer wrapping differ from the queued-input preview.
## What changed
- Hang breakable whitespace from the preceding visual row at soft word breaks
while preserving the underlying editable text.
- Keep indentation, trailing whitespace, mandatory breaks, and nonbreaking spaces
visible and editable according to their existing semantics.
- Align cursor placement, scrolling, vertical navigation, masked rendering, and
styled overlays with the visible wrapped content, including after resizes.
## Testing
Add focused wrapping, rendering, cursor, editing, scrolling, navigation, Unicode
separator, long whitespace-run, and resize coverage.
GitOrigin-RevId: 7fbdb0a4bf33cfee20c4c19dca5aee74df4f892c
## Why
Overflowing whitespace in the TUI composer could occupy a separate blank row
instead of remaining attached to the text that follows it.
## What changed
- Add composer-specific, grapheme-safe wrapping that keeps breakable Unicode
whitespace with the following word while preserving semantic breakpoints such
as hyphens and nonbreaking spaces.
- Preserve cursor insertion rows and positions as content reflows, including
across full lines and wrapped fragments.
- Keep wrapping linear for maximum-length unbroken input.
## Testing
Add focused rendering and cursor tests for ASCII and Unicode whitespace,
hyphenated words, reflowed fragments, and maximum-length input.
GitOrigin-RevId: fb7713e33bfddf37460b6c2f6f0c9700f31d86bf
## Why
Vim mode currently supports some normal-mode operators and motions, but
common text-object combinations like `ciw`, `daw`, `di(`, and
quote/bracket variants are still missing. That makes the composer feel
incomplete for users who expect operator + text object editing to work
inside prompts.
Closes#21383.
## What Changed
- Add Vim pending-state support for operator/text-object sequences.
- Add `c` as a normal-mode operator for text objects, so combinations
like `ciw` delete the object and enter insert mode.
- Support word, WORD, delimiter, and quote text objects:
- `iw`, `aw`, `iW`, `aW`
- `i(`, `a(`, `i)`, `a)`, `ib`, `ab`
- `i[`, `a[`, `i]`, `a]`
- `i{`, `a{`, `i}`, `a}`, `iB`, `aB`
- `i"`, `a"`, `i'`, `a'`, `i\``, `a\``
- Add configurable keymap entries and keymap picker coverage for the new
Vim text-object context.
- Regenerate the config schema and update keymap picker snapshots.
## How to Test
Manual smoke test:
1. Start Codex with Vim composer mode enabled.
2. Type a draft such as:
```text
alpha beta gamma
call(foo[bar], {"x": "hello world"})
say "one \"two\" three" now
```
3. Put the cursor on `beta`, press `ciw`, and confirm `beta` is removed
and the composer enters insert mode.
4. Escape back to normal mode, put the cursor on `gamma`, press `daw`,
and confirm `gamma` plus surrounding whitespace is removed.
5. Put the cursor inside `foo[bar]`, press `di[`, and confirm only `bar`
is removed.
6. Put the cursor inside `call(...)`, press `da(`, and confirm the whole
parenthesized section is removed.
7. Put the cursor inside the quoted text, press `ci"`, and confirm the
quote contents are removed and insert mode starts.
8. Verify cancellation does not edit text: press `d` then `Esc`, and
press `d` then `i` then `Esc`.
Targeted tests:
- `cargo test -p codex-tui --lib vim_`
- `cargo nextest run -p codex-tui keymap_setup::tests`
Additional local checks:
- `just write-config-schema`
- `just fmt`
- `just fix -p codex-tui`
- `git diff --check`
- `cargo insta pending-snapshots --manifest-path tui/Cargo.toml`
Local full-suite note: `just test -p codex-tui` ran to completion. The
keymap snapshot failures were expected and accepted. Two unrelated
guardian feature-flag tests still fail locally:
-
`app::tests::update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
-
`app::tests::update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`
`just argument-comment-lint` is currently blocked locally by Bazel
analysis before the lint runs because `compiler-rt` has an empty
`include/sanitizer/*.h` glob in the local Bazel cache. The touched Rust
diff was manually inspected for opaque positional literals.