227 lines
8.5 KiB
TypeScript
227 lines
8.5 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { parseCommand, getHelpText, getCommandCompletions, isToolInventoryQuery, PROVIDER_NAMES } from './commands.js';
|
|
import { MODEL_PROVIDERS } from '../../config/index.js';
|
|
|
|
describe('parseCommand', () => {
|
|
it('parses /quit command', () => {
|
|
expect(parseCommand('/quit')).toEqual({ type: 'quit' });
|
|
expect(parseCommand('/exit')).toEqual({ type: 'quit' });
|
|
});
|
|
|
|
it('parses /reset command', () => {
|
|
expect(parseCommand('/reset')).toEqual({ type: 'reset' });
|
|
expect(parseCommand('/clear')).toEqual({ type: 'reset' });
|
|
});
|
|
|
|
it('parses /help command', () => {
|
|
expect(parseCommand('/help')).toEqual({ type: 'help' });
|
|
expect(parseCommand('/?')).toEqual({ type: 'help' });
|
|
});
|
|
|
|
it('parses /status command', () => {
|
|
expect(parseCommand('/status')).toEqual({ type: 'status' });
|
|
});
|
|
|
|
it('parses /tools command', () => {
|
|
expect(parseCommand('/tools')).toEqual({ type: 'tools' });
|
|
});
|
|
|
|
it('parses /research command', () => {
|
|
expect(parseCommand('/research compare k3s and k0s')).toEqual({ type: 'research', task: 'compare k3s and k0s' });
|
|
expect(parseCommand('/research')).toEqual({ type: 'research', task: '' });
|
|
});
|
|
|
|
it('parses /council command', () => {
|
|
expect(parseCommand('/council design backup plan')).toEqual({ type: 'council', task: 'design backup plan' });
|
|
expect(parseCommand('/council preflight')).toEqual({ type: 'council', task: 'preflight' });
|
|
expect(parseCommand('/council')).toEqual({ type: 'council', task: '' });
|
|
});
|
|
|
|
it('parses natural-language council shortcut', () => {
|
|
expect(parseCommand('run council design backup plan')).toEqual({ type: 'council', task: 'design backup plan' });
|
|
expect(parseCommand('yes run the council')).toEqual({ type: 'council', task: '' });
|
|
expect(parseCommand('Run council on #2')).toEqual({ type: 'council', task: '#2' });
|
|
});
|
|
|
|
it('parses /fullscreen command', () => {
|
|
expect(parseCommand('/fullscreen')).toEqual({ type: 'fullscreen' });
|
|
expect(parseCommand('/fs')).toEqual({ type: 'fullscreen' });
|
|
});
|
|
|
|
it('parses /compact command', () => {
|
|
expect(parseCommand('/compact')).toEqual({ type: 'compact' });
|
|
});
|
|
|
|
it('parses /usage command', () => {
|
|
expect(parseCommand('/usage')).toEqual({ type: 'usage' });
|
|
});
|
|
|
|
it('parses /context command', () => {
|
|
expect(parseCommand('/context')).toEqual({ type: 'context' });
|
|
});
|
|
|
|
it('parses /verbose command', () => {
|
|
expect(parseCommand('/verbose')).toEqual({ type: 'verbose' });
|
|
});
|
|
|
|
it('parses /model command without argument', () => {
|
|
expect(parseCommand('/model')).toEqual({ type: 'model' });
|
|
});
|
|
|
|
it('parses /model command with argument', () => {
|
|
expect(parseCommand('/model local')).toEqual({ type: 'model', name: 'local' });
|
|
expect(parseCommand('/model opus')).toEqual({ type: 'model', name: 'opus' });
|
|
});
|
|
|
|
it('parses /model with provider/model', () => {
|
|
expect(parseCommand('/model default anthropic/claude-sonnet-4')).toEqual({
|
|
type: 'model',
|
|
name: 'default',
|
|
providerModel: 'anthropic/claude-sonnet-4',
|
|
});
|
|
expect(parseCommand('/model fast github-copilot/gpt-4o-mini')).toEqual({
|
|
type: 'model',
|
|
name: 'fast',
|
|
providerModel: 'github-copilot/gpt-4o-mini',
|
|
});
|
|
expect(parseCommand('/model complex openai/o3')).toEqual({
|
|
type: 'model',
|
|
name: 'complex',
|
|
providerModel: 'openai/o3',
|
|
});
|
|
});
|
|
|
|
it('still parses /model fast as tier switch (no providerModel)', () => {
|
|
expect(parseCommand('/model fast')).toEqual({ type: 'model', name: 'fast' });
|
|
});
|
|
|
|
it('still parses /model as info (no args)', () => {
|
|
expect(parseCommand('/model')).toEqual({ type: 'model' });
|
|
});
|
|
|
|
it('parses /backend command without argument', () => {
|
|
expect(parseCommand('/backend')).toEqual({ type: 'backend' });
|
|
});
|
|
|
|
it('parses /backend command with argument', () => {
|
|
expect(parseCommand('/backend llamacpp')).toEqual({ type: 'backend', provider: 'llamacpp' });
|
|
expect(parseCommand('/backend ollama')).toEqual({ type: 'backend', provider: 'ollama' });
|
|
});
|
|
|
|
it('parses /transfer command', () => {
|
|
expect(parseCommand('/transfer telegram')).toEqual({ type: 'transfer', target: 'telegram' });
|
|
expect(parseCommand('/transfer')).toEqual({ type: 'transfer', target: '' });
|
|
});
|
|
|
|
it('parses /queue commands', () => {
|
|
expect(parseCommand('/queue')).toEqual({ type: 'queue', action: 'show' });
|
|
expect(parseCommand('/queue show')).toEqual({ type: 'queue', action: 'show' });
|
|
expect(parseCommand('/queue reset')).toEqual({ type: 'queue', action: 'reset' });
|
|
expect(parseCommand('/queue set mode followup')).toEqual({ type: 'queue', action: 'set', args: 'mode followup' });
|
|
});
|
|
|
|
it('parses /elevate command', () => {
|
|
expect(parseCommand('/elevate')).toEqual({ type: 'elevate' });
|
|
expect(parseCommand('/elevate 10m test --yes')).toEqual({ type: 'elevate', args: '10m test --yes' });
|
|
});
|
|
|
|
it('parses regular message', () => {
|
|
expect(parseCommand('Hello Flynn')).toEqual({ type: 'message', content: 'Hello Flynn' });
|
|
});
|
|
|
|
it('returns null for empty input', () => {
|
|
expect(parseCommand('')).toBeNull();
|
|
expect(parseCommand(' ')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('getHelpText', () => {
|
|
it('returns help text with all commands', () => {
|
|
const help = getHelpText();
|
|
expect(help).toContain('/help');
|
|
expect(help).toContain('/model');
|
|
expect(help).toContain('/tools');
|
|
expect(help).toContain('/research');
|
|
expect(help).toContain('/council');
|
|
expect(help).toContain('/reset');
|
|
expect(help).toContain('/compact');
|
|
expect(help).toContain('/usage');
|
|
expect(help).toContain('/context');
|
|
expect(help).toContain('/verbose');
|
|
expect(help).toContain('/queue');
|
|
expect(help).toContain('/elevate');
|
|
expect(help).toContain('/quit');
|
|
});
|
|
});
|
|
|
|
describe('/pair command', () => {
|
|
it('parses /pair as list', () => {
|
|
expect(parseCommand('/pair')).toEqual({ type: 'pair', action: 'list' });
|
|
});
|
|
|
|
it('parses /pair list', () => {
|
|
expect(parseCommand('/pair list')).toEqual({ type: 'pair', action: 'list' });
|
|
});
|
|
|
|
it('parses /pair generate without label', () => {
|
|
expect(parseCommand('/pair generate')).toEqual({ type: 'pair', action: 'generate', args: undefined });
|
|
});
|
|
|
|
it('parses /pair generate with label', () => {
|
|
expect(parseCommand('/pair generate for alice')).toEqual({ type: 'pair', action: 'generate', args: 'for alice' });
|
|
});
|
|
|
|
it('parses /pair revoke with channel and sender', () => {
|
|
expect(parseCommand('/pair revoke telegram 12345')).toEqual({ type: 'pair', action: 'revoke', args: 'telegram 12345' });
|
|
});
|
|
});
|
|
|
|
describe('PROVIDER_NAMES', () => {
|
|
it('matches all providers from the config schema', () => {
|
|
expect(PROVIDER_NAMES).toEqual(MODEL_PROVIDERS);
|
|
});
|
|
|
|
it('includes zhipuai, openrouter, and xai', () => {
|
|
expect(PROVIDER_NAMES).toContain('zhipuai');
|
|
expect(PROVIDER_NAMES).toContain('openrouter');
|
|
expect(PROVIDER_NAMES).toContain('xai');
|
|
});
|
|
});
|
|
|
|
describe('getCommandCompletions', () => {
|
|
it('suggests all providers when typing /model default with partial provider', () => {
|
|
// Typing any character after the tier triggers provider suggestions
|
|
const completions = getCommandCompletions('/model default a');
|
|
expect(completions).toContain('/model default anthropic');
|
|
});
|
|
|
|
it('filters provider suggestions by partial input', () => {
|
|
const completions = getCommandCompletions('/model default zh');
|
|
expect(completions).toEqual(['/model default zhipuai']);
|
|
});
|
|
|
|
it('completes xai provider', () => {
|
|
const completions = getCommandCompletions('/model fast x');
|
|
expect(completions).toEqual(['/model fast xai']);
|
|
});
|
|
|
|
it('completes /council preflight shortcut', () => {
|
|
const completions = getCommandCompletions('/council pre');
|
|
expect(completions).toEqual(['/council preflight']);
|
|
});
|
|
});
|
|
|
|
describe('isToolInventoryQuery', () => {
|
|
it('detects common capability/tool-list prompts', () => {
|
|
expect(isToolInventoryQuery('check your new tools')).toBe(true);
|
|
expect(isToolInventoryQuery('what tools do you have?')).toBe(true);
|
|
expect(isToolInventoryQuery('show capabilities')).toBe(true);
|
|
});
|
|
|
|
it('does not match unrelated prompts', () => {
|
|
expect(isToolInventoryQuery('write a shell script')).toBe(false);
|
|
expect(isToolInventoryQuery('summarize this doc')).toBe(false);
|
|
expect(isToolInventoryQuery('The json by default is up to you, same as for gemini, codex is your tool, so decide what format is best for you to deal with.')).toBe(false);
|
|
});
|
|
});
|