Commit Graph

22 Commits

  • chore: clean up argument-comment lint and roll out all-target CI on macOS (#16054)
    ## Why
    
    `argument-comment-lint` was green in CI even though the repo still had
    many uncommented literal arguments. The main gap was target coverage:
    the repo wrapper did not force Cargo to inspect test-only call sites, so
    examples like the `latest_session_lookup_params(true, ...)` tests in
    `codex-rs/tui_app_server/src/lib.rs` never entered the blocking CI path.
    
    This change cleans up the existing backlog, makes the default repo lint
    path cover all Cargo targets, and starts rolling that stricter CI
    enforcement out on the platform where it is currently validated.
    
    ## What changed
    
    - mechanically fixed existing `argument-comment-lint` violations across
    the `codex-rs` workspace, including tests, examples, and benches
    - updated `tools/argument-comment-lint/run-prebuilt-linter.sh` and
    `tools/argument-comment-lint/run.sh` so non-`--fix` runs default to
    `--all-targets` unless the caller explicitly narrows the target set
    - fixed both wrappers so forwarded cargo arguments after `--` are
    preserved with a single separator
    - documented the new default behavior in
    `tools/argument-comment-lint/README.md`
    - updated `rust-ci` so the macOS lint lane keeps the plain wrapper
    invocation and therefore enforces `--all-targets`, while Linux and
    Windows temporarily pass `-- --lib --bins`
    
    That temporary CI split keeps the stricter all-targets check where it is
    already cleaned up, while leaving room to finish the remaining Linux-
    and Windows-specific target-gated cleanup before enabling
    `--all-targets` on those runners. The Linux and Windows failures on the
    intermediate revision were caused by the wrapper forwarding bug, not by
    additional lint findings in those lanes.
    
    ## Validation
    
    - `bash -n tools/argument-comment-lint/run.sh`
    - `bash -n tools/argument-comment-lint/run-prebuilt-linter.sh`
    - shell-level wrapper forwarding check for `-- --lib --bins`
    - shell-level wrapper forwarding check for `-- --tests`
    - `just argument-comment-lint`
    - `cargo test` in `tools/argument-comment-lint`
    - `cargo test -p codex-terminal-detection`
    
    ## Follow-up
    
    - Clean up remaining Linux-only target-gated callsites, then switch the
    Linux lint lane back to the plain wrapper invocation.
    - Clean up remaining Windows-only target-gated callsites, then switch
    the Windows lint lane back to the plain wrapper invocation.
  • Remove the legacy TUI split (#15922)
    This is the part 1 of 2 PRs that will delete the `tui` /
    `tui_app_server` split. This part simply deletes the existing `tui`
    directory and marks the `tui_app_server` feature flag as removed. I left
    the `tui_app_server` feature flag in place for now so its presence
    doesn't result in an error. It is simply ignored.
    
    Part 2 will rename the `tui_app_server` directory `tui`. I did this as
    two parts to reduce visible code churn.
  • chore: remove skill metadata from command approval payloads (#15906)
    ## Why
    
    This is effectively a follow-up to
    [#15812](https://github.com/openai/codex/pull/15812). That change
    removed the special skill-script exec path, but `skill_metadata` was
    still being threaded through command-approval payloads even though the
    approval flow no longer uses it to render prompts or resolve decisions.
    
    Keeping it around added extra protocol, schema, and client surface area
    without changing behavior.
    
    Removing it keeps the command-approval contract smaller and avoids
    carrying a dead field through app-server, TUI, and MCP boundaries.
    
    ## What changed
    
    - removed `ExecApprovalRequestSkillMetadata` and the corresponding
    `skillMetadata` field from core approval events and the v2 app-server
    protocol
    - removed the generated JSON and TypeScript schema output for that field
    - updated app-server, MCP server, TUI, and TUI app-server approval
    plumbing to stop forwarding the field
    - cleaned up tests that previously constructed or asserted
    `skillMetadata`
    
    ## Testing
    
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-protocol`
    - `cargo test -p codex-app-server-test-client`
    - `cargo test -p codex-mcp-server`
    - `just argument-comment-lint`
  • Fix quoted command rendering in tui_app_server (#15825)
    When `tui_app_server` is enabled, shell commands in the transcript
    render as fully quoted invocations like `/bin/zsh -lc "..."`. The
    non-app-server TUI correctly shows the parsed command body.
    
    Root cause:
    The app-server stores `ThreadItem::CommandExecution.command` as a
    shell-quoted string. When `tui_app_server` bridges that item back into
    the exec renderer, it was passing `vec![command]` unchanged instead of
    splitting the string back into argv. That prevented
    `strip_bash_lc_and_escape()` from recognizing the shell wrapper, so the
    renderer displayed the wrapper literally.
    
    Solution:
    Add a shared command-string splitter that round-trips shell-quoted
    commands back into argv when it is safe to do so, while preserving
    non-roundtrippable inputs as a single string. Use that helper everywhere
    `tui_app_server` reconstructs exec commands from app-server payloads,
    including live command-execution items, replayed thread items, and exec
    approval requests. This restores the same command display behavior as
    the direct TUI path without breaking Windows-style commands that cannot
    be safely round-tripped.
  • fix(tui_app_server): fix remote subagent switching and agent names (#15513)
    ## TL;DR
    
    This PR changes the `tui_app_server` _path_ in the following ways:
    
    - add missing feature to show agent names (shows only UUIDs today) 
    - add `Cmd/Alt+Arrows` navigation between agent conversations
    
    ## Problem
    
    When the TUI connects to a remote app server, collab agent tool-call
    items (spawn, wait, delegate, etc.) render thread UUIDs instead of
    human-readable agent names because the `ChatWidget` never receives
    nickname/role metadata for receiver threads. Separately, keyboard
    next/previous agent navigation silently does nothing when the local
    `AgentNavigationState` cache has not yet been populated with subagent
    threads that the remote server already knows about.
    
    Both issues share a root cause: in the remote (app-server) code path the
    TUI never proactively fetches thread metadata. In the local code path
    this metadata arrives naturally via spawn events the TUI itself
    orchestrates, but in the remote path those events were processed by a
    different client and the TUI only sees the resulting collab tool-call
    notifications.
    
    ## Mental model
    
    Collab agent tool-call notifications reference receiver threads by id,
    but carry no nickname or role. The TUI needs that metadata in two
    places:
    
    1. **Rendering** -- `ChatWidget` converts `CollabAgentToolCall` items
    into history cells. Without metadata, agent status lines show raw UUIDs.
    2. **Navigation** -- `AgentNavigationState` tracks known threads for the
    `/agent` picker and keyboard cycling. Without entries for remote
    subagents, next/previous has nowhere to go.
    
    This change closes the gap with two complementary strategies:
    
    - **Eager hydration**: when any notification carries
    `receiver_thread_ids`, the TUI fetches metadata (`thread/read`) for
    threads it has not yet cached before the notification is rendered.
    - **Backfill on thread switch**: when the user resumes, forks, or starts
    a new app-server thread, the TUI fetches the full `thread/loaded/list`,
    walks the parent-child spawn tree, and registers every descendant
    subagent in both the navigation cache and the `ChatWidget` metadata map.
    
    A new `collab_agent_metadata` side-table in `ChatWidget` stores
    nickname/role keyed by `ThreadId`, kept in sync by `App` whenever it
    calls `upsert_agent_picker_thread`. The `replace_chat_widget` helper
    re-seeds this map from `AgentNavigationState` so that thread switches
    (which reconstruct the widget) do not lose previously discovered
    metadata.
    
    ## Non-goals
    
    - This change does not alter the local (non-app-server) collab code
    path. That path already receives metadata via spawn events and is
    unaffected.
    - No new protocol messages are introduced. The change uses existing
    `thread/read` and `thread/loaded/list` RPCs.
    - No changes to how `AgentNavigationState` orders or cycles through
    threads. The traversal logic is unchanged; only the population of
    entries is extended.
    
    ## Tradeoffs
    
    - **Extra RPCs on notification path**:
    `hydrate_collab_agent_metadata_for_notification` issues a `thread/read`
    for each unknown receiver thread before the notification is forwarded to
    rendering. This adds latency on the notification path but only fires
    once per thread (the result is cached). The alternative -- rendering
    first and backfilling names later -- would cause visible flicker as
    UUIDs are replaced with names.
    - **Backfill fetches all loaded threads**:
    `backfill_loaded_subagent_threads` fetches the full loaded-thread list
    and walks the spawn tree even when the user may only care about one
    subagent. This is simple and correct but O(loaded_threads) per thread
    switch. For typical session sizes this is negligible; it could become a
    concern for sessions with hundreds of subagents.
    - **Metadata duplication**: agent nickname/role is now stored in both
    `AgentNavigationState` (for picker/label) and
    `ChatWidget::collab_agent_metadata` (for rendering). The two are kept in
    sync through `upsert_agent_picker_thread` and `replace_chat_widget`, but
    there is no compile-time enforcement of this coupling.
    
    ## Architecture
    
    ### New module: `app::loaded_threads`
    
    Pure function `find_loaded_subagent_threads_for_primary` that takes a
    flat list of `Thread` objects and a primary thread id, then walks the
    `SessionSource::SubAgent` parent-child edges to collect all transitive
    descendants. Returns a sorted vec of `LoadedSubagentThread` (thread_id +
    nickname + role). No async, no side effects -- designed for unit
    testing.
    
    ### New methods on `App`
    
    | Method | Purpose |
    |--------|---------|
    | `collab_receiver_thread_ids` | Extracts `receiver_thread_ids` from
    `ItemStarted` / `ItemCompleted` collab notifications |
    | `hydrate_collab_agent_metadata_for_notification` | Fetches and caches
    metadata for unknown receiver threads before a notification is rendered
    |
    | `backfill_loaded_subagent_threads` | Bulk-fetches all loaded threads
    and registers descendants of the primary thread |
    | `adjacent_thread_id_with_backfill` | Attempts navigation, falls back
    to backfill if the cache has no adjacent entry |
    | `replace_chat_widget` | Replaces the widget and re-seeds its metadata
    map from `AgentNavigationState` |
    
    ### New state in `ChatWidget`
    
    `collab_agent_metadata: HashMap<ThreadId, CollabAgentMetadata>` -- a
    lookup table that rendering functions consult to attach human-readable
    names to collab tool-call items. Populated externally by `App` via
    `set_collab_agent_metadata`.
    
    ### New method on `AppServerSession`
    
    `thread_loaded_list` -- thin wrapper around
    `ClientRequest::ThreadLoadedList`.
    
    ## Observability
    
    - `tracing::warn` on invalid thread ids during hydration and backfill.
    - `tracing::warn` on failed `thread/read` or `thread/loaded/list` RPCs
    (with thread id and error).
    - No new metrics or feature flags.
    
    ## Tests
    
    -
    **`loaded_threads::tests::finds_loaded_subagent_tree_for_primary_thread`**
    -- unit test for the spawn-tree walk: verifies child and grandchild are
    included, unrelated threads are excluded, and metadata is carried
    through.
    -
    **`app::tests::replace_chat_widget_reseeds_collab_agent_metadata_for_replay`**
    -- integration test that creates a `ChatWidget`, replaces it via
    `replace_chat_widget`, replays a collab wait notification, and asserts
    the rendered history cell contains the agent name rather than a UUID.
    - **Updated snapshot** `app_server_collab_wait_items_render_history` --
    the existing collab wait rendering test now sets metadata before sending
    notifications, so the snapshot shows `Robie [explorer]` / `Ada
    [reviewer]` instead of raw thread ids.
    
    ---------
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • app-server: add filesystem watch support (#14533)
    ### Summary
    Add the v2 app-server filesystem watch RPCs and notifications, wire them
    through the message processor, and implement connection-scoped watches
    with notify-backed change delivery. This also updates the schema
    fixtures, app-server documentation, and the v2 integration coverage for
    watch and unwatch behavior.
    
    This allows clients to efficiently watch for filesystem updates, e.g. to
    react on branch changes.
    
    ### Testing
    - exercise watch lifecycles for directory changes, atomic file
    replacement, missing-file targets, and unwatch cleanup
  • Finish moving codex exec to app-server (#15424)
    This PR completes the conversion of non-interactive `codex exec` to use
    app server rather than directly using core events and methods.
    
    ### Summary
    - move `codex-exec` off exec-owned `AuthManager` and `ThreadManager`
    state
    - route exec bootstrap, resume, and auth refresh through existing
    app-server paths
    - replace legacy `codex/event/*` decoding in exec with typed app-server
    notification handling
    - update human and JSONL exec output adapters to translate existing
    app-server notifications only
    - clean up "app server client" layer by eliminating support for legacy
    notifications; this is no longer needed
    - remove exposure of `authManager` and `threadManager` from "app server
    client" layer
    
    ### Testing
    - `exec` has pretty extensive unit and integration tests already, and
    these all pass
    - In addition, I asked Codex to put together a comprehensive manual set
    of tests to cover all of the `codex exec` functionality (including
    command-line options), and it successfully generated and ran these tests
  • Remove legacy auth and notification handling from tui_app_server (#15414)
    ## Summary
    - remove `tui_app_server` handling for legacy app-server notifications
    - drop the local ChatGPT auth refresh request path from `tui_app_server`
    - remove the now-unused refresh response helper from local auth loading
    
    Split out of #15106 so the `tui_app_server` cleanup can land separately
    from the larger `codex-exec` app-server migration.
  • Remove legacy app-server notification handling from tui_app_server (#15390)
    As part of moving the TUI onto the app server, we added some temporary
    handling of some legacy events. We've confirmed that these do not need
    to be supported, so this PR removes this support from the
    tui_app_server, allowing for additional simplifications in follow-on
    PRs. These events are needed only for very old rollouts. None of the
    other app server clients (IDE extension or app) support these either.
    
    ## Summary
    - stop translating legacy `codex/event/*` notifications inside
    `tui_app_server`
    - remove the TUI-side legacy warning and rollback buffering/replay paths
    that were only fed by those notifications
    - keep the lower-level app-server and app-server-client legacy event
    plumbing intact so PR #15106 can rebase on top and handle the remaining
    exec/lower-layer migration separately
  • Add realtime transcript notification in v2 (#15344)
    - emit a typed `thread/realtime/transcriptUpdated` notification from
    live realtime transcript deltas
    - expose that notification as flat `threadId`, `role`, and `text` fields
    instead of a nested transcript array
    - continue forwarding raw `handoff_request` items on
    `thread/realtime/itemAdded`, including the accumulated
    `active_transcript`
    - update app-server docs, tests, and generated protocol schema artifacts
    to match the delta-based payloads
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Feat/restore image generation history (#15223)
    Restore image generation items in resumed thread history
  • feat(app-server): add mcpServer/startupStatus/updated notification (#15220)
    Exposes the legacy `codex/event/mcp_startup_update` event as an API v2
    notification.
    
    The legacy event has this shape:
    ```
    #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
    pub struct McpStartupUpdateEvent {
        /// Server name being started.
        pub server: String,
        /// Current startup status.
        pub status: McpStartupStatus,
    }
    
    #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
    #[serde(rename_all = "snake_case", tag = "state")]
    #[ts(rename_all = "snake_case", tag = "state")]
    pub enum McpStartupStatus {
        Starting,
        Ready,
        Failed { error: String },
        Cancelled,
    }
    ```
  • [hooks] use a user message > developer message for prompt continuation (#14867)
    ## Summary
    
    Persist Stop-hook continuation prompts as `user` messages instead of
    hidden `developer` messages + some requested integration tests
    
    This is a followup to @pakrym 's comment in
    https://github.com/openai/codex/pull/14532 to make sure stop-block
    continuation prompts match training for turn loops
    
    - Stop continuation now writes `<hook_prompt hook_run_id="...">stop
    hook's user prompt<hook_prompt>`
    - Introduces quick-xml dependency, though we already indirectly depended
    on it anyway via syntect
    - This PR only has about 500 lines of actual logic changes, the rest is
    tests/schema
    
    ## Testing
    
    Example run (with a sessionstart hook and 3 stop hooks) - this shows
    context added by session start, then two stop hooks sending their own
    additional prompts in a new turn. The model responds with a single
    message addressing both. Then when that turn ends, the hooks detect that
    they just ran using `stop_hook_active` and decide not to infinite loop
    
    test files for this (unzip, move codex -> .codex):
    [codex.zip](https://github.com/user-attachments/files/26075806/codex.zip)
    
    ```
    › cats
    
    
    • Running SessionStart hook: lighting the observatory
    
    SessionStart hook (completed)
      warning: Hi, I'm a session start hook for wizard-tower (startup).
      hook context: A wimboltine stonpet is an exotic cuisine from hyperspace
    
    • Cats are tiny zen wizards, my friend: equal parts nap, mystery, and chaos. If you want, we can talk
      cat facts, cat breeds, cat names, or build something cat-themed in this repo.
    
    • Running Stop hook: checking the tower wards
    
    • Running Stop hook: sacking the guards
    
    • Running Stop hook: hiring the guards
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook reviewed the completed reply (177 chars).
    
    Stop hook (blocked)
      warning: Wizard Tower Stop hook continuing conversation
      feedback: cook the stonpet
    
    Stop hook (blocked)
      warning: Wizard Tower Stop hook continuing conversation
      feedback: eat the cooked stonpet
    
    • Stonpet’s cooked, aloha style: flash-seared over a blue quasiflame, glazed with nebula salt, and
      rested until the hyperspace juices settle.
    
      Now we eat with gratitude, my friend. One mindful bite in, and the flavor is pure cosmic surf:
      smoky, bright, and totally out of this dimension.
    
    • Running Stop hook: checking the tower wards
    
    • Running Stop hook: sacking the guards
    
    • Running Stop hook: hiring the guards
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook reviewed the completed reply (285 chars).
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook saw a second pass and stayed calm to avoid a loop.
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook saw a second pass and stayed calm to avoid a loop.
    ```
  • Add thread/shellCommand to app server API surface (#14988)
    This PR adds a new `thread/shellCommand` app server API so clients can
    implement `!` shell commands. These commands are executed within the
    sandbox, and the command text and output are visible to the model.
    
    The internal implementation mirrors the current TUI `!` behavior.
    - persist shell command execution as `CommandExecution` thread items,
    including source and formatted output metadata
    - bridge live and replayed app-server command execution events back into
    the existing `tui_app_server` exec rendering path
    
    This PR also wires `tui_app_server` to submit `!` commands through the
    new API.
  • Gate realtime audio interruption logic to v2 (#14984)
    - thread the realtime version into conversation start and app-server
    notifications
    - keep playback-aware mic gating and playback interruption behavior on
    v2 only, leaving v1 on the legacy path
  • Add device-code onboarding and ChatGPT token refresh to app-server TUI (#14952)
    ## Summary
    - add device-code ChatGPT sign-in to `tui_app_server` onboarding and
    reuse the existing `chatgptAuthTokens` login path
    - fall back to browser login when device-code auth is unavailable on the
    server
    - treat `ChatgptAuthTokens` as an existing signed-in ChatGPT state
    during onboarding
    - add a local ChatGPT auth loader for handing local tokens to the app
    server and serving refresh requests
    - handle `account/chatgptAuthTokens/refresh` instead of marking it
    unsupported, including workspace/account mismatch checks
    - add focused coverage for onboarding success, existing auth handling,
    local auth loading, and refresh request behavior
    
    ## Testing
    - `cargo test -p codex-tui-app-server`
    - `just fix -p codex-tui-app-server`
  • fix(tui): restore remote resume and fork history (#14930)
    ## Problem
    
    When the TUI connects to a **remote** app-server (via WebSocket), resume
    and fork operations lost all conversation history.
    `AppServerStartedThread` carried only the `SessionConfigured` event, not
    the full `Thread` snapshot. After resume or fork, the chat transcript
    was empty — prior turns were silently discarded.
    
    A secondary issue: `primary_session_configured` was not cleared on
    reset, causing stale session state after reconnection.
    
    ## Approach: TUI-side only, zero app-server changes
    
    The app-server **already returns** the full `Thread` object (with
    populated `turns: Vec<Turn>`) in its `ThreadStartResponse`,
    `ThreadResumeResponse`, and `ThreadForkResponse`. The data was always
    there — the TUI was simply throwing it away. The old
    `AppServerStartedThread` struct only kept the `SessionConfiguredEvent`,
    discarding the rich turn history that the server had already provided.
    
    This PR fixes the problem entirely within `tui_app_server` (3 files
    changed, 0 changes to `app-server`, `app-server-protocol`, or any other
    crate). Rather than modifying the server to send history in a different
    format or adding a new endpoint, the fix preserves the existing `Thread`
    snapshot and replays it through the TUI's standard event pipeline —
    making restored sessions indistinguishable from live ones.
    
    ## Solution
    
    Add a **thread snapshot replay** path. When the server hands back a
    `Thread` object (on start, resume, or fork),
    `restore_started_app_server_thread` converts its historical turns into
    the same core `Event` sequence the TUI already processes for live
    interactions, then replays them into the event store so the chat widget
    renders them.
    
    Key changes:
    - **`AppServerStartedThread` now carries the full `Thread`** —
    `started_thread_from_{start,resume,fork}_response` clone the thread into
    the struct alongside the existing `SessionConfiguredEvent`.
    - **`thread_snapshot_events()`** walks the thread's turns and items,
    producing `TurnStarted` → `ItemCompleted`* →
    `TurnComplete`/`TurnAborted` event sequences that the TUI already knows
    how to render.
    - **`restore_started_app_server_thread()`** pushes the session event +
    history events into the thread channel's store, activates the channel,
    and replays the snapshot — used for initial startup, resume, and fork.
    - **`primary_session_configured` cleared on reset** to prevent stale
    session state after reconnection.
    
    ## Tradeoffs
    
    - **`Thread` is cloned into `AppServerStartedThread`**: The full thread
    snapshot (including all historical turns) is cloned at startup. For
    long-lived threads this could be large, but it's a one-time cost and
    avoids lifetime gymnastics with the response.
    
    ## Tests
    
    - `restore_started_app_server_thread_replays_remote_history` —
    end-to-end: constructs a `Thread` with one completed turn, restores it,
    and asserts user/agent messages appear in the transcript.
    - `bridges_thread_snapshot_turns_for_resume_restore` — unit: verifies
    `thread_snapshot_events` produces the correct event sequence for
    completed and interrupted turns.
    
    ## Test plan
    
    - [ ] Verify `cargo check -p codex-tui-app-server` passes
    - [ ] Verify `cargo test -p codex-tui-app-server` passes
    - [ ] Manual: connect to a remote app-server, resume an existing thread,
    confirm history renders in the chat widget
    - [ ] Manual: fork a thread via remote, confirm prior turns appear
  • Fix tui_app_server: ignore duplicate legacy stream events (#14892)
    The in-process app-server currently emits both typed
    `ServerNotification`s and legacy `codex/event/*` notifications for the
    same live turn updates. `tui_app_server` was consuming both paths, so
    message deltas and completed items could be enqueued twice and rendered
    as duplicated output in the transcript.
    
    Ignore legacy notifications for event types that already have typed (app
    server) notification handling, while keeping legacy fallback behavior
    for events that still only arrive on the old path. This preserves
    compatibility without duplicating streamed commentary or final agent
    output.
    
    We will remove all of the legacy event handlers over time; they're here
    only during the short window where we're moving the tui to use the app
    server.
  • Apply argument comment lint across codex-rs (#14652)
    ## Why
    
    Once the repo-local lint exists, `codex-rs` needs to follow the
    checked-in convention and CI needs to keep it from drifting. This commit
    applies the fallback `/*param*/` style consistently across existing
    positional literal call sites without changing those APIs.
    
    The longer-term preference is still to avoid APIs that require comments
    by choosing clearer parameter types and call shapes. This PR is
    intentionally the mechanical follow-through for the places where the
    existing signatures stay in place.
    
    After rebasing onto newer `main`, the rollout also had to cover newly
    introduced `tui_app_server` call sites. That made it clear the first cut
    of the CI job was too expensive for the common path: it was spending
    almost as much time installing `cargo-dylint` and re-testing the lint
    crate as a representative test job spends running product tests. The CI
    update keeps the full workspace enforcement but trims that extra
    overhead from ordinary `codex-rs` PRs.
    
    ## What changed
    
    - keep a dedicated `argument_comment_lint` job in `rust-ci`
    - mechanically annotate remaining opaque positional literals across
    `codex-rs` with exact `/*param*/` comments, including the rebased
    `tui_app_server` call sites that now fall under the lint
    - keep the checked-in style aligned with the lint policy by using
    `/*param*/` and leaving string and char literals uncommented
    - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo
    registry/git metadata in the lint job
    - split changed-path detection so the lint crate's own `cargo test` step
    runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes
    - continue to run the repo wrapper over the `codex-rs` workspace, so
    product-code enforcement is unchanged
    
    Most of the code changes in this commit are intentionally mechanical
    comment rewrites or insertions driven by the lint itself.
    
    ## Verification
    
    - `./tools/argument-comment-lint/run.sh --workspace`
    - `cargo test -p codex-tui-app-server -p codex-tui`
    - parsed `.github/workflows/rust-ci.yml` locally with PyYAML
    
    ---
    
    * -> #14652
    * #14651
  • Move TUI on top of app server (parallel code) (#14717)
    This PR replicates the `tui` code directory and creates a temporary
    parallel `tui_app_server` directory. It also implements a new feature
    flag `tui_app_server` to select between the two tui implementations.
    
    Once the new app-server-based TUI is stabilized, we'll delete the old
    `tui` directory and feature flag.