Take the CLI's word for a clear instead of inferring it

Bryan reported no divider when clearing. It was not this code -- the
backend serving him started at 17:06, three hours before `Event::Cleared`
existed, so it has no such event to send and `/clear` reaches it as an
unrecognised passthrough. Verified against a current build: the event is
recorded.

Probing the CLI to establish that turned up something better than what
was here. `/clear` in stream-json mode emits a dedicated
`conversation_reset` line and *then* a fresh `init` with the new session
id -- so watching the id be replaced, which is what this did, was reading
the event through one of its side effects. The announcement says it
directly, and it arrives first, so the divider now lands above the new
conversation rather than after its opening line.

That also removes the reasoning the previous commit needed about which id
changes count. There is one signal now instead of an inference with two
exceptions, and the test that used to pin those exceptions became
`an_init_alone_is_never_a_clear`, which covers all three ways an init
arrives: a session's first, the one a compaction re-announces with the
same id, and the one following a resume.

The resume token still follows the id, unchanged -- one CLI event with
two observable effects, and each half now reads the half it needs.

Verified end to end against a real claude-cli session: message, /clear,
message, and the transcript reads userMessage / assistantText / cleared /
userMessage, in that order. 74 tests, clippy and rustfmt clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VETa8afmpWaYezLCqJhDB8
This commit is contained in:
irisandClaude Opus 5 committed 2026-08-29 20:39:21 -04:00
1 parent 71067275e2
commit 894180de77
2 files changed
+51 -55

No files matched your search

+9
View File
@@ -97,6 +97,15 @@ impl Translator {
}
match message.get("type").and_then(Value::as_str) {
Some("system") => self.translate_system(message),
// The CLI's own announcement that `/clear` took effect, sent
// just before the fresh `init` that carries the new
// session_id. Measured against 2.1.237 rather than inferred:
// this used to watch for the id being *replaced*, which is the
// same event seen through one of its side effects. Taking the
// announcement instead means the transcript's divider is the
// CLI saying "I did this", and it lands before the new init
// rather than after it.
Some("conversation_reset") => vec![Event::Cleared],
Some("stream_event") => self.translate_stream_event(&message["event"]),
Some("assistant") => self.translate_assistant(&message["message"]),
Some("user") => self.translate_user(message),