* feat(native-chat): model Codex MCP and web-search items instead of leaking opcodes
Codex's app-server sends 19 thread-item types; the structured translator handled
six. The rest fell through to a generic gray `codex · item:<type>` row, even
though the disposition table's own comment says it exists so a new item type
cannot leak like that — the table had one entry.
Give `mcpToolCall` and `webSearch` real tool-call bodies, and chrome `sleep`,
which carries only a duration and renders as nothing in Codex's own TUI.
`subAgentActivity` and `collabAgentToolCall` deliberately keep their generic
rows. They arrive in real sessions today and are currently the only visible
sign a subagent is running; hiding them before the subagent UI lands would
render minutes of work as an idle turn. Tests pin that they stay visible.
MCP tool names pass through verbatim when they contain `:`, `.`, `/` or `__`,
so `mcp__server__tool` survives instead of being title-cased into nonsense.
* fix(native-chat): keep Codex MCP tool identity and web-search results on the row
Four fixes to the Codex MCP / web-search item bodies:
- Drop the title-casing display name. `get_forecast` became `Get Forecast`,
which no longer matches the raw snake_case identifiers that the diff
renderer, question parsers, and tool-input previews dispatch on, and does not
match how the Claude lane or the sibling `shell`/`apply_patch`/`web_search`
bodies name a tool. The row name is now `server/tool` verbatim, the bare
`tool` when no server is given, and `mcp` when the item names no tool at all.
Server-qualifying also stops an MCP tool that happens to be called
`apply_patch` from hijacking the diff renderer.
- Pass the MCP call's own `arguments` as the tool input instead of wrapping it
in `{server, tool, arguments}`. Row-label derivation only reads top-level
keys, so the wrapper degraded every MCP row to a truncated raw JSON blob.
A non-object `arguments` stays addressable under a key rather than being
dropped; an absent one becomes null, which labels as empty rather than `{}`.
- Carry a web search's `results` as the call output, bounded like every other
inline payload and omitted when there are none. They were being dropped
entirely, which showed less than the generic fallback row it replaced.
- No streaming branches were added for these two item types: the Codex delta
stream is a closed set of six methods that neither can reach, so such
branches would be unreachable.
* fix(native-chat): label Codex web searches and argument-less MCP calls
A row label is derived from top-level `input` keys only, so a webSearch
whose detail lives inside `action` — an opened page, an in-page find, or
a bare `other` — fell through to the raw JSON of the whole input, as did
the empty `query` Codex leaves on a completed search. Hoist the action's
`url`, `pattern` and `type` beside the query, keep the full `action`
object so the expanded detail loses nothing, and emit no input at all for
the start frame.
An MCP tool that takes no arguments sends `arguments: {}`, which passed
straight through and labelled the row a literal `{}`; treat it as absent
so the row reads as a bare `server/tool`.
Split the durable-identity half of the item translator into
`codex-thread-item-identity.ts`, re-exported so every existing import is
unchanged, to keep both files under the max-lines cap.
---------
Co-authored-by: Merge Sim <sim@local>