Files
clide/test/builtin/claude/slash_commands_test.dart
T
jpmschweitzerandClaude Opus 4.7 e5fa6302d3
test / unit + widget + golden + a11y (push) Failing after 24s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 26s
handle /resume in clide with a native session picker
Like /clear (T-156), Claude Code's /resume forks to a session the
transcript reader can't follow. clide now owns it: /resume opens a modal
picker of the workspace's recorded sessions — each labelled by its first
… last user prompt and last-active time — and re-binds the pane to the
chosen session-id (killing the current tmux session and respawning on the
picked id). Session enumeration reads bookend prompts from a bounded
window at each end of the transcript, so even multi-MB sessions summarise
cheaply.

T-156.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 14:05:03 +02:00

107 lines
4.1 KiB
Dart

import 'package:clide/builtin/claude/src/slash_commands.dart';
import 'package:test/test.dart';
void main() {
group('slashCommandToken', () {
test('extracts the command word from single-line slash input', () {
expect(slashCommandToken('/model sonnet'), 'model');
expect(slashCommandToken('/whats-next'), 'whats-next');
expect(slashCommandToken('/foo\tbar'), 'foo');
});
test('returns null for non-command input', () {
expect(slashCommandToken('hello'), isNull);
expect(slashCommandToken(' /leading-space'), isNull);
expect(slashCommandToken('/'), isNull); // empty token
expect(slashCommandToken('/foo\nbar'), isNull); // multi-line
});
});
group('isKnownSlashCommand', () {
const known = {'model', 'clear', 'whats-next'};
test('true only when the token is a recognised command', () {
expect(isKnownSlashCommand('/model opus', known), isTrue);
expect(isKnownSlashCommand('/whats-next', known), isTrue);
expect(isKnownSlashCommand('/unknown-cmd', known), isFalse);
});
test('a path-like leading slash is not a command (stays literal)', () {
expect(isKnownSlashCommand('/tmp/foo.log has errors', known), isFalse);
});
test('non-slash and multi-line input is never a command', () {
expect(isKnownSlashCommand('hello world', known), isFalse);
expect(isKnownSlashCommand('/clear\nand more', {'clear'}), isFalse);
});
});
group('clideOwnedCommand', () {
test('recognises /clear and /resume as clide-owned', () {
expect(clideOwnedCommand('/clear'), 'clear');
expect(clideOwnedCommand('/clear '), 'clear');
expect(clideOwnedCommand('/resume'), 'resume');
});
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'));
expect(activeSlashQuery('go /mo', 6), const SlashQuery(start: 3, query: 'mo'));
expect(activeSlashQuery('/', 1), const SlashQuery(start: 0, query: ''));
});
test('no match for paths, post-space, or non-slash runs', () {
expect(activeSlashQuery('a/b', 3), isNull); // slash mid-token (path)
expect(activeSlashQuery('/model sonnet', 13), isNull); // closed after space
expect(activeSlashQuery('hello', 5), isNull);
expect(activeSlashQuery('/model ', 7), isNull); // cursor right after space
});
test('uses the cursor, not the end of text', () {
// Cursor sits right after "/mo" inside "/model".
expect(activeSlashQuery('/model', 3), const SlashQuery(start: 0, query: 'mo'));
});
});
group('filterSlashCommands', () {
const commands = ['model', 'memory', 'clear', 'compact', 'context'];
test('prefix-filters case-insensitively and sorts', () {
expect(filterSlashCommands('co', commands), ['compact', 'context']);
expect(filterSlashCommands('M', commands), ['memory', 'model']);
});
test('empty query returns all (sorted, capped)', () {
expect(filterSlashCommands('', commands, limit: 3), ['clear', 'compact', 'context']);
});
test('de-duplicates', () {
expect(filterSlashCommands('p', ['pql', 'pql', 'plan']), ['plan', 'pql']);
});
});
group('completeSlash', () {
test('replaces the token with /command and a trailing space', () {
const q = SlashQuery(start: 0, query: 'mo');
final r = completeSlash('/mo', q, 'model');
expect(r.text, '/model ');
expect(r.cursor, 7);
});
test('completes an inline token without disturbing surrounding text', () {
const q = SlashQuery(start: 3, query: 'mo');
final r = completeSlash('go /mo now', q, 'model');
expect(r.text, 'go /model now');
expect(r.cursor, 10);
});
});
}