Render code comment directives in TUI replay (#26554)

## Summary

Resumed Codex App or VS Code review sessions can contain
`::code-comment` directives that the TUI previously displayed verbatim
because only rich clients interpret them.

This change rewrites valid line-start directives into readable Markdown
during assistant-message parsing, using the session working directory
for relative file paths. The fallback is applied consistently to live
messages, replayed transcripts, and resume previews while preserving
malformed directives and existing `::git-*` parsing.

## Before

The TUI exposed the raw client directive:

```text
::code-comment{title="Fix body= parsing" body="Keep role=\"tab\", ::git-stage{cwd=/tmp}, file=, and \n literal." file="/repo/src/app.ts" start=10 end=12 priority="P2"}
```

## After

The same directive is rendered as readable review feedback:

```text
- [P2] Fix body= parsing — src/app.ts:10-12
  Keep role="tab", ::git-stage{cwd=/tmp}, file=, and \n literal.
```

Fixes #25658
This commit is contained in:
Eric Traut authored and GitHub committed 2026-06-05 08:34:34 -07:00
1 parent fb0993dd3b
commit e5af672d73
6 files changed
+167 -11

No files matched your search

+3 -2
View File
@@ -38,7 +38,8 @@ impl ChatWidget {
// Consolidate the run of streaming AgentMessageCells into a single AgentMarkdownCell
// that can re-render from source on resize.
if let Some(source) = source {
let source = parse_assistant_markdown(&source).visible_markdown;
let source =
parse_assistant_markdown(&source, self.config.cwd.as_path()).visible_markdown;
self.app_event_tx.send(AppEvent::ConsolidateAgentMessage {
source,
cwd: self.config.cwd.to_path_buf(),
@@ -261,7 +262,7 @@ impl ChatWidget {
AgentMessageContent::Text { text } => message.push_str(text),
}
}
let parsed = parse_assistant_markdown(&message);
let parsed = parse_assistant_markdown(&message, self.config.cwd.as_path());
self.finalize_completed_assistant_message(
(!parsed.visible_markdown.is_empty()).then_some(parsed.visible_markdown.as_str()),
);
+3 -3
View File
@@ -89,9 +89,9 @@ impl ChatWidget {
// source only when no earlier item-level event (AgentMessageItem, plan
// commit, review output) already recorded markdown for this turn. This
// prevents the final summary from overwriting a more specific source.
let sanitized_last_agent_message = last_agent_message
.as_deref()
.map(|message| parse_assistant_markdown(message).visible_markdown);
let sanitized_last_agent_message = last_agent_message.as_deref().map(|message| {
parse_assistant_markdown(message, self.config.cwd.as_path()).visible_markdown
});
if let Some(message) = sanitized_last_agent_message
.as_ref()
.filter(|message| !message.is_empty())