wta + Settings: Codex CLI support (history, hooks, auto-upgrade) — issue #80#98
Merged
Conversation
Replaces the dead 'codex' => None arm in from_agent_id with 'codex' => Some(Self::Codex), and threads the new variant through parse and all exhaustive matches in agent_sessions.rs, app.rs, history_loader.rs, session_registry.rs, and ui/agents_view.rs. history_loader: Codex returns true (conservative/Unknown semantics) until a dedicated codex probe is added in a later slice-A task. Subsequent commits in this slice wire downstream call-sites (history_loader, app, session_mgmt, session_registry, ui). Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verified that 'codex resume <session-id>' accepts a bare UUID and re-attaches to the on-disk rollout file. Flipping the profile's resume_flag from '' to 'resume' lets the existing command-synthesis template produce a valid command without further changes. Updates docstring + comments that asserted 'false for Codex today' in session_mgmt.rs and app.rs. This commit is intentionally separable from the rest of slice A so it can be reverted independently if downstream issues surface. Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Walks YYYY/MM/DD/rollout-*.jsonl, parses session_meta header for session id + cwd + payload.timestamp (used as last_activity_at for deterministic sort), extracts the first event_msg/user_message payload — with a response_item user-role fallback that skips the synthetic <environment_context> wrapper — as the title, and skips phantom files (header-only sessions or sessions with no user/assistant exchange past the env-context boilerplate). Phantom scanner uses stream_jsonl_lines so it's both capped and conservative on IO error (true preserves the row). Wired into load_all so F2 picks Codex history up alongside Claude/Copilot/Gemini. Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Lets live Codex rows whose title arrives later (e.g. via a SetTitle hook event in a future slice, or a re-scan after restart) pick up the same first-user-message extraction the historical loader uses. Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wires codex_key_is_resumable_on_disk_in (lenient — missing artefact defers to CLI) and codex_key_has_definite_resumable_content_in (strict — missing artefact reports phantom) into the public match-based dispatchers. The shared codex_session_has_real_content scanner landed in the previous commit. Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces four near-identical inline matches in app.rs with a single known_cli_id(&CliSource) -> Option<&'static str> helper that covers Codex (added in this slice). Each call-site continues to handle the None case with its own current semantics — bool false at the resume_flag site, the literal 'this CLI' string at both user-visible-message sites, and the existing log-and-early-return at dispatch_resume. Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regression tests that CliSource::Codex serializes to
SessionHookCliSource::Known("Codex") and that the reverse
direction accepts both "Codex" and "codex".
Refs #80
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Direct regression test that from_agent_id('codex') flowing into
the in-memory registry surfaces as CliSource::Codex (not
None or Unknown). Catches regressions in either layer.
Refs #80
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds Codex equivalents of the Claude live/ended/historical Enter + Shift+Enter cells so a regression in either resume_flag or the CliSource exhaustive matches fails this module directly. Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
main.rs is a binary target with no test module of its own; this mapping is exhaustive so the compiler enforces correctness when the CliSource enum gains a variant. Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refs #80 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The module-level docstring listed on-disk layouts for Copilot, Claude, and Gemini but omitted Codex. Mirror the existing entries (id, cwd, title, last_activity, phantom rules) so future maintainers see the full set of supported CLIs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends WTA’s agent session management (F2/Agents view) to treat Codex as a first-class CLI source and to surface read-only historical Codex sessions by scanning ~/.codex/sessions/.../rollout-*.jsonl, enabling resume via codex resume <uuid>.
Changes:
- Add
CliSource::Codexend-to-end (parsing, display labels, wire-format round-trip viaSessionHookCliSource). - Implement Codex historical-session scanning and title/phantom detection in
history_loader.rs, plus ISO-8601 timestamp parsing for Codex metadata. - Update session-management routing/tests so Codex rows behave consistently with existing CLI sources (focus vs resume-in-pane vs resume-via-CLI).
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/wta/src/ui/agents_view.rs | Show codex suffix for selected/active rows and add a focused unit test. |
| tools/wta/src/session_registry.rs | Add Codex wire-format mapping ("Codex"/"codex") and fan-in/round-trip tests. |
| tools/wta/src/session_mgmt.rs | Expand routing tests to cover Codex “Class A” scenarios and update resume-flag semantics. |
| tools/wta/src/main.rs | Display Codex in CLI source label output. |
| tools/wta/src/history_loader.rs | Add Codex history loader, phantom filtering, title lookup, and ISO timestamp parsing + tests. |
| tools/wta/src/app.rs | Centralize CliSource -> cli_id mapping via known_cli_id and route Codex through resume/focus logic. |
| tools/wta/src/agent_sessions.rs | Promote CliSource::Codex and allow from_agent_id("codex"). |
| tools/wta/src/agent_registry.rs | Update Codex profile to support resume via resume_flag = "resume" and add a regression test. |
This comment has been minimized.
This comment has been minimized.
# Conflicts: # tools/wta/src/history_loader.rs
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Includes placeholder codex_status/marketplace_info/uninstall stubs that return 'not installed' defaults. Tasks 7 and 8 replace them with real implementations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
# Conflicts: # tools/wta/src/agent_hooks_installer.rs # tools/wta/src/agent_sessions.rs # tools/wta/src/app.rs
This comment has been minimized.
This comment has been minimized.
…x-session # Conflicts: # tools/wta/src/app.rs
Without changing slice-A scope, fix the issues raised in the PR review: history_loader.rs (Copilot review): * Use SystemTime::UNIX_EPOCH.checked_add(...) so malformed / far-future timestamps fail closed (return None) instead of panicking on overflow. * Range-check timezone offsets HH (0-23) / MM (0-59) so strings like '...+99:99' are rejected instead of silently skewing the timestamp. * Update parse_iso_to_system_time docstring to match behavior (it also supports the +/-HH:MM offset variant, not only Z). agent_hooks_installer.rs (Copilot review): * parse_codex_marketplace_list: trim both ends of each line so the first whitespace-delimited column parses correctly when 'codex plugin marketplace list' emits column-aligned rows with leading spaces. * parse_codex_plugin_list: match the documented behavior by checking for an 'installed*' status prefix instead of just '!= "not"', so statuses like 'available' don't get misreported as installed. * Drop the stale 'Codex placeholders' section header — the functions below are real implementations. Resources.resw: add AIAgents_HooksRemovingCodexSummary to every locale that already had the Copilot/Claude/Gemini variants (16 .resw files total), so Codex doesn't silently fall back to en-US for translators. wt-agent-hooks/codex/.../send-event.ps1: update the bundle header and the CliSource-identification comment to refer to Codex instead of Claude/Copilot — the bundle is Codex-specific. Check-spelling fixes (rewording / renaming, no dictionary changes): * parse_iso_to_systemtime -> parse_iso_to_system_time (snake_case matches the SystemTime type). * parse_iso_accepts_feb_29_leap_year -> parse_iso_accepts_february_29_leap_year. * codex-fanin-test -> codex-fan-in-test (session_registry.rs test key). * superpowers slice-B docs: replace author handle in worktree paths with <user> placeholder; reword "stat'ing" to "running stat on". No behavior change beyond the targeted bug fixes Copilot called out; no new features, no signature changes, no test additions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@yeelam-gordon I've opened a new pull request, #150, to work on those changes. Once the pull request is ready, I'll request review from you. |
yeelam-gordon
approved these changes
May 31, 2026
* Add Codex variant to HooksCliFilter enum + into_scope arm so the Settings "Remove" action routes to codex hooks instead of failing. * Tolerate "not configured" / "not installed" stderr substrings during marketplace removal idempotency check, matching codex CLI's output. * Replace codex's send-event.ps1 with the same content as claude/copilot/gemini. The WTA_HOOK_LOG_DIR branch is a no-op for codex (codex doesn't spawn from wta-master so the env var is never set) but unifying eliminates four-way drift and lets us maintain a single script going forward. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Codex variant of the hook-removal status summary was committed
with the English string "Removing Codex hooks..." copy-pasted into
every .resw file. Translate it in the 12 real non-English locales by
mirroring the existing AIAgents_HooksRemovingClaudeSummary translation
pattern with "Claude" -> "Codex". en-US and the three pseudo-locales
(qps-ploc*) keep the English baseline, matching how the parallel
Claude entry is handled in those files.
Also fix zh-CN AIAgents_HooksInstall.HelpText: it was the only locale
with a longer translation that enumerates the supported CLIs as
"(Copilot, Claude, Gemini)". Add Codex so Chinese users see the
correct, complete list. Update the {Locked=...} comment to match.
No code or test changes; resw XML structure is preserved.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codex was the only CLI without auto-upgrade wiring after PR #142: when Intelligent Terminal rolled the wt-agent-hooks bundle version, Copilot / Claude / Gemini all refreshed automatically but Codex users stayed pinned at the old plugin version until they re-ran 'wta hooks install' manually. Wire up the same flow for Codex: * parse_codex_plugin_list_entry — parse 'codex plugin list' text into InstalledInfo (version + enabled). Sibling to the existing parse_codex_plugin_list bool helper; this one extracts the richer state needed by decide_upgrade. * read_installed_codex — spawn 'codex plugin list' (fast since Codex is a Rust binary; no PATH probe needed) and call the parser. * UpgradeAction::CodexReinstall — new variant. Codex has no 'plugin update' subcommand and 'marketplace upgrade' only refreshes Git marketplaces (not local), so we must uninstall + reinstall. Trust hashes in ~/.codex/config.toml survive because they hash the command string with literal \, not a resolved path. * upgrade_codex — calls uninstall_for_codex + install_for_codex; both helpers already handle idempotency. * upgrade_one_cli — read installed Codex state and dispatch to upgrade_codex when reinstall is needed. Tests: 10 new (4 parse + 4 decide + the existing 2 generic cases now cover Codex too). cargo test now 687/687 passing (was 677). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… parity, Settings trust hint Three follow-up gaps surfaced by the post-merge audit: 1. build/scripts/Verify-AgentHooks.ps1 hardcoded a three-CLI ValidateSet and display-name map, so `-CliFilter codex` was rejected outright and the status table never labeled the Codex row. Extended ValidateSet to include 'codex' and added a 'Codex CLI' entry to the display map. 2. All four send-event.ps1 copies (claude/copilot/gemini/codex) missed CODEX_SESSION_ID in three env-fallback chains: cliEnvHint trace tag, agent_session_id extraction (used only when stdin JSON lacks session_id), and the CliSource detection block. Defensive parity — hooks.json passes `-CliSource codex` explicitly, so these branches never fire in production, but the chain now matches the other three CLIs for consistency. claude/copilot/gemini stay byte-identical (the existing byte-equality tests in agent_hooks_installer.rs cover this). 3. Codex is the only CLI whose hook commands must be individually trusted by the user inside the CLI (`/hooks` -> approve) before the handlers fire. Surfaced a static one-line reminder under the Codex row in Settings -> AI agents -> Agent Hooks. The new AIAgents_CodexTrustHint resw string is translated across all 16 locales matching the existing Codex-string pattern (qps-* keep English per convention). Row visibility is already gated by ShowCodexHookRow so users without Codex on PATH see nothing. Also drops docs/superpowers/ from source control (kept locally via .gitignore) — those were ad-hoc plan/spec notes that shouldn't ship with the PR. Tests: cargo test -p wta still 687/687. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drop the extra plugins/ directory between the codex bundle root and
the plugin folder. Codex's marketplace protocol lets the plugin folder
live at any relative path declared in marketplace.json, so this
normalization brings the codex bundle in line with the other three
CLIs.
Before: tools/wta/wt-agent-hooks/codex/plugins/wt-agent-hooks/...
After: tools/wta/wt-agent-hooks/codex/wt-agent-hooks/...
Changes:
- Moved .codex-plugin/ and hooks/ up one level via git mv
- marketplace.json: ./plugins/wt-agent-hooks -> ./wt-agent-hooks
- agent_hooks_installer.rs read_bundled_version Codex arm: drop the
redundant .join("plugins") segment
- Updated installer module doc-comment to document the codex subtree
alongside the other three CLIs
cargo test: 687/687 pass. No CI test exercises real
`codex plugin marketplace add`, so a manual smoke install is
recommended after this change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The trust-hint commit (6620605) accidentally stripped the UTF-8 BOM from all 16 Resources.resw files because the PowerShell helper used to inject the AIAgents_CodexTrustHint string wrote files without the leading EF BB BF preamble. Every other resw in the repo carries a BOM; losing it makes the first line of these 16 files look modified in any diff and breaks tooling that relies on the BOM to detect encoding. Re-add EF BB BF to the start of each file. Content is otherwise identical (still contains AIAgents_CodexTrustHint.Text, still XML-well-formed). Diff against origin/main now shows only the new data blocks, no spurious xml-decl line change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
codex plugin list enumerates every plugin from every registered marketplace, including the built-in openai-curated snapshot (~150 entries). All we care about is the lone wt-agent-hooks row in our wt-local marketplace, so the rest is wasted work and masses of noise in the master log. Pass --marketplace wt-local to both call sites (status reader and the auto-upgrade ead_installed_codex reader). Parser logic is unchanged — it already filters for the wt-agent-hooks row and skips everything else. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…allButton The translator comment on AIAgents_HooksInstallButton.Content enumerated the agent CLIs hooks install into as `(Copilot, Claude, Gemini)` in 11 localized resw files. Add Codex to keep the hint in sync with what the installer actually targets now. User-facing values are unchanged; this only touches the internal comment text. en-US uses generic `every detected agent` wording so it doesn't need the same update. zh-CN already received the update along with its existing CLI enumeration in the user-visible value text. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #80
What this PR does
Adds Codex CLI support to Intelligent Terminal, bringing
Codex to parity with Copilot / Claude / Gemini across the
session-management view, the hooks installer, the Settings UI, and the
auto-upgrade pipeline.
Slice A — Session management (read-only history)
~/.codex/sessions/YYYY/MM/DD/rollout-*-<uuid>.jsonlasHistoricalrows in the session-management view (Ctrl+Shift+/).
codex resume <uuid>inthe agent pane (lenient resumability probe in the row, strict probe
screens out phantoms before showing the row).
CliSource::Codexto a first-class enum variant alongsideClaude,Copilot, andGemini.CliSource::Codexthrough the session-hook wire format(
"Codex", with lowercase"codex"also accepted on ingress) solive Codex sessions route through the registry like the other CLIs.
Slice B — Hooks installer + Settings UI
wta hooks install --codex/--alladds thewt-localmarketplaceand
wt-agent-hooksplugin to~/.codex/config.toml.Idempotent ("already registered" tolerated).
wta hooks remove --codex/--allreverses install.Idempotent ("not installed" / "not registered" tolerated).
wta hooks status --codexreports CLI + filesystem fallback state.tools/wta/wt-agent-hooks/codex/...withmarketplace.json,plugin.json,hooks.json(4 events:SessionStart,UserPromptSubmit,PermissionRequest,Stop),and
send-event.ps1(unified across all 4 CLIs in this branch).row with Install hooks / Remove hooks buttons mirroring the
existing CLIs.
cpSync EPERM when running from MSIX.
(
AgentName_Codex,AIAgents_HooksRemovingCodexSummary, zh-CNhelp-text expansion to list Codex in the CLI enumeration).
Auto-upgrade (PR #142 parity)
read_installed_codex+parse_codex_plugin_list_entryread theinstalled version from
codex plugin list.UpgradeAction::CodexReinstall— Codex has noplugin updatesubcommand and
marketplace upgradeonly refreshes Git marketplaces(not the local
wt-localmarketplace), so the upgrade pathuninstalls + reinstalls. Trust hashes in
~/.codex/config.tomlsurvive because they hash the command string with literal
${PLUGIN_ROOT}, not the resolved bundle path.upgrade_one_cliso an IT MSIX bundle bump automaticallyrefreshes the Codex plugin at next wta-master startup.
Codex-side limitations (vs. Claude / Copilot / Gemini)
Codex's hook system exposes a smaller event surface than the other CLIs;
the following gaps are upstream Codex CLI limitations, not work this PR
defers:
SessionEnd/StopFailurehooks. Codex emitsSessionStart/UserPromptSubmit/PermissionRequest/Stop(4 events) where Claude emits 6. Crash / abnormal-exitdetection therefore falls back to process-exit + timeout, the same
fallback path already used for sessions without hooks installed.
PermissionRequest≠Notification. Codex firesPermissionRequestonly when asking for a tool-permission grant,not when the LLM asks the user a clarifying question. So the
Attention/ "waiting for input" status surfaces for permissionprompts but not for LLM-driven free-text questions — the same
underlying limitation applies to all 4 CLIs, but Codex's coverage is
narrower because its single notification event is permission-only.
Implementation highlights
CliSource::Codexvariantagent_sessions.rsagent_registry.rsresume_flag = "resume"(Codex usescodex resume <id>, not--resume)history_loader.rsload_codex, phantom detector, handwritten ISO 8601 parser (chrono not in dep tree), title-by-key, lenient + strict probessession_registry.rsFrom<&CliSource>/From<SessionHookCliSource>app.rsknown_cli_idhelper centralizesCliSource -> &'static strui/agents_view.rs,main.rscli_suffix_for+cli_source_labelCodex armssession_mgmt.rsagent_hooks_installer.rsinstall_for_codex,uninstall_for_codex,codex_status, plugin/marketplace list parsers, auto-upgrade (read_installed_codex,parse_codex_plugin_list_entry,upgrade_codex,UpgradeAction::CodexReinstall)AIAgents.{xaml,idl,h,cpp}RemoveCodexHookscommandResources/<locale>/Resources.resw(16 locales)AgentName_Codex,AIAgents_HooksRemovingCodexSummary, zh-CN help-texttools/wta/wt-agent-hooks/codex/...Tests
cargo test --manifest-path tools/wta/Cargo.toml→ 687 passing, 0 failing.Codex-specific coverage added on top of the existing suite:
history_loader.rs(loader, phantom filtering, ordering,ISO parser bounds, title fallback, lenient + strict probes,
title-by-key round-trip).
session_registry.rs.session_mgmt.rs.known_cli_idtests inapp.rs.cli_suffix_fortest inui/agents_view.rs.staging, plugin-list parsing (
installed, enabled/not installed/ disabled / bare-installed forms).
parse_codex_plugin_list_entrycases (version +enabled extraction, bare-installed tolerance, not-installed, missing
row, unparseable version) + 4
decide_upgradeCodex cases(reinstall, up-to-date, disabled, not-installed).
ISO parser hardened against pre-1970 underflow, out-of-range
month/day/hour/min/sec, and
±HH:MMoffset handling. Phantom detectorskips synthetic
<environment_context>response items socodex resumeis never invoked on a session it would reject.Manual smoke checklist (for reviewer)
The TUI can't be exercised non-interactively, so please verify:
cargo run --manifest-path tools/wta/Cargo.toml --releasestartswta.session-management list if
~/.codex/sessions/has rollout files.phantoms / no env-context-only sessions).
codex resume <uuid>and the previous conversation loads.Click it; confirm
codex /hookslists 4 events asInstalled=1.t); confirm statusflips to
Active=1.Workingwhile the agent runs andIdleafter it stops.codex /hooksreportsInstalled=0for all events.tools/wta/wt-agent-hooks/codex/.codex-plugin/plugin.jsonversion, restart wta-master; confirm
codex plugin listshowsthe new version after one startup cycle.