feat: add Telegram confirmation UI components
Implements Phase 2 Task 7 - Telegram Confirmation UI: - formatConfirmationMessage(): formats tool and args into readable message - createConfirmationKeyboard(): creates approve/deny inline keyboard - parseConfirmationCallback(): parses callback data from button clicks - Full test coverage with vitest All tests passing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { formatConfirmationMessage, parseConfirmationCallback } from './confirmations.js';
|
||||
|
||||
describe('formatConfirmationMessage', () => {
|
||||
it('formats tool and args into readable message', () => {
|
||||
const message = formatConfirmationMessage('shell.exec', { cmd: 'ls -la' });
|
||||
|
||||
expect(message).toContain('shell.exec');
|
||||
expect(message).toContain('ls -la');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseConfirmationCallback', () => {
|
||||
it('parses approve callback data', () => {
|
||||
const result = parseConfirmationCallback('confirm:abc123:approve');
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'abc123',
|
||||
approved: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('parses deny callback data', () => {
|
||||
const result = parseConfirmationCallback('confirm:abc123:deny');
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'abc123',
|
||||
approved: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns null for invalid callback data', () => {
|
||||
expect(parseConfirmationCallback('invalid')).toBeNull();
|
||||
expect(parseConfirmationCallback('other:data')).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { InlineKeyboard } from 'grammy';
|
||||
|
||||
export function formatConfirmationMessage(tool: string, args: Record<string, unknown>): string {
|
||||
const argsStr = Object.entries(args)
|
||||
.map(([key, value]) => ` ${key}: ${JSON.stringify(value)}`)
|
||||
.join('\n');
|
||||
|
||||
return `🔐 **Confirmation Required**
|
||||
|
||||
Tool: \`${tool}\`
|
||||
Arguments:
|
||||
${argsStr || ' (none)'}
|
||||
|
||||
Approve this action?`;
|
||||
}
|
||||
|
||||
export function createConfirmationKeyboard(confirmationId: string): InlineKeyboard {
|
||||
return new InlineKeyboard()
|
||||
.text('✅ Approve', `confirm:${confirmationId}:approve`)
|
||||
.text('❌ Deny', `confirm:${confirmationId}:deny`);
|
||||
}
|
||||
|
||||
export interface ConfirmationCallbackData {
|
||||
id: string;
|
||||
approved: boolean;
|
||||
}
|
||||
|
||||
export function parseConfirmationCallback(data: string): ConfirmationCallbackData | null {
|
||||
const parts = data.split(':');
|
||||
if (parts.length !== 3 || parts[0] !== 'confirm') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [, id, action] = parts;
|
||||
if (action !== 'approve' && action !== 'deny') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
approved: action === 'approve',
|
||||
};
|
||||
}
|
||||
@@ -1,2 +1,8 @@
|
||||
export { createTelegramBot, type TelegramBotConfig } from './bot.js';
|
||||
export { isAllowedChat, createMessageHandler, createResetHandler } from './handlers.js';
|
||||
export {
|
||||
formatConfirmationMessage,
|
||||
createConfirmationKeyboard,
|
||||
parseConfirmationCallback,
|
||||
type ConfirmationCallbackData,
|
||||
} from './confirmations.js';
|
||||
|
||||
Reference in New Issue
Block a user