acpmux: _acpmux/chat_transcript shows a chat's past turns before its first send (cx-5esm)

Merged
TE
1mo ago
+525-5

Summary

A chat that cannot be resumed over ACP (Droid, Continue, Amp, and Claude Code or Codex chats that cannot adopt) can now show its past turns read-only before the first send. This PR adds the daemon side: _acpmux/chat_transcript {key}. It reads the chat's prompts and answers from the harness's own store when asked, and keeps nothing.

  • The answer is {key, harness, title, cwd, turns: [{prompt, answer, promptAt?, answerAt?}]}. It holds the newest 200 turns, with each prompt and each answer capped at 20k characters.
  • Droid, Continue and Amp go through a new reader in cmux-chat-index (transcript.rs). Claude Code and Codex use adopt's existing reader (adopt_replay.rs), so a chat shows the same turns it would replay when adopted.
  • Tool calls, tool results and injected context (a whole <tag>…</tag> block) are left out. A person's prompt that starts with markup is kept.
  • Failures come back as invalid params with data.reason set to transcript_unsupported, transcript_too_large or transcript_unreadable. A file cut short mid-write, or one that is gone, is unreadable rather than an empty chat.
  • The verb is local socket only, like every other _acpmux/chat* verb. It is added to websocket_origins_never_get_chats.

The app pane that draws these turns is the next slice (cx-5esm).

Testing

acpmux/tests/chats_transcript.rs runs a hub over synthetic temp homes. Each test commit was run red on the fleet before its fix (cmux-tui-rust-check.sh, filter a_chat_with_no_acp_resume):

  • Droid, Continue and Amp: red on the test commit, then green.
  • Claude and Codex: red on 826ba62 (transcript_unsupported for the Claude key), then green on 433cd0e.
  • Markup prompts and unreadable files: red on d526e14 (the <div> prompt was dropped), then green on the head with fmt, clippy and test.

Other checks:

  • This PR also fixes two chats.rs failures that are red on base: chats_lists_synthetic_roots_with_filters_and_pages and watch_pushes_new_grown_and_removed_chats.
    • The cause is that the test homes lived in the temp dir. On workers whose temp dir is under /Volumes, every chat root there is refused as "another volume", so the index came back empty. The new test hit the same thing, failing with "no chat droid:…" on such a worker.
    • The chats*.rs test files (chats, chats_transcript, chats_activity, chats_settings, chats_open and chats_deltas) now put their homes under /tmp.
    • The full chat filter (fmt, clippy and test) now passes these binaries on an AWS worker.
    • The run then failed two hub_integration adopt tests on that worker: adopt_refuses_a_chat_live_in_another_process and adopt_forks_a_live_claude_chat_when_asked. This PR doesn't touch those tests, and their session cwd is also under /Volumes. I didn't run them on base to confirm; they are filed separately.
  • The crash ratchet shows no new hits in the touched crates, and the god-file check flags none of the touched files.
  • A review subagent read the change. It found nothing blocking, and its findings are fixed in 85bdb43.

Changelog

none

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Adds _acpmux/chat_transcript {key} so a chat without ACP resume can show its past turns read-only before its first send (cx-5esm). The verb reads the chat's prompts and answers from the harness's own store and keeps nothing.

  • Returns {key, harness, title, cwd, turns} with the newest 200 turns; each prompt and answer is capped at 20k characters, and tool calls, tool results, and injected <tag> blocks are skipped (a prompt that starts with markup is kept).
  • Droid, Continue, and Amp read through a new cmux-chat-index reader; Claude Code and Codex reuse adopt's reader, so an adopted chat replays the same turns.
  • Failures answer invalid params with data.reason set to transcript_unsupported, transcript_too_large, or transcript_unreadable; a missing or cut-short file is unreadable, never an empty chat.
  • Local socket only, like the other _acpmux/chat* verbs.

Testing

  • Chat index test homes now live under /tmp, fixing two chats.rs failures on workers whose temp dir sits on /Volumes (every chat root there is refused as another volume).