mirror of
https://github.com/openai/codex.git
synced 2026-11-01 08:16:54 +00:00
c0ea3c4d0a2fb99a0f5978bfa7d2bbab467d7a77
755
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9993fb838a |
Improve Responses WebSocket timing telemetry (#32256)
## What changed - Emit `responsesapi.websocket_timing` payloads as opt-in trace events with request context, while excluding them from diagnostic uploads and persisted logs by default. - Preserve fractional-millisecond TBT values in telemetry histograms and runtime summaries, rounding only when formatting the TUI label. ## Testing - Cover timing-log filtering, fractional TBT collection and display, and existing whole-millisecond duration behavior. GitOrigin-RevId: 5f0a1c60c237abed17cc8b2d569ca77fbbc6ec41 |
||
|
|
f46b53bd85 |
fix(tui): hide empty reasoning summaries (#31652)
## Why Reasoning summaries can contain an empty HTML comment placeholder, `<!-- -->`, when a generated summary part has no prose. The TUI treated that placeholder as visible summary content, so it leaked into both the completed conversation history and persisted transcript. Multi-part empty summaries could also leave later generated status headings visible as orphaned transcript content. ## What - Strip the empty reasoning-summary placeholder at the shared `ReasoningSummaryCell` boundary. - Suppress the cell when removing placeholders leaves only generated bold status headings. - Cover the multi-part placeholder-only shape with a rendering regression test for both normal history and transcript output. ## How to Test 1. Start Codex TUI with reasoning summaries visible, for example with `hide_agent_reasoning = false` and `model_reasoning_summary = "detailed"`. 2. Run a turn that receives an empty generated reasoning-summary part. 3. Confirm that the in-progress status heading may appear while the turn is running, but the completed history and transcript contain neither literal `<!-- -->` tokens nor orphaned reasoning headings. 4. Confirm that a reasoning summary with actual prose still renders normally. The model output is nondeterministic, so the targeted regression covers the exact multi-part placeholder shape from the report: - `just test -p codex-tui reasoning_summary_block_hides_empty_html_comment_parts` |
||
|
|
d7ab20ce62 |
[codex-cli] Show reset details in redemption picker (#30488)
## Why Users can see that usage-limit reset credits are available, but not which credits they have, when each one expires, or which credit will be consumed. The TUI should use the supported rate-limit RPC for that information without maintaining a second reset-credit request path. ## What changed - load reset-credit details through the existing `account/rateLimits/read` refresh when the user opens **Redeem usage limit reset** - show available credits sorted by expiry, using the backend title when present and a scope-based fallback otherwise - consume the exact selected credit and preserve its idempotency key across retries - fall back to the existing generic reset action when the RPC returns a positive count without detail rows - remove the dedicated list-RPC event, request, response-combining, and TUI state plumbing - handle a selected credit becoming unavailable without incorrectly caching the user's total count as zero - handle forward-compatible unknown reset types with the existing scope-based fallback label ## TUI preview Rendered from the final standard-width and narrow `insta` snapshots in this PR. <img width="1280" height="570" alt="pr30488-reset-picker-preview" src="https://github.com/user-attachments/assets/8b84cd33-cb35-4a37-aaed-dbd6b62bff51" /> ## Validation - `just test -p codex-tui chatwidget::tests::usage` (32 passed) - `just fix -p codex-tui` - no pending `insta` snapshots Uses the reset-credit details added by #30395. Fixes #29618. |
||
|
|
6801941cfe | TUI support for buffer experience (#29919) | ||
|
|
e639e8c4bd |
connectors: own app metadata types (#29723)
## Why Connector metadata is consumed by connector discovery, ChatGPT integration, core, and TUI code. Treating app-server's wire DTO as the shared domain model reverses the intended dependency direction. ## What changed - Added connector-owned app branding, review, screenshot, metadata, and info types. - Added explicit conversions in app-server and TUI while preserving app-server's wire payloads. - Removed production app-server-protocol dependencies from connectors and ChatGPT connector code. ## Stack This is PR 4 of 6, stacked on [PR #29722](https://github.com/openai/codex/pull/29722). Review only the delta from `codex/split-config-layer-types`. Next: [PR #29724](https://github.com/openai/codex/pull/29724). ## Validation - Connector and tools coverage passed. - App-server app-list coverage passed: 13 tests. |
||
|
|
1d65ccabd5 |
config: own layer provenance types (#29722)
## Why Config layer provenance describes how effective configuration was assembled, so it belongs with the config loader rather than in app-server's serialized API types. ## What changed - Moved `ConfigLayerSource`, `ConfigLayerMetadata`, and `ConfigLayer` ownership into `codex-config`. - Kept app-server's wire payloads unchanged and added explicit conversions at the app boundary. - Removed lower-level app-server-protocol dependencies from config consumers. ## Stack This is PR 3 of 6, stacked on [PR #29721](https://github.com/openai/codex/pull/29721). Review only the delta from `codex/split-auth-domain-types`. Next: [PR #29723](https://github.com/openai/codex/pull/29723). ## Validation - `codex-config` coverage passed. - App-server config-manager and config RPC coverage passed. |
||
|
|
5c0fbf3492 |
[codex] Fix usage-limit reset copy and state (#28793)
## Why The reset flow introduced in #28154 still describes earned reset credits as "rate-limit resets" and uses generic reset-scope copy. It can also retain a stale available-credit count after redemption or an account change, leaving the reset action enabled after the last credit is used. This follow-up updates terminology only within that reset feature. Existing rate-limit wording elsewhere in the CLI and TUI is unchanged. ## What changed - Rename reset-specific `/usage` menu items, startup hints, and reset dialogs to "usage limit reset." - Describe monthly resets for Free, Go, and accounts that report a monthly usage window; otherwise describe the current 5-hour and weekly limits. - Recheck a cached zero balance when `/usage` is reopened, and refresh the balance after redemption so the final reset immediately disables the action. - Correlate async refresh results before updating snapshots and clear account-derived reset state, warnings, prompts, and status surfaces when the account changes. ## Validation - `just test -p codex-tui chatwidget::tests::usage` — 29 passed. - `just test -p codex-tui chatwidget::tests::status_command_tests` — 7 passed. - Account-boundary prompt and plan-mode prompt regression tests passed. - `cargo insta pending-snapshots` from `codex-rs/tui` — no pending snapshots.\ <img width="814" height="318" alt="image" src="https://github.com/user-attachments/assets/2a460e96-458b-4805-8d9f-c759382d21a4" /> view for monthly <img width="905" height="243" alt="image" src="https://github.com/user-attachments/assets/179f88e3-08fb-4af5-8dc6-ce6a944ed681" /> |
||
|
|
21d36296f1 |
Add workspace messages app-server API (#29001)
## Summary - Add backend-client types and fetch support for active workspace messages. - Add the app-server v2 `account/workspaceMessages/read` method, generated schemas, and README documentation. - Delegate workspace-message eligibility to the Codex backend feature gate; map a backend 404 to `featureEnabled: false`. ## Testing - `just write-app-server-schema` - `just test -p codex-backend-client` - `just test -p codex-app-server-protocol` - `just test -p codex-app-server workspace_messages` - `just fix -p codex-backend-client -p codex-app-server-protocol -p codex-app-server` - `just fmt` ## Stack - Base PR for #28232, which adds the TUI status-line integration. |
||
|
|
dce673905a |
core: load AGENTS.md from foreign environments (#28958)
## Why Make it possible to load AGENTS.md from remote exec-servers whose OS is different than app-server. ## What - keep `AGENTS.md` discovery and provenance as `PathUri`, with root-aware parent and ancestor traversal - expose lifecycle instruction sources as legacy app-server path strings in events while retaining `PathUri` internally - preserve and test mixed POSIX and Windows paths in model context and TUI status output - cover remote Windows loading end to end by seeding the Wine prefix through host filesystem APIs - fix bug in `PathUri`'s parent() implementation that would erase Windows drive letters |
||
|
|
3931bc2bde |
unified-exec: retain PathUri in command events (#28780)
## Why App-server must report command events containing foreign-platform paths without changing existing client or rollout path-string formats. ## What changed - retain `PathUri` through exec command begin/end events - convert cwd values to `LegacyAppPathString` at the app-server compatibility boundary - drop command actions with foreign paths and log them - serialize rollout-trace cwd values using their inferred native path representation - restore Wine coverage for retained Windows cwd values and successful completion |
||
|
|
b668abb488 |
Extract TUI plugin catalog rendering (#28768)
This mechanically extracts the existing TUI plugin catalog and detail popup rendering from `chatwidget/plugins.rs` into a new `chatwidget/plugin_catalog.rs` module. `plugins.rs` now keeps the stateful plugin workflow and orchestration, while `plugin_catalog.rs` owns the presentation-heavy catalog/detail popup construction and its pure helpers. The goal is to keep `plugins.rs` focused before later plugin sharing work adds more catalog behavior. - Moves existing catalog/detail popup builders and related pure helpers into `plugin_catalog.rs` - Leaves plugin fetch/state/key handling in `plugins.rs` - Adds only minimal sibling-module visibility/import wiring - Intentionally makes no product behavior or UI changes beyond the code move |
||
|
|
1391d786bc |
Scope command approvals by execution environment (#28738)
## Why Command approval cache keys included the command and working directory, but not the execution environment. An approval for `/workspace` locally could therefore be reused for the same command and path on an executor. ## What changed - Include the selected environment ID in shell and unified-exec approval cache keys. - Carry that ID through the normal command approval request so clients can show which environment is being approved. - Expose the environment through app-server as a required nullable `environmentId` and show it in the inline TUI approval prompt. - Keep older recorded approval events compatible when the environment is absent. For example, `echo ok` in local `/workspace` and `echo ok` in executor `/workspace` now produce different approval keys and separate prompts. ## Scope This PR does not change network approvals, Guardian review actions, MCP elicitation, full-screen TUI rendering, or environment-ID validation. Remote `shell_command` execution itself remains in #28722; this PR only makes its approval key environment-aware. |
||
|
|
f8f5a6e78f |
feat(tui): add rate-limit reset redemption to /usage (#28154)
## Why Codex users can earn personal rate-limit reset credits, but the CLI does not currently provide a way to view or redeem them. The `/usage` command restored in #27925 is intended to be the entry point for usage-related actions, so reset redemption belongs there rather than in a separate dashed slash command. Depends on #28143 for the app-server and backend-client reset-credit APIs. ## What changed - Turn bare `/usage` into a menu with entries for token activity and earned rate-limit resets while preserving `/usage daily`, `/usage weekly`, and `/usage cumulative`. - Add loading, empty, confirmation, success, retry, and error states with a caller-generated UUID idempotency key reused across retries of the same logical reset. - Show an availability hint only for backend-classified rate-limit errors with credits available. - Hide the reset entry for workspace accounts. ## Validation - `just test -p codex-tui chatwidget::tests::usage` — 19 passed. - `just fix -p codex-tui` — passed. - `just fmt` — passed. - `cargo insta pending-snapshots` from `codex-rs/tui` — no pending snapshots. ## Examples <img width="1168" height="304" alt="image" src="https://github.com/user-attachments/assets/caa4c1e3-e996-494d-ae17-50b521f5dce8" /> <img width="908" height="260" alt="image" src="https://github.com/user-attachments/assets/e38a726b-77cc-4bd0-9ea8-9f3ad21c5768" /> ### Reset flow <img width="1509" height="312" alt="image" src="https://github.com/user-attachments/assets/d987013c-78a5-48a2-ad8d-c61ad267a327" /> <img width="585" height="190" alt="image" src="https://github.com/user-attachments/assets/de32be19-79b9-4a3e-8574-6f1c208c98ae" /> <img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/88a165cf-796d-4fdc-a7bc-ea89917573da" /> <img width="512" height="193" alt="image" src="https://github.com/user-attachments/assets/d2353998-5aa8-442e-a5f8-3a8a5b832753" /> |
||
|
|
ecfe174d5f |
Use ApiPathString in app-server filesystem permission paths (#28367)
## Why Clients running an app-server on one OS and an exec-server on another OS need to be able to pass sandbox config to app-server that refers to resources on the executor's foreign OS. ## What `AbsolutePathBuf` can't represent these paths and we don't want users to be exposed to `PathUri` yet, so this moves the public app-server API to be expressed in terms of `ApiPathString`. Stacked on #28165. - change app-server v2 filesystem permission paths, including legacy read/write roots, to `ApiPathString` - localize API paths through `PathUri` when converting into the current native core permission types - make path-bearing permission conversions fallible and surface localization failures instead of silently treating malformed grants as ordinary denials - propagate conversion failures through app-server and TUI approval handling - regenerate the app-server JSON and TypeScript schemas - leave migration TODOs on native-path conversions so they can be removed once core permission paths use `PathUri` |
||
|
|
29224d945b |
TUI Plugin Sharing 2 - add remote plugin section plumbing (#26702)
This adds the background plumbing for remote-backed plugin catalog sections while leaving the fuller directory presentation to the next PR. The TUI can fetch section-specific remote marketplace results, keep local plugin data available, and carry section errors forward for later rendering. - Fetches explicit remote marketplace kinds for curated, workspace, and shared-with-me sections. - Gates shared-with-me loading on the plugin sharing feature flag. - Adds section-level error state and user-actionable error copy. - Merges remote marketplace results into the cached plugin list without discarding local results. |
||
|
|
8a6a039f26 |
Remove terminal resize reflow flag gates (#27794)
## Why `terminal_resize_reflow` is now stable and should behave as always on. Keeping the disabled runtime paths around made the feature look configurable even though the rollout is complete, and old config could still suggest there was a supported off mode. ## What Changed - Marked `terminal_resize_reflow` as `Stage::Removed` while keeping it default-enabled for compatibility. - Ignored `[features].terminal_resize_reflow` config entries so stale `false` settings no longer affect the effective feature set. - Removed TUI branches that depended on the flag being disabled, so draw, replay buffering, stream finalization, and resize scheduling all assume resize reflow is active. - Simplified resize smoke coverage to exercise the always-on behavior only. ## Verification - `just test -p codex-features` - `just test -p codex-tui resize_reflow` - `just test -p codex-tui initial_replay_buffer thread_switch_replay_buffer` |
||
|
|
c884536d84 |
feat(tui): reland token activity command (#27925)
## Why [#25345](https://github.com/openai/codex/pull/25345) was approved, green, and squash-merged into its stacked base branch, `fcoury/tokenmaxxing-api`. Four minutes later, that base branch was force-pushed back to an API-only rebased head while preparing [#25344](https://github.com/openai/codex/pull/25344) for `main`. As a result, the squash commit from #25345 was orphaned and the TUI command never reached `main` or a release. This PR relands the orphaned TUI change from [`411410b8`](https://github.com/openai/codex/commit/411410b85c2d8eb050d441f17396c5c4048d866f) on current `main`. ## What changed - Add `/usage`, `/usage daily`, `/usage weekly`, and `/usage cumulative` for account token activity. - Fetch account usage asynchronously through the existing `account/usage/read` app-server RPC. - Render daily, weekly, and cumulative activity with theme-aware terminal palettes and bounded transient cards. - Preserve transcript ordering while assistant streams, history consolidations, active cells, and hooks complete. - Hide `/usage` from completion when backend auth is unavailable while keeping typed-command guidance. - Carry current-main behavior forward for cwd-aware Markdown parsing, Windows Terminal color detection, and personal access token auth. - Clear pending usage cards on thread rollback and delay completed cards until live hook output is committed. - Add focused regression and snapshot coverage for loading, auth errors, invalid views, rollback, hook ordering, layout, and charts. ## Prior review The original implementation was approved by Eric Traut in #25345 after testing multiple themes and light/dark terminals. This PR preserves that reviewed implementation while adapting it to current `main` and adding regression coverage for newer rollback and hook lifecycle behavior. ## Validation - `just test -p codex-tui token_activity palette renderable usage_command` — 37 passed. - Focused rollback, hook-ordering, and error snapshot tests — 4 passed. - `just fix -p codex-tui` — passed. - `UV_CACHE_DIR=/private/tmp/codex-uv-cache just fmt` — passed. - `cargo insta pending-snapshots` — no pending snapshots. - `just test -p codex-tui` — 2,870 passed; two unrelated guardian feature-flag tests failed because their expected `OverrideTurnContext` event was absent: - `update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history` - `update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default` - `just argument-comment-lint` could not complete because the local Bazel LLVM `compiler-rt` repository is missing `include/sanitizer/*.h`. The touched Rust diff was manually inspected and no missing opaque-literal argument comments were found. |
||
|
|
576f603440 |
Remove TUI realtime voice support (#27801)
## Why Removes the realtime audio support from TUI. ## What Changed - Removed the TUI `/realtime` and realtime `/settings` command paths. - Deleted TUI voice capture/playback, WebRTC session handling, audio-device selection UI, and recording-meter code. - Removed TUI realtime tests and snapshots that covered the deleted surfaces. - Dropped the TUI-only `cpal` and `codex-realtime-webrtc` dependencies and refreshed the Rust/Bazel locks. |
||
|
|
78bab04116 |
[1 of 3] Support long raw TUI goal objectives (#27508)
## Stack 1. **[1 of 3] Support long raw TUI goal objectives** - this PR 2. [2 of 3] Support long pasted text in TUI goals - #27509 3. [3 of 3] Support images in TUI goals - #27510 ## Why `thread/goal/set` limits persisted objective text to 4000 characters. The TUI used to reject raw `/goal` objectives above that limit, even though the client can make them usable by writing the long text to a file and storing a short objective that points at that file. This also needs to work for remote app-server sessions: filesystem API calls must create files on the app-server host, and the stored path must be meaningful to the agent on that host. ## What Changed - Adds an app-server-host path helper so TUI code can build paths that are resolved on the app-server host rather than the TUI host. - Adds TUI app-server session helpers for `fs/createDirectory`, `fs/writeFile`, `fs/readFile`, and `fs/remove` that work for embedded and remote app-server sessions without changing the app-server protocol. - Materializes oversized raw `/goal` objectives into `$CODEX_HOME/attachments/<uuid>/goal-objective.md` through the app-server filesystem APIs, then stores a short, readable objective that directs the agent to that file. - Reads managed objective files back for `/goal edit`. Other goal UI renders the readable stored objective normally, without managed-file-specific presentation logic. - Recognizes managed references only when they name the expected generated file under the app server's reported `$CODEX_HOME`, and cleans up newly materialized files when goal replacement or setting does not complete. ## Verification - Added/updated TUI tests for raw oversized `/goal` submission, large inline-paste expansion, queued oversized goals, app-facing materialization before `thread/goal/set`, managed-path validation, editing, and cleanup. - Added/updated app-server-client remote coverage for initialized remote Codex home handling. ## Manual Testing - Ran the real TUI against a Unix-socket app server with different local and server `$CODEX_HOME` directories. Oversized goals wrote only under the server home, and persisted references used the server-canonical path rather than the TUI path. - Exercised 3,999-, 4,000-, and 4,001-character raw objectives. The first two stayed inline without new files; the 4,001-character objective became a managed objective file. - Submitted a larger 8,275-character objective, verified its full contents on the app-server host, and observed the goal continuation open the referenced server-side file. - Opened `/goal edit` for a managed objective and verified the full text was restored through remote `fs/readFile`. - Submitted an oversized replacement while a goal was active, verified no file was written before confirmation, then canceled and confirmed that the existing goal and attachment count were unchanged. |
||
|
|
1e5b87b4d7 |
Remove TUI legacy Windows sandbox dependency (#27490)
## Why This is part of an ongoing attempt to eliminate the TUI's direct dependency on core features. When we moved the TUI to the app server, we left a `legacy_core` shim that re-exported some remaining core symbols for the TUI. The intent was to eventually remove all of these. In this PR, we remove the symbols related to the Windows sandbox. The change should be behavior-neutral and low risk because it's just refactoring and removal of code that is now effectively dead. When working on this PR, I noticed a big existing problem that affects mixed-platform remoting. For example, if you run the TUI on a Linux box and remote into a Windows box, the TUI logic doesn't properly handle Windows sandbox setup properly. Fixing this is beyond the scope of this PR, but I've left a TODO comment in place so we don't forget. ## What changed - Move the remaining TUI-specific sandbox level, setup, telemetry, and read-root helpers into `codex-tui`, calling `codex-windows-sandbox` directly. - Remove the Windows sandbox namespace and read-root grant re-exports from the client-side `legacy_core` facade. - Remove the dormant pre-elevation prompt fallback guarded by the permanently enabled `ELEVATED_SANDBOX_NUX_ENABLED` switch. The reachable elevated and non-elevated setup flows remain unchanged. |
||
|
|
36fc79c6f4 |
Remove TUI legacy core test_support dependencies (#27484)
## Why The TUI now sits on the app-server layer, but `app-server-client::legacy_core` still exposed core test helpers solely for TUI tests. We've been whittling away the remaining dependencies. This is the next step on that journey. There is no functional change — just a refactor, and this affects only test code, so it should be low risk. ## What changed - remove the `legacy_core::test_support` re-export and call model-manager test helpers directly - keep the bundled model-preset cache local to TUI test support - import constraint types directly from `codex-config` |
||
|
|
8e69d29521 |
Reduce TUI legacy core dependencies (#26711)
## Why The TUI still reached through `app-server-client::legacy_core` for thread-name normalization and project-instruction filename details. In particular, checking the TUI's local filesystem for `/init` is incorrect for remote app-server sessions, where the server owns the working directory and instruction discovery. ## What changed - use the instruction source paths supplied by the app server to decide whether `/init` should avoid overwriting project instructions - keep the small thread-name normalization helper local to the TUI - remove the now-unused instruction filename constants, utility module, and other unused `legacy_core` re-exports - make status helper tests independent of concrete instruction filenames ## Verification - `just test -p codex-app-server-client` - `just test -p codex-tui slash_init_skips_when_project_instructions_are_loaded` - `just test -p codex-tui` ran 2,799 tests; 2,797 passed and two unrelated guardian feature-flag tests failed reproducibly in untouched code ### Manual test Started an app server over WebSocket with a remote workspace containing `AGENTS.md`, then connected the TUI using `--remote`. After confirming `thread/start` returned the file in `instructionSources`, deleted `AGENTS.md` and ran `/init` in the existing session. The TUI still reported that project instructions already existed and skipped `/init`. The trace contained no `turn/start` request, confirming the decision came from app-server session state rather than a new client-local filesystem check. |
||
|
|
9de568372d |
Propagate permission approval environment id (#25862)
## Stack 1. #25850 - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. #25858 - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. This PR (#25862) - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. #25867 - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. This PR is stacked on #25858, and #25867 is stacked on this PR. ## Why PR2 lets the model bind a `request_permissions` call to a selected environment, but the approval event and client-facing request still needed to carry that binding. For CCA, the user-facing prompt and delegated approval path should know which environment the grant applies to instead of relying on cwd alone. ## What Changed - Added optional `environmentId` to `RequestPermissionsEvent`. - Emit the selected environment id from core permission approval events. - Preserve the environment id through delegate forwarding, including cwd-based delegated requests. - Added `environmentId` to app-server permission approval params, generated schema/TypeScript artifacts, and README examples. - Preserve and display the environment id in TUI permission approval prompts. - Updated focused core, app-server protocol, and TUI conversion coverage. ## Testing Not run locally per instruction. Performed read-only `git diff --check`. |
||
|
|
c0ea566bb5 |
feat(tui): restore output-free cancelled prompts (#25316)
## TL;DR When you press Esc or Ctrl+C after sending a prompt but before any output was rendering, it restores the last composer and the message. ## Summary Cancelling a prompt immediately after submission should behave like returning to edit that prompt, not like discarding the user's draft. Today, pressing `Esc` or `Ctrl+C` before Codex responds leaves the submitted prompt in the transcript and returns an empty composer, forcing the user to recall or retype it. When an interrupted turn has not produced substantive visible output, restore its submitted prompt directly into the composer and roll back that latest turn. This also covers the first prompt in a fresh thread, before the TUI has retained a local user-history cell. The restored draft keeps its text, image attachments, and active collaboration mode so it can be edited and resubmitted in place. Restoration is intentionally suppressed once the turn has produced user-visible activity such as assistant output, tool work, hooks, or patches. A transient thinking status does not make the prompt ineligible. Rollback also rebuilds terminal scrollback from the retained transcript cells so repeated cancellations and terminal resizes do not duplicate history. ## How to Test 1. Start the TUI with `cargo run -p codex-cli --bin codex`. 2. In a fresh thread, submit the first prompt and press `Esc` before Codex emits substantive output. Confirm that the prompt returns to the composer for editing and its submitted transcript row is removed. 3. Repeat with `Ctrl+C`, then repeat after at least one completed turn. Confirm the same behavior. 4. Submit a prompt, wait for assistant output or tool activity, then cancel. Confirm that the transcript remains intact and the prompt is not restored into the composer. 5. Cancel several output-free prompts and resize the terminal between attempts. Confirm that the startup banner, tip, and transcript history do not duplicate in scrollback. Targeted tests: - `just test -p codex-tui cancelled_turn_edit_restores_prompt` - `just test -p codex-tui output_free_interrupted_turn_requests_prompt_restore` - `just test -p codex-tui visible_output_prevents_cancelled_turn_prompt_restore` - `just test -p codex-tui thinking_status_keeps_cancelled_turn_prompt_restore_eligible` - `just test -p codex-tui patch_activity_prevents_cancelled_turn_prompt_restore` The full `just test -p codex-tui` run completed with `2746` passing tests and two unrelated existing guardian feature-flag failures. `just argument-comment-lint` remains blocked locally by the existing Bazel LLVM `compiler-rt` sanitizer-header glob failure; the touched Rust diff was manually audited for positional literal comments. |
||
|
|
a5a94ee5a7 |
Constrain Windows sandbox requirements (#23766)
# Why Managed requirements can already constrain sandbox policy choices, but Windows sandbox implementation selection was still resolved independently from those requirements. That left the TUI able to continue through the unelevated fallback even when an organization wants to require the elevated Windows sandbox implementation. # What - Add `[windows].allowed_sandbox_implementations` requirements support for the Windows `elevated` and `unelevated` implementations. - Apply that allowlist during core config resolution so disallowed configured or feature-selected Windows sandbox implementations fall back to an allowed implementation with the existing requirements warning path. - Reuse the existing TUI Windows setup prompts to block disallowed unelevated continuation, keep required elevated setup in front of the user, and refuse to persist a TUI-selected Windows sandbox mode that requirements disallow. # Semantics | Allowed | Selected | Effective | | --- | --- | --- | | `["elevated"]` | `unelevated` / unset | `elevated` | | `["unelevated"]` | `elevated` / unset | `unelevated` | | `["elevated", "unelevated"]` | `elevated` | `elevated` | | `["elevated", "unelevated"]` | `unelevated` | `unelevated` | | `["elevated", "unelevated"]` | unset | `elevated` | Availability is handled by interactive setup surfaces after allowlist resolution. If the effective elevated implementation is not ready, elevated-only requirements block on setup. When unelevated is also allowed, the UI may offer the existing unelevated fallback. ## TUI Screens If elevated setup is not already complete: ``` Your organization requires the default Codex agent sandbox to continue. Set it up to protect your files and control network access. Learn more <https://developers.openai.com/codex/windows> › 1. Set up default sandbox (requires Administrator permissions) 2. Quit ``` If admin setup fails under `["elevated"]`: ``` Couldn't set up your sandbox with Administrator permissions Your organization requires the default sandbox before Codex can continue. Learn more <https://developers.openai.com/codex/windows> › 1. Try setting up admin sandbox again 2. Quit ``` # Next Steps - extend the requirements/readout surface, such as `configRequirements/read`, so clients can inspect the loaded `[windows].allowed_sandbox_implementations` requirement instead of inferring it from Windows setup state - consider extending `windowsSandbox/readiness` as well - update the App startup guide, setup flow, and banner surfaces so an elevated-only requirement omits any continue-unelevated escape hatch and blocks startup until a permitted implementation is ready; - preserve the existing unelevated fallback path when requirements allow it, including the `["unelevated"]` case where elevated is disallowed |
||
|
|
62039e8d35 |
Use session wording in /rename confirmation (#25035)
## Why The TUI `/rename` confirmation should use the term "session" for consistency. |
||
|
|
1333f4a689 |
Align TUI permissions labels with app (#25017)
## Summary The desktop app now presents the on-request permissions mode as `Ask for approval` and the manual-review-backed mode as `Approve for me`. The TUI still exposed older/internal labels like `Default` and `Auto-review`, which made the same underlying settings look different across clients. This updates the TUI UX copy to match the app without changing the underlying default behavior. Fresh threads continue to use the existing on-request approval mode, now displayed as `Ask for approval`. The label changes cover `/permissions`, explicit profile permissions menus, status surfaces, config persistence history/error text, and the corresponding TUI snapshots. ### Before <img width="1181" height="119" alt="Screenshot 2026-05-28 at 10 19 47 PM" src="https://github.com/user-attachments/assets/0664846b-b6dd-4931-b4dd-d0af0d42058e" /> <img width="523" height="19" alt="Screenshot 2026-05-28 at 10 21 29 PM" src="https://github.com/user-attachments/assets/7899c33e-b35d-4684-8389-97e357803423" /> ### After <img width="1216" height="117" alt="Screenshot 2026-05-28 at 10 19 32 PM" src="https://github.com/user-attachments/assets/015aab43-ac97-411f-8031-75cdd887251b" /> <img width="567" height="18" alt="Screenshot 2026-05-28 at 10 20 24 PM" src="https://github.com/user-attachments/assets/28b6422c-b823-4298-b221-c83d46d09d66" /> |
||
|
|
56958f2512 |
Seed prompt history from resumed messages (#24298)
## Why When the TUI resumes a thread, transcript replay renders prior user messages but did not seed the composer history. That leaves the resumed session with empty in-memory prompt history, so pressing Up can fall through to persisted global history and surface a prompt from another thread. The expected behavior is that prompts from the resumed thread are recalled first, with global history only as a fallback. ## What changed - Record replayed user messages into the composer history during resume replay. - Preserve the existing persisted history format and avoid any startup history scan. - Add focused TUI coverage showing replayed prompts are recalled before persisted global history. ## Validation - Added `replayed_user_messages_seed_composer_history` in `codex-rs/tui/src/chatwidget/tests/history_replay.rs`. - `just test -p codex-tui replayed_user_messages_seed_composer_history` passed. |
||
|
|
7a26497836 |
feat(tui): add OSC 8 web links to rich content (#24472)
## Why Wrapped URLs in rich TUI output, especially URLs rendered inside Markdown tables, are split across terminal rows. In terminals that support OSC 8 hyperlinks, treating each visible fragment as part of the complete destination enables reliable open-link and copy-link actions even after table layout wraps the URL. This addresses the semantic-link portion of #12200 and the behavior described in https://github.com/openai/codex/issues/12200#issuecomment-4535452980. It does not change ordinary drag-selection across bordered table rows. ## What Changed - Added shared TUI OSC 8 support that validates `http://` and `https://` destinations, sanitizes terminal payloads, and applies metadata separately from visible line width/layout. - Added semantic web-link annotations to assistant and proposed-plan Markdown, including explicit web links and bare web URLs in prose and table cells while excluding code and non-web Markdown destinations. - Preserved complete URL targets through table wrapping, narrow pipe fallback, streaming, transcript overlay rendering, history insertion, and resize replay. - Routed intentional Codex-owned links in notices, status/setup/app-link, feedback, onboarding, MCP/plugin help, memories, and update surfaces through the shared hyperlink handling. ## How to Test 1. Run Codex in a terminal with OSC 8 link support, such as Ghostty, and request an assistant response containing a Markdown table whose last column contains a long `https://` URL. 2. Make the terminal narrow enough for the URL to wrap across multiple bordered table rows. 3. Use the terminal's open-link or copy-link action on more than one wrapped URL fragment and confirm each fragment resolves to the complete original URL. 4. Resize the terminal after the table is rendered and repeat the link action to confirm the destination survives scrollback replay. 5. Open the transcript overlay while rich output is present and confirm web links remain interactive there. 6. As a regression check, render inline/fenced code containing URL text and a Markdown link such as `[https://example.com](mailto:support@example.com)`; confirm these do not acquire a web OSC 8 destination. Targeted automated coverage exercised Markdown links and exclusions, wrapped and pipe-fallback tables, streaming/transcript overlay propagation, status-link truncation, and rendered word-wrapping cell alignment. `just test -p codex-tui` was also run; it passed the hyperlink coverage and reproduced two unrelated existing guardian feature-flag test failures. |
||
|
|
9826581e7b |
Attach Windows sandbox log to feedback reports (#24623)
## Why Windows sandbox diagnostics are currently hard to recover from `/feedback` even though they are often the most useful artifact when debugging sandbox behavior. Now that sandbox logging uses daily rolling files, feedback can safely include the current day's sandbox log without uploading the old ever-growing legacy `sandbox.log`. ## What changed - Add a `codex-windows-sandbox` helper that resolves the current daily sandbox log from `codex_home`. - When feedback is submitted with logs enabled on Windows, app-server attaches today's sandbox log if it exists. - Upload the attachment under the stable filename `windows-sandbox.log`, independent of the dated on-disk filename. - Keep existing raw `extra_log_files` behavior unchanged for rollout and desktop log attachments. ## Verification - `cargo fmt -p codex-app-server -p codex-windows-sandbox` - `cargo test -p codex-windows-sandbox current_log_file_path_for_codex_home_uses_sandbox_dir` - `cargo test -p codex-app-server windows_sandbox_log_attachment_uses_current_log` - Manual CLI/TUI `/feedback` test confirmed Sentry received `windows-sandbox.log`. |
||
|
|
cd934c8bcb |
tui: keep inaccessible apps out of mentions (#24625)
## Summary Fix the TUI `$` app mention paths so App Directory rows that are not accessible are not treated as usable apps. This includes the core preservation fix from #24104, but expands it to the other app mention paths: - preserve app-server `is_accessible` flags when partial `app/list/updated` snapshots reach the TUI - require apps to be both accessible and enabled when resolving exact `$slug` mentions - require restored/stale `app://...` bindings to point at accessible, enabled apps before emitting structured app mentions - remove the now-unused `codex-chatgpt` dependency from `codex-tui`, which addresses the `cargo shear` failure seen on #24104 ## Root Cause The app server already sends merged app snapshots with accessibility computed. The TUI handled app-server app list updates as partial app loads and re-ran the old accessible-app merge path. That path treated every notification row as accessible, so App Directory entries with `isAccessible=false` could appear in `$` suggestions. Regression source: #22914 routed app-list updates through the app server while reusing the old TUI partial-load handling. Related precursor: #14717 introduced the partial-load path, but #22914 made it user-visible for app-server updates. ## Issues Fixes #24145 Fixes #24205 Fixes #24319 ## Validation - `just fmt` - `git diff --check` - `just bazel-lock-update` - `just bazel-lock-check` - `just argument-comment-lint -p codex-tui` - `just test -p codex-tui chatwidget::tests::popups_and_settings::apps_notification_update_excludes_inaccessible_apps_from_mentions chatwidget::tests::composer_submission::submit_user_message_ignores_inaccessible_app_mentions_from_bindings chatwidget::skills::tests::find_app_mentions_requires_accessible_enabled_apps_for_bound_paths chatwidget::skills::tests::find_app_mentions_requires_accessible_enabled_apps_for_slugs` |
||
|
|
f6fd753039 |
tui: add named permission profile picker (#21559)
## Why Users who opt into named permission profiles through `default_permissions` or `[permissions.*]` should stay in named-profile semantics when they open `/permissions`. The legacy picker rewrites those users into anonymous preset state, which loses the active profile identity and hides custom configured profiles. ## What changed - Switch `/permissions` to a profile-aware picker when profile mode is active. - Show friendly built-in labels instead of raw `:` profile syntax. - Include configured custom profiles and their descriptions in the picker. - Route selections through the split TUI profile-selection flow below this PR. - Add TUI snapshots and regression coverage for built-ins, custom profiles, and conflicting legacy runtime overrides. ## Stack 1. [#22931](https://github.com/openai/codex/pull/22931): runtime/session/network propagation for active permission profiles. 2. [#23708](https://github.com/openai/codex/pull/23708): TUI selection plumbing and guardrail flow. 3. **This PR**: profile-aware `/permissions` menu and custom profile display. ## UX impact In profile mode, `/permissions` shows the same human-facing built-ins users already know: ```text Default Auto-review Full Access Read Only locked-down web-enabled ``` Selecting `locked-down` keeps `active_permission_profile = Some("locked-down")`; selecting a built-in keeps the friendly label while switching to its named built-in profile. ## Screenshots Live `$test-tui` smoke screenshots uploaded through GitHub attachments: **Profile mode with built-ins and custom profiles** <img width="832" alt="Profile mode permissions picker with custom profiles" src="https://github.com/user-attachments/assets/58b72431-418c-4839-9e39-575076db4c8f" /> **Legacy mode remains anonymous preset picker** <img width="1232" alt="Legacy permissions picker" src="https://github.com/user-attachments/assets/95f413ab-4cee-411c-9afb-92580a885c97" /> <img width="1296" height="906" alt="image" src="https://github.com/user-attachments/assets/ea381a78-9904-4aa2-828f-b7f2e43f60f2" /> <img width="705" height="207" alt="Screenshot 2026-05-18 at 2 58 00 PM" src="https://github.com/user-attachments/assets/2fa6dd71-0296-449e-a6de-a72d78a1cb70" /> ## Validation - `git diff --cached --check` before commit. - Full test run skipped at the user request while pushing the split stack. |
||
|
|
0f91e869bd |
Use thread config for TUI MCP inventory (#24532)
## Summary `/mcp` in the TUI should reflect the current loaded thread, including project-local MCP servers from that thread config. Before this change, `mcpServerStatus/list` only read the latest global MCP config, so the active chat could miss project-local servers. This adds optional `threadId` to `mcpServerStatus/list`. When present, app-server resolves the loaded thread and lists MCP status from the refreshed effective config for that thread; when omitted, existing global config behavior stays unchanged. The TUI now sends the active chat thread id for `/mcp` and `/mcp verbose`, carries that origin through the async inventory result, and ignores stale completions if the user has switched threads before the fetch returns. The app-server schemas were regenerated. ## Follow-up Once this app-server API change lands, the desktop app should make the same `threadId` plumbing so its MCP inventory also uses the current thread config. Fixes #23874 |
||
|
|
913270a689 |
Show remote connection details in /status (#24420)
## Summary Fixes #24411. `/status` currently has no way to show when the TUI is talking to Codex through a remote transport. That makes embedded local sessions, local daemon sessions, and true remote sessions look the same, and it hides the remote server version when debugging connection-specific behavior. This PR adds a single `Remote` row for non-embedded connections only. The row shows the sanitized connection address and a dimmed version parenthetical, preserving the existing status output for embedded local sessions. <img width="791" height="144" alt="image" src="https://github.com/user-attachments/assets/529d7940-1c45-4586-8b06-f20a1f04b771" /> ## Verification - Manually validated when connecting remotely (either implicitly to local daemon or explicitly) |
||
|
|
fcff0d6c52 |
tui: plumb permission profile selection (#23708)
## Why The named-profile `/permissions` picker needs a small TUI action path that can select permission profiles without folding the menu UI and profile metadata into the same review. ## What changed - Carry permission-profile selections through the TUI app event flow. - Persist selected profiles while preserving the existing approval settings and guardrail prompts. - Keep the legacy `/permissions` picker behavior in this layer; the profile-mode menu stays in the follow-up PR. ## Stack 1. [#22931](https://github.com/openai/codex/pull/22931): runtime/session/network propagation for active permission profiles. 2. **This PR**: TUI selection plumbing and guardrail flow. 3. [#21559](https://github.com/openai/codex/pull/21559): profile-aware `/permissions` menu and custom profile display. <img width="1632" height="1186" alt="image" src="https://github.com/user-attachments/assets/69ddcd5e-b57c-468d-8c1d-246916323c15" /> ## Validation - `git diff --cached --check` before commit. - Full test run skipped at the user request while pushing the split stack. |
||
|
|
edc48e4612 |
Sync TUI thread settings through app server (#23507)
Builds on #23502. ## Why #23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR https://github.com/openai/codex/pull/22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa. |
||
|
|
d269aa2af9 |
Harden CLI rate limit window labels (#22929)
## Context The CLI rate-limit surfaces previously described usage windows as fixed 5-hour and weekly limits. We want the CLI to display whatever supported rate-limit period the server returns instead of assuming a 5-hour/1-week pair. This supports generalized Codex rate-limit periods. ## Summary - Formats CLI rate-limit warning/status labels only for the supported returned window durations: approximate 5h, daily, weekly, monthly, and annual. - Uses generic fallback copy when a primary or secondary window has no duration, so missing secondary protection data does not produce stale weekly copy. - Uses generic fallback copy for unsupported window durations instead of adding arbitrary hourly, multi-day, multi-week, or multi-year labels. - Updates status line and terminal title setup descriptions/previews to talk about primary/secondary usage limits rather than fixed 5h/weekly limits. - Adds rendered insta snapshot coverage for the updated rate-limit status surfaces and `/status` fallback labels. ## Tests Tested locally: - one primary window - one secondary window - primary and secondary window |
||
|
|
ae10708ae0 |
[2 of 4] tui: route app and skill enablement through app server (#22914)
## Why App and skill toggles are user config mutations too. When the TUI is attached to a remote app server, writing those toggles into the local `config.toml` makes the UI report success without updating the server that actually owns the session. This is **[2 of 4]** in a stacked series that moves TUI-owned config mutations onto app-server APIs. ## What changed - Routed app enable/disable persistence through app-server config batch writes. - Routed skill enable/disable persistence through `skills/config/write`. - Avoided refreshing local config from disk after these writes when the TUI is connected to a remote app server. ## Config keys affected - `apps.<app_id>.enabled` - `apps.<app_id>.disabled_reason` - `[[skills.config]]` entries keyed by `path`, with `enabled = false` used for persisted disables ## Suggested manual validation - Connect the TUI to a remote app server, disable an app, reconnect, and confirm the app remains disabled from remote config rather than local disk state. - Re-enable the same app and confirm both `apps.<app_id>.enabled` and `apps.<app_id>.disabled_reason` are cleared remotely. - Disable a skill in the manage-skills UI and confirm a remote `[[skills.config]]` disable entry appears. - Re-enable that skill and confirm the disable entry is removed and the effective enabled state updates without relying on local config reloads. ## Stack 1. [#22913](https://github.com/openai/codex/pull/22913) `[1 of 4]` primary settings writes 2. [#22914](https://github.com/openai/codex/pull/22914) `[2 of 4]` app and skill enablement 3. [#22915](https://github.com/openai/codex/pull/22915) `[3 of 4]` feature and memory toggles 4. [#22916](https://github.com/openai/codex/pull/22916) `[4 of 4]` startup and onboarding bookkeeping |
||
|
|
4ac3ea20a2 |
Clarify resume hints for renamed threads (#23234)
Addresses #23181 ## Why Renamed threads can share names, so hints that suggest resuming directly by name are ambiguous. Issue #23181 asks for the picker hint to include the thread name and thread ID in parens so users can disambiguate safely. ## What - Adds a shared resume hint formatter for named threads: run `codex resume`, then select `<name> (<thread-id>)`. - Uses that hint for /rename confirmations, TUI session summaries, and CLI/TUI exit messages. - Keeps direct `codex resume <thread-id>` guidance for unnamed threads. ## Verification Manually verified that message after `/rename` and after `/exit` include session ID in parens. --------- Co-authored-by: Felipe Coury <felipe.coury@openai.com> |
||
|
|
bb43044cba |
fix(tui): show shutdown feedback on exit (#23323)
## Why Ctrl+C can take a noticeable amount of time to finish when the TUI is waiting for the app-server thread shutdown path to complete. Before this change, the UI could look like it had not accepted the shutdown request because the composer and cursor remained in their normal interactive state during that wait. This PR makes the accepted shutdown visible immediately. It does not add an artificial sleep or change the shutdown timeout; it only draws one final feedback frame before continuing through the existing shutdown flow. ## What Changed - On `ExitMode::ShutdownFirst`, the TUI now renders shutdown feedback before awaiting the existing thread shutdown future. - The bottom pane disables composer input, which hides the cursor through the existing disabled-input cursor path. - The composer shows `Shutting down...` as the disabled input hint and suppresses footer content so the shutdown acknowledgement is not competing with shortcut/status text. - The logout path uses the same feedback path before shutting down. ## How to Test 1. Start Codex from this branch. 2. Press `Ctrl+C` to request shutdown. 3. If shutdown takes long enough to observe, confirm the composer changes to `› Shutting down...`, the cursor disappears, and no footer hint is rendered below it. 4. Regression check: repeat with text already typed in the composer and confirm the visible row still switches to `Shutting down...` while the draft remains preserved internally until the process exits. Targeted tests: - `cargo test -p codex-tui shutdown_in_progress_disables_input_and_uses_hint_without_footer` - `cargo test -p codex-tui bottom_pane::footer::tests::` ## Local Validation Note `cargo test -p codex-tui` still aborts in `app::tests::discard_side_thread_removes_agent_navigation_entry` with a stack overflow. That same test also failed when run alone locally, and the failure appears unrelated to this shutdown feedback path. |
||
|
|
108234b5eb |
core: set permission profiles from snapshots (#22920)
## Why #22891 moved the TUI turn-command path to pass `ActivePermissionProfile` instead of the full `PermissionProfile`, but the remaining config/session bridge still accepted the concrete `PermissionProfile` and active profile id as separate arguments. That shape made it too easy for future callers to update the concrete profile and active profile id out of sync. This PR makes the trusted session snapshot path pass one coherent value into `Permissions`, while keeping `requirements.toml` enforcement owned by the existing constrained permission state. ## What Changed - Added `PermissionProfileSnapshot` as the public snapshot value for trusted session/config synchronization. - Changed `Permissions::set_permission_profile_from_session_snapshot()` and `replace_permission_profile_from_session_snapshot()` to take a `PermissionProfileSnapshot`. - Updated the replacement path to derive its constrained `PermissionProfile` from the snapshot, so callers cannot pass a separate profile that disagrees with the snapshot. - Removed the internal tuple-style `PermissionProfileState::set_active_permission_profile()` mutation path. - Updated core session projection and TUI call sites to construct explicit legacy or active snapshots. - Documented the snapshot constructors so legacy use and id/profile mismatch hazards are called out at the API boundary. - Added a focused config test that verifies snapshot updates still respect existing permission constraints. ## How To Review 1. Start with `codex-rs/core/src/config/resolved_permission_profile.rs`; `PermissionProfileSnapshot` is the public wrapper, while `ResolvedPermissionProfile` stays internal. 2. Check `codex-rs/core/src/config/mod.rs` to confirm both session-snapshot setters validate through `PermissionProfileState` and no longer accept loose profile/id pairs. 3. Skim `codex-rs/core/src/session/session.rs` for the session projection path; it now builds the snapshot before installing it. 4. Skim the TUI changes as call-site migration from loose argument pairs to explicit snapshot construction. ## Verification - `cargo test -p codex-core permission_snapshot_setter_preserves_permission_constraints` - `cargo test -p codex-tui status_permissions_` - `cargo test -p codex-tui session_configured_preserves_profile_workspace_roots` - `just fix -p codex-core -p codex-tui` |
||
|
|
bbb5c2811d |
tui: pass active permission profiles through app commands (#22891)
## Why This continues the permissions migration by keeping the TUI command boundary aligned with the app-server protocol direction from #22795: callers should select a permission profile by id instead of passing a concrete `PermissionProfile` value around as the turn configuration. `AppCommand` is internal to the TUI, but it is the path that eventually becomes `thread/turn/start`, so carrying concrete profile details there made it too easy for UI code to keep relying on the old whole-profile replacement model. ## What changed - `AppCommand::UserTurn` and `AppCommand::OverrideTurnContext` now carry `Option<ActivePermissionProfile>` instead of `PermissionProfile`. - Composer submissions copy the active permission profile id from the current session snapshot; legacy snapshots intentionally submit no active profile id. - Permission preset UI events now carry only the active built-in profile id. The app derives the concrete built-in `PermissionProfile` internally only when updating its local config/status snapshot. - Permission presets expose their built-in active profile id, and preset selection preserves that id in both the immediate turn override and the local TUI config snapshot. - Turn routing sends `TurnPermissionsOverride::ActiveProfile` when an active id is present, and only falls back to the legacy sandbox projection for the remaining runtime override path. ## How to review Start with `codex-rs/tui/src/app_command.rs` to verify the command shape no longer exposes `PermissionProfile`. Then read `codex-rs/tui/src/app/thread_routing.rs` to verify the app-server turn-start conversion: active ids go through as ids, while the legacy sandbox fallback is still constrained to the existing runtime override case. Finally, check `codex-rs/tui/src/chatwidget/permission_popups.rs`, `codex-rs/tui/src/app/event_dispatch.rs`, `codex-rs/tui/src/app/config_persistence.rs`, and `codex-rs/utils/approval-presets/src/lib.rs` to see how preset selections stay id-only across TUI events while the local display/config mirror still gets a concrete built-in profile. ## Verification Latest local verification after the id-only `AppEvent` cleanup: - `cargo check -p codex-tui --tests` - `cargo test -p codex-tui permissions_selection_sends_approvals_reviewer_in_override_turn_context` - `cargo test -p codex-tui update_feature_flags_enabling_guardian` - `cargo test -p codex-utils-approval-presets` - `just fmt` - `just fix -p codex-tui -p codex-utils-approval-presets` Earlier in the same PR, before the final event-shape cleanup: - `cargo test -p codex-tui turn_permissions_` - `cargo test -p codex-tui submission_` - `cargo test -p codex-tui session_configured_syncs_widget_config_permissions_and_cwd` - `RUST_MIN_STACK=16777216 cargo test -p codex-tui` |
||
|
|
3dc278b68e |
Trim TUI legacy core helper usage (#22695)
## Why The TUI still had a few low-risk dependencies flowing through the transitional `legacy_core` namespace after the app-server migration. These helpers either already have clearer non-core owners or are presentation logic that does not belong in `codex-core`, so moving them out reduces the compatibility surface without changing product behavior. ## What changed This is a low-risk change, almost completely mechanical in nature. - Route TUI Codex-home lookup through `codex-utils-home-dir`, use `Config::log_dir` directly, and call `codex-sandboxing::system_bwrap_warning` without going through `legacy_core`. - Move shared `codex resume` hint formatting from `codex-core` into `codex-utils-cli`. - Update CLI and TUI call sites to use the shared CLI utility, and keep the resume-command behavior covered by tests in its new home. ## Verification - `cargo test -p codex-utils-cli` - `cargo test -p codex-utils-cli resume_command` |
||
|
|
3c3e18c222 |
Refactor chatwidget orchestration into modules (phase 5) (#22537)
## Why `chatwidget.rs` is still carrying too many unrelated responsibilities in one file. #22269 started a five-phase cleanup to move coherent behavior domains into focused modules while keeping `chatwidget.rs` as the composition layer. #22407 completed phase 2 by extracting input and submission flow, #22433 completed phase 3 by extracting protocol, replay, streaming, and tool lifecycle handling, and #22518 completed phase 4 by extracting settings, popups, and status surfaces. This PR is phase 5. It cleans up the remaining constructor and orchestration code now that the larger behavior domains have moved out, leaving `chatwidget.rs` much closer to the composition layer the cleanup was aiming for. This is once again a mechanical movement of existing functions. No functional changes. ## What Changed - Added focused modules for widget construction and initial wiring, session configuration flow, key/composer interaction routing, review popup orchestration, desktop notification coalescing, and render composition. - Moved the remaining constructor, session setup, interaction, notification, review picker, and rendering helpers out of `codex-rs/tui/src/chatwidget.rs`. - Preserved the existing startup/session behavior, keyboard handling, review picker flow, notification priority behavior, and render composition while shrinking the central widget module substantially. - Left `codex-rs/tui/src/chatwidget.rs` as the registration and composition surface for the extracted behavior modules. ## Cleanup Phases The five-phase cleanup plan from #22269 is: 1. Phase 1: mechanical helper and state moves. Completed in #22269. 2. Phase 2: extract input and submission flow, including queued user messages, shell prompt submission, pending steer restoration, and thread input snapshot/restore behavior. Completed in #22407. 3. Phase 3: extract protocol, replay, streaming, and tool lifecycle handling, while preserving active-cell grouping, transcript invalidation, interrupt deferral, and final-message separator behavior. Completed in #22433. 4. Phase 4: extract settings, popups, and status surfaces, including model/reasoning/collaboration/personality popups, permission prompts, rate-limit UI, and connectors helpers. Completed in #22518. 5. Phase 5: clean up the remaining constructor and orchestration code once the larger behavior domains have moved out, leaving `chatwidget.rs` as the composition layer. This PR. ## Verification - `cargo check -p codex-tui` - `cargo test -p codex-tui chatwidget::tests::popups_and_settings` - `cargo test -p codex-tui chatwidget::tests::plan_mode` - `cargo test -p codex-tui chatwidget::tests::review_mode` - `cargo test -p codex-tui chatwidget::tests::status_and_layout` `cargo test -p codex-tui` also compiles and begins running, but aborts in the unchanged app-side test `app::tests::discard_side_thread_keeps_local_state_when_server_close_fails` with the same reproducible stack overflow noted in phase 4. |
||
|
|
1ae811ddb2 |
Refactor chatwidget settings surfaces into modules (phase 4) (#22518)
## Why `chatwidget.rs` is still carrying too many unrelated responsibilities in one file. #22269 started a five-phase cleanup to move coherent behavior domains into focused modules while keeping `chatwidget.rs` as the composition layer. #22407 completed phase 2 by extracting input and submission flow, and #22433 completed phase 3 by extracting protocol, replay, streaming, and tool lifecycle handling. This PR is phase 4. It keeps moving high-churn UI coordination out of the central widget by extracting settings, popups, and status surfaces without changing the visible behavior those flows already provide. This is once again a mechanical movement of existing functions. No functional changes. ## What Changed - Added focused modules for runtime settings/model coordination, model/reasoning/collaboration popups, settings/personality/theme/audio/experimental popups, permission prompts, status setup/output controls, and Windows sandbox prompt flows. - Moved the remaining rate-limit nudge/status helpers and connectors popup/loading/update helpers into their existing focused modules. - Preserved the existing picker flows, approval behavior, status/title setup previews, rate-limit notices, and connectors/app list behavior while shrinking `chatwidget.rs` back toward orchestration. - Left `codex-rs/tui/src/chatwidget.rs` as the registration and composition surface for these extracted behaviors. ## Cleanup Phases The five-phase cleanup plan from #22269 is: 1. Phase 1: mechanical helper and state moves. Completed in #22269. 2. Phase 2: extract input and submission flow, including queued user messages, shell prompt submission, pending steer restoration, and thread input snapshot/restore behavior. Completed in #22407. 3. Phase 3: extract protocol, replay, streaming, and tool lifecycle handling, while preserving active-cell grouping, transcript invalidation, interrupt deferral, and final-message separator behavior. Completed in #22433. 4. Phase 4: extract settings, popups, and status surfaces, including model/reasoning/collaboration/personality popups, permission prompts, rate-limit UI, and connectors helpers. This PR. 5. Phase 5: clean up the remaining constructor and orchestration code once the larger behavior domains have moved out, leaving `chatwidget.rs` as the composition layer. ## Verification - `cargo check -p codex-tui` - `cargo test -p codex-tui chatwidget::tests::permissions` - `cargo test -p codex-tui chatwidget::tests::status_surface_previews` - `cargo test -p codex-tui chatwidget::tests::popups_and_settings` - `cargo test -p codex-tui chatwidget::tests::status_and_layout` `cargo test -p codex-tui` also compiles and begins running, but aborts in the unchanged app-side test `app::tests::discard_side_thread_keeps_local_state_when_server_close_fails` with a reproducible stack overflow. |
||
|
|
8fe0ecb045 |
Refactor chatwidget protocol flows into modules (phase 3) (#22433)
## Why `chatwidget.rs` is still carrying too many unrelated responsibilities in one file. #22269 started a five-phase cleanup to move coherent behavior domains into focused modules while keeping `chatwidget.rs` as the composition layer. #22407 completed phase 2 by extracting input and submission flow. This PR is phase 3. It keeps moving high-churn event handling out of the central widget by extracting protocol, replay, streaming, and tool lifecycle handling without changing the visible behavior those flows already provide. This is once again just a mechanical movement of existing functions. No functional changes. ## What Changed - Added focused modules for protocol request dispatch, replay rendering, assistant/plan/reasoning streaming, turn runtime bookkeeping, hook lifecycle handling, command lifecycle handling, tool lifecycle rendering, and interactive tool request prompts. - Kept active-cell grouping, transcript invalidation, interrupt deferral, and final-message separator behavior in the same flows, just moved into smaller files. - Added module header comments to the new files so the ownership boundaries are explicit. - Left `codex-rs/tui/src/chatwidget.rs` as the registration and orchestration surface for these extracted behaviors. ## Cleanup Phases The five-phase cleanup plan from #22269 is: 1. Phase 1: mechanical helper and state moves. Completed in #22269. 2. Phase 2: extract input and submission flow, including queued user messages, shell prompt submission, pending steer restoration, and thread input snapshot/restore behavior. Completed in #22407. 3. Phase 3: extract protocol, replay, streaming, and tool lifecycle handling, while preserving active-cell grouping, transcript invalidation, interrupt deferral, and final-message separator behavior. This PR. 4. Phase 4: extract settings, popups, and status surfaces, including model/reasoning/collaboration/personality popups, permission prompts, rate-limit UI, and connectors helpers. 5. Phase 5: clean up the remaining constructor and orchestration code once the larger behavior domains have moved out, leaving `chatwidget.rs` as the composition layer. |
||
|
|
3d517fbd00 |
feat(tui): standardize picker navigation keys (#22347)
## Why Picker-style UI in the TUI has accumulated a mix of hardcoded navigation keys. Some lists supported page movement, some did not; some accepted Vim-like keys, while others only accepted arrows; and tabbed or horizontally adjustable pickers had no shared keymap action for left/right movement. This PR makes picker/list navigation consistent and configurable so users can rely on the same defaults across the TUI. ## What Changed - Adds shared list keymap actions for: - vertical movement: `move_up`, `move_down` - horizontal movement: `move_left`, `move_right` - paging and jumps: `page_up`, `page_down`, `jump_top`, `jump_bottom` - Adds defaults: - Up/down: arrows, `Ctrl+P/N`, `Ctrl+K/J`, and plain `k/j` where text input is not active - Page up/down: `PageUp/PageDown` and `Ctrl+B/F` - First/last: `Home/End` - Left/right: `Left/Right` and `Ctrl+H/L` - Wires the shared list keymap through picker and list surfaces including session resume, multi-select, tabbed selection lists, settings-style lists, app-link selection, MCP elicitation, request-user-input, and the OSS selection wizard. - Keeps search behavior intact by reserving printable characters for query text in searchable pickers. - Updates keymap setup actions, config schema, snapshots, and focused coverage for the new list actions. ## How to Test 1. Start Codex from this branch and open the session picker, for example with an existing session history. 2. In the session list, verify that `Ctrl+J/K` moves the selection down/up. 3. Verify that `Ctrl+F/B` pages down/up and `Home/End` jumps to the first/last visible session. 4. Type printable search text such as `j` or `k` and confirm it updates the query instead of navigating. 5. Focus a picker control that changes values horizontally, such as a session picker toolbar control, and verify `Ctrl+H/L` changes the focused value like left/right arrows. Targeted tests run: - `cargo test -p codex-tui keymap::tests::` - `cargo test -p codex-tui keymap_setup::tests::` - `cargo test -p codex-tui horizontal_list_keys` - `cargo test -p codex-tui page_and_jump_navigation_use_list_keymap` - `cargo test -p codex-tui ctrl_h_l_move_provider_selection` - `cargo test -p codex-tui scroll_state::tests` - `cargo test -p codex-tui switching_tabs_changes_visible_items_and_clears_search` - `cargo test -p codex-tui toggle_sort_key_reloads_with_new_sort` Also ran `just write-config-schema`, `just fmt`, `just fix -p codex-tui`, `just argument-comment-lint`, and `git diff --check`. Note: `cargo test -p codex-tui` was attempted and still aborts in the pre-existing `tests::fork_last_filters_latest_session_by_cwd_unless_show_all` stack overflow, which is unrelated to this branch. |
||
|
|
2630a6ca35 |
Refactor chatwidget input flow into modules (#22407)
## Why `chatwidget.rs` is still carrying too many unrelated responsibilities in one file. #22269 started a five-phase effort to move coherent behavior domains into focused modules while keeping `chatwidget.rs` as the composition layer. This PR is phase 2 of that plan. It extracts the input and submission flow as a mechanical move before the later protocol, popup/status, and constructor/orchestration phases. ## What Changed - Added `codex-rs/tui/src/chatwidget/input_flow.rs` for composer input results, queued user-message draining, pending-input previews, and mode-specific submission entry points. - Added `codex-rs/tui/src/chatwidget/input_submission.rs` for user-message construction/submission, shell prompt submission, structured mention resolution, and blocked image draft restoration. - Added `codex-rs/tui/src/chatwidget/input_restore.rs` for initial-message submission, pending steer restoration after interrupts, and thread input snapshot/restore behavior. - Registered the new modules and removed the moved `ChatWidget` impl methods from `codex-rs/tui/src/chatwidget.rs`. ## Follow-On Refactor Phases The five-phase plan from #22269 is: - Phase 1: mechanical helper and state moves. Completed in #22269. - Phase 2: extract input and submission flow, including queued user messages, shell prompt submission, pending steer restoration, and thread input snapshot/restore behavior. This PR. - Phase 3: extract protocol, replay, streaming, and tool lifecycle handling, while preserving active-cell grouping, transcript invalidation, interrupt deferral, and final-message separator behavior. - Phase 4: extract settings, popups, and status surfaces, including model/reasoning/collaboration/personality popups, permission prompts, rate-limit UI, and connectors helpers. - Phase 5: clean up the remaining constructor and orchestration code once the larger behavior domains have moved out, leaving `chatwidget.rs` as the composition layer. |
||
|
|
92930a8d40 |
Refactor chatwidget state into modules (#22269)
## Why `chatwidget.rs` is still carrying too many unrelated responsibilities in one file. After #21866 consolidated some of the state it tracks, this starts the next phase by moving coherent state/helper clusters out of the main module without changing behavior. This PR is intentionally mechanical: it only moves existing functions, structs, and helpers into focused modules so the boundaries are easier to review before the less mechanical refactors that should follow. ## What Changed - Moved user-message, composer, queue, pending steer, and merge/remap helpers into `codex-rs/tui/src/chatwidget/user_messages.rs`. - Added `codex-rs/tui/src/chatwidget/exec_state.rs` for unified exec bookkeeping helpers. - Added `codex-rs/tui/src/chatwidget/rate_limits.rs` for rate-limit warning, prompt, and error classification state. - Moved plugin list fetch and install auth-flow state into `codex-rs/tui/src/chatwidget/plugins.rs`. - Made a couple of test-only `VecDeque` imports explicit now that those tests no longer inherit the parent module import. ## Verification - `cargo test -p codex-tui` was run ## Follow-On Refactor Phases This PR is phase 1: mechanical helper and state moves. Planned follow-up PRs: - Phase 2: extract input and submission flow, including queued user messages, shell prompt submission, pending steer restoration, and thread input snapshot/restore behavior. - Phase 3: extract protocol, replay, streaming, and tool lifecycle handling, while preserving active-cell grouping, transcript invalidation, interrupt deferral, and final-message separator behavior. - Phase 4: extract settings, popups, and status surfaces, including model/reasoning/collaboration/personality popups, permission prompts, rate-limit UI, and connectors helpers. - Phase 5: clean up the remaining constructor and orchestration code once the larger behavior domains have moved out, leaving `chatwidget.rs` as the composition layer. |
||
|
|
b6e718591b |
[codex] Remove workspace owner usage nudge gate (#20509)
## Summary - make workspace owner nudge handling unconditional in the TUI now that it is fully rolled out - keep `workspace_owner_usage_nudge` as a removed no-op compatibility flag so old configs/app overrides remain accepted during rollout - remove flag-disabled test setup ## Companion PR - https://github.com/openai/openai/pull/876351 removes the Codex Apps Statsig rollout gate override after this change is available to the app/runtime path ## Validation - `just write-config-schema` - `just fmt` - `cargo test -p codex-features` - `cargo test -p codex-tui status_and_layout` |