feat: make /transfer bidirectional across telegram and tui

This commit is contained in:
William Valentin
2026-02-18 07:55:08 -08:00
parent d48adbe0b0
commit 16af5e75fd
13 changed files with 262 additions and 17 deletions
+31 -2
View File
@@ -78,13 +78,14 @@ describe('TelegramAdapter', () => {
// .use() for auth middleware
expect(mockUse).toHaveBeenCalledTimes(1);
// .command() for /start, /reset, /model, /local, /cloud
expect(mockCommand).toHaveBeenCalledTimes(5);
// .command() for /start, /reset, /model, /local, /cloud, /transfer
expect(mockCommand).toHaveBeenCalledTimes(6);
expect(mockCommand.mock.calls[0][0]).toBe('start');
expect(mockCommand.mock.calls[1][0]).toBe('reset');
expect(mockCommand.mock.calls[2][0]).toBe('model');
expect(mockCommand.mock.calls[3][0]).toBe('local');
expect(mockCommand.mock.calls[4][0]).toBe('cloud');
expect(mockCommand.mock.calls[5][0]).toBe('transfer');
// .on('message:text', ...) for text handler
expect(mockOn).toHaveBeenCalledWith('message:text', expect.any(Function));
// .start() to begin long polling
@@ -269,6 +270,34 @@ describe('TelegramAdapter', () => {
});
});
it('/transfer command strips @bot suffix in groups', async () => {
const handler = vi.fn();
adapter.onMessage(handler);
await adapter.connect();
const transferCall = mockCommand.mock.calls.find((call) => call[0] === 'transfer');
expect(transferCall).toBeDefined();
const transferHandler = getCommandHandler('transfer');
const ctx = {
message: { message_id: 124, text: '/transfer@flynn_bot tui' },
chat: { id: 100 },
from: { first_name: 'Will' },
};
await transferHandler(ctx);
expect(handler).toHaveBeenCalledTimes(1);
const msg: InboundMessage = handler.mock.calls[0][0];
expect(msg.text).toBe('/transfer tui');
expect(msg.metadata).toEqual({
isCommand: true,
command: 'transfer',
commandArgs: 'tui',
});
});
// ── Auth middleware ───────────────────────────────────────────
it('auth middleware blocks unauthorized chat IDs', async () => {
+22
View File
@@ -210,6 +210,28 @@ export class TelegramAdapter implements ChannelAdapter {
});
});
this.bot.command('transfer', async (ctx) => {
if (!this.messageHandler) {return;}
// Telegram can deliver group commands in the form: /transfer@bot_username ...
// Strip optional @mention for consistent parsing across contexts.
const args = ctx.message?.text?.replace(/^\/transfer(?:@\S+)?\s*/i, '').trim() ?? '';
this.messageHandler({
id: String(ctx.message?.message_id ?? Date.now()),
channel: 'telegram',
senderId: String(ctx.chat.id),
senderName: ctx.from?.first_name,
text: `/transfer ${args}`.trim(),
timestamp: Date.now(),
metadata: {
isCommand: true,
command: 'transfer',
commandArgs: args || undefined,
},
});
});
// ── Text message handler ──
this.bot.on('message:text', async (ctx) => {