handle /clear in clide: reset to a fresh session instead of forwarding

Claude Code's /clear forks the conversation to a new session-id, which
clide's transcript reader (pinned to the spawn --session-id) can't
follow — so after /clear the pane froze on the old transcript and looked
dead. clide now owns /clear: it's intercepted in the composer's send
path (never forwarded to tmux), tears the pane's session down, and
respawns a fresh empty one. A new session-id is forced even for the
primary so it starts empty rather than resuming the old transcript;
_spawn's self-heal kills the stale tmux session. The old transcript is
left on disk.

Known follow-up (T-156): /resume and /compact have the same forking
problem but need different handling (a session picker, not a wipe).

T-156.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 13:36:01 +02:00
co-authored by Claude Opus 4.7
parent f6a5d72ccd
commit c4cc68ad2e
6 changed files with 79 additions and 0 deletions
@@ -36,6 +36,20 @@ void main() {
});
});
group('clideOwnedCommand', () {
test('recognises /clear as clide-owned', () {
expect(clideOwnedCommand('/clear'), 'clear');
expect(clideOwnedCommand('/clear '), 'clear');
});
test('returns null for commands clide forwards to Claude', () {
expect(clideOwnedCommand('/model sonnet'), isNull);
expect(clideOwnedCommand('/compact'), isNull);
expect(clideOwnedCommand('not a command'), isNull);
expect(clideOwnedCommand('/clearairspace'), isNull); // token must be exactly "clear"
});
});
group('activeSlashQuery', () {
test('matches a slash token at the cursor, including inline', () {
expect(activeSlashQuery('/mod', 4), const SlashQuery(start: 0, query: 'mod'));