feat(core): add command, intent, and routing primitives
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { CommandRegistry } from './registry.js';
|
||||
|
||||
describe('CommandRegistry', () => {
|
||||
it('registers commands and retrieves by name/alias', () => {
|
||||
const registry = new CommandRegistry();
|
||||
registry.register({
|
||||
name: 'help',
|
||||
aliases: ['h'],
|
||||
description: 'show help',
|
||||
execute: async () => ({ handled: true, text: 'ok' }),
|
||||
});
|
||||
|
||||
expect(registry.get('help')?.name).toBe('help');
|
||||
expect(registry.get('/help')?.name).toBe('help');
|
||||
expect(registry.get('h')?.name).toBe('help');
|
||||
expect(registry.get('/h')?.name).toBe('help');
|
||||
expect(registry.list()).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('parses slash command input', () => {
|
||||
const registry = new CommandRegistry();
|
||||
|
||||
expect(registry.isCommand('/help')).toBe(true);
|
||||
expect(registry.parse('/model fast')).toEqual({
|
||||
name: 'model',
|
||||
args: ['fast'],
|
||||
});
|
||||
expect(registry.parse('hello')).toBeNull();
|
||||
expect(registry.parse('/')).toBeNull();
|
||||
});
|
||||
|
||||
it('executes known command and returns handled result', async () => {
|
||||
const registry = new CommandRegistry();
|
||||
registry.register({
|
||||
name: 'status',
|
||||
description: 'show status',
|
||||
execute: async (_args, ctx) => ({ handled: true, text: `ok:${ctx.channel}` }),
|
||||
});
|
||||
|
||||
const result = await registry.execute('/status', {
|
||||
channel: 'telegram',
|
||||
senderId: 'u1',
|
||||
sessionId: 'telegram:u1',
|
||||
rawInput: '/status',
|
||||
});
|
||||
|
||||
expect(result).toEqual({ handled: true, text: 'ok:telegram' });
|
||||
});
|
||||
|
||||
it('returns handled=false for unknown commands', async () => {
|
||||
const registry = new CommandRegistry();
|
||||
|
||||
const result = await registry.execute('/unknown', {
|
||||
channel: 'telegram',
|
||||
senderId: 'u1',
|
||||
sessionId: 'telegram:u1',
|
||||
rawInput: '/unknown',
|
||||
});
|
||||
|
||||
expect(result).toEqual({ handled: false, text: '' });
|
||||
});
|
||||
|
||||
it('catches handler errors and returns safe message', async () => {
|
||||
const registry = new CommandRegistry();
|
||||
registry.register({
|
||||
name: 'boom',
|
||||
description: 'throws',
|
||||
execute: async () => {
|
||||
throw new Error('bad things');
|
||||
},
|
||||
});
|
||||
|
||||
const result = await registry.execute('/boom', {
|
||||
channel: 'telegram',
|
||||
senderId: 'u1',
|
||||
sessionId: 'telegram:u1',
|
||||
rawInput: '/boom',
|
||||
});
|
||||
|
||||
expect(result.handled).toBe(true);
|
||||
expect(result.text).toContain('Command failed: bad things');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user