260 lines
8.5 KiB
TypeScript
260 lines
8.5 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
|
|
import { createApproveCommand, createApprovalsCommand, createContextCommand, createDenyCommand, createElevateCommand, createModelCommand, createQueueCommand, createResearchCommand, createSkillCommand, createTransferCommand } from './index.js';
|
|
|
|
describe('builtin /model command', () => {
|
|
it('passes through the full argument string', async () => {
|
|
const cmd = createModelCommand();
|
|
const setModel = vi.fn(() => 'ok');
|
|
|
|
const result = await cmd.execute(['default', 'github/gpt-5-mini'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/model default github/gpt-5-mini',
|
|
services: { setModel },
|
|
});
|
|
|
|
expect(setModel).toHaveBeenCalledWith('default github/gpt-5-mini');
|
|
expect(result).toEqual({ handled: true, text: 'ok' });
|
|
});
|
|
|
|
it('still works for single-argument tier switching', async () => {
|
|
const cmd = createModelCommand();
|
|
const setModel = vi.fn(() => 'switched');
|
|
|
|
const result = await cmd.execute(['fast'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/model fast',
|
|
services: { setModel },
|
|
});
|
|
|
|
expect(setModel).toHaveBeenCalledWith('fast');
|
|
expect(result).toEqual({ handled: true, text: 'switched' });
|
|
});
|
|
});
|
|
|
|
describe('builtin /research command', () => {
|
|
it('delegates to the research agent with the full task string', async () => {
|
|
const cmd = createResearchCommand();
|
|
const delegateAgent = vi.fn(() => 'research output');
|
|
|
|
const result = await cmd.execute(['compare', 'k0s', 'vs', 'k3s'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/research compare k0s vs k3s',
|
|
services: { delegateAgent },
|
|
});
|
|
|
|
expect(delegateAgent).toHaveBeenCalledWith('research', 'compare k0s vs k3s');
|
|
expect(result).toEqual({ handled: true, text: 'research output' });
|
|
});
|
|
|
|
it('returns usage when no task is provided', async () => {
|
|
const cmd = createResearchCommand();
|
|
const result = await cmd.execute([], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/research',
|
|
services: {},
|
|
});
|
|
expect(result).toEqual({ handled: true, text: 'Usage: /research <question or task>' });
|
|
});
|
|
});
|
|
|
|
describe('builtin /elevate command', () => {
|
|
it('passes through the full argument string', async () => {
|
|
const cmd = createElevateCommand();
|
|
const setElevation = vi.fn(() => 'ok');
|
|
|
|
const result = await cmd.execute(['10m', 'reason', '--yes'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/elevate 10m reason --yes',
|
|
services: { setElevation },
|
|
});
|
|
|
|
expect(setElevation).toHaveBeenCalledWith('10m reason --yes');
|
|
expect(result).toEqual({ handled: true, text: 'ok' });
|
|
});
|
|
|
|
it('shows status when no args are provided', async () => {
|
|
const cmd = createElevateCommand();
|
|
const getElevation = vi.fn(() => 'status');
|
|
const result = await cmd.execute([], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/elevate',
|
|
services: { getElevation },
|
|
});
|
|
expect(getElevation).toHaveBeenCalledOnce();
|
|
expect(result).toEqual({ handled: true, text: 'status' });
|
|
});
|
|
});
|
|
|
|
describe('builtin /queue command', () => {
|
|
it('shows queue status with no args', async () => {
|
|
const cmd = createQueueCommand();
|
|
const getQueue = vi.fn(() => 'queue status');
|
|
const result = await cmd.execute([], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/queue',
|
|
services: { getQueue },
|
|
});
|
|
expect(getQueue).toHaveBeenCalledOnce();
|
|
expect(result).toEqual({ handled: true, text: 'queue status' });
|
|
});
|
|
|
|
it('passes through set operations', async () => {
|
|
const cmd = createQueueCommand();
|
|
const setQueue = vi.fn(() => 'updated');
|
|
const result = await cmd.execute(['set', 'mode', 'followup'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/queue set mode followup',
|
|
services: { setQueue },
|
|
});
|
|
expect(setQueue).toHaveBeenCalledWith('mode followup');
|
|
expect(result).toEqual({ handled: true, text: 'updated' });
|
|
});
|
|
|
|
it('calls reset operation', async () => {
|
|
const cmd = createQueueCommand();
|
|
const resetQueue = vi.fn(() => 'reset');
|
|
const result = await cmd.execute(['reset'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/queue reset',
|
|
services: { resetQueue },
|
|
});
|
|
expect(resetQueue).toHaveBeenCalledOnce();
|
|
expect(result).toEqual({ handled: true, text: 'reset' });
|
|
});
|
|
});
|
|
|
|
describe('builtin /context command', () => {
|
|
it('returns context usage text from services', async () => {
|
|
const cmd = createContextCommand();
|
|
const getContext = vi.fn(() => 'Context Usage\n\n75.0%');
|
|
const result = await cmd.execute([], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/context',
|
|
services: { getContext },
|
|
});
|
|
expect(getContext).toHaveBeenCalledOnce();
|
|
expect(result).toEqual({ handled: true, text: 'Context Usage\n\n75.0%' });
|
|
});
|
|
|
|
it('returns not-available when service is missing', async () => {
|
|
const cmd = createContextCommand();
|
|
const result = await cmd.execute([], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/context',
|
|
services: {},
|
|
});
|
|
expect(result).toEqual({ handled: true, text: 'Context command is not available in this session.' });
|
|
});
|
|
});
|
|
|
|
describe('builtin /transfer command', () => {
|
|
it('passes through the full target argument string', async () => {
|
|
const cmd = createTransferCommand();
|
|
const transferSession = vi.fn(() => 'Session transferred');
|
|
const result = await cmd.execute(['telegram'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/transfer telegram',
|
|
services: { transferSession },
|
|
});
|
|
expect(transferSession).toHaveBeenCalledWith('telegram');
|
|
expect(result).toEqual({ handled: true, text: 'Session transferred' });
|
|
});
|
|
|
|
it('returns not-available when service is missing', async () => {
|
|
const cmd = createTransferCommand();
|
|
const result = await cmd.execute(['tui'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/transfer tui',
|
|
services: {},
|
|
});
|
|
expect(result).toEqual({ handled: true, text: 'Transfer command is not available in this session.' });
|
|
});
|
|
});
|
|
|
|
describe('builtin approval commands', () => {
|
|
it('calls getApprovals for /approvals', async () => {
|
|
const cmd = createApprovalsCommand();
|
|
const getApprovals = vi.fn(() => '1 pending');
|
|
const result = await cmd.execute([], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/approvals',
|
|
services: { getApprovals },
|
|
});
|
|
expect(getApprovals).toHaveBeenCalledOnce();
|
|
expect(result).toEqual({ handled: true, text: '1 pending' });
|
|
});
|
|
|
|
it('passes raw input to approvePending for /approve', async () => {
|
|
const cmd = createApproveCommand();
|
|
const approvePending = vi.fn(() => 'approved');
|
|
const result = await cmd.execute(['abc-123'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/approve abc-123',
|
|
services: { approvePending },
|
|
});
|
|
expect(approvePending).toHaveBeenCalledWith('abc-123');
|
|
expect(result).toEqual({ handled: true, text: 'approved' });
|
|
});
|
|
|
|
it('passes raw input to denyPending for /deny', async () => {
|
|
const cmd = createDenyCommand();
|
|
const denyPending = vi.fn(() => 'denied');
|
|
const result = await cmd.execute(['abc-123', 'too', 'risky'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/deny abc-123 too risky',
|
|
services: { denyPending },
|
|
});
|
|
expect(denyPending).toHaveBeenCalledWith('abc-123 too risky');
|
|
expect(result).toEqual({ handled: true, text: 'denied' });
|
|
});
|
|
});
|
|
|
|
describe('builtin /skill command', () => {
|
|
it('passes subcommand text to skillCommand service', async () => {
|
|
const cmd = createSkillCommand();
|
|
const skillCommand = vi.fn(() => 'ok');
|
|
const result = await cmd.execute(['search', 'calendar'], {
|
|
channel: 'test',
|
|
senderId: 'user',
|
|
sessionId: 's1',
|
|
rawInput: '/skill search calendar',
|
|
services: { skillCommand },
|
|
});
|
|
expect(skillCommand).toHaveBeenCalledWith('search calendar');
|
|
expect(result).toEqual({ handled: true, text: 'ok' });
|
|
});
|
|
});
|