From 213dba855ad5c057ce13be3dffd9b74f02be1052 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Tue, 10 Feb 2026 09:27:18 -0800 Subject: [PATCH] refactor: make telegram config optional for non-telegram setups Co-Authored-By: Claude Opus 4.6 --- src/cli/doctor.ts | 3 +++ src/cli/shared.test.ts | 2 +- src/cli/start.ts | 4 +++- src/cli/tui.ts | 10 +++++++--- src/config/loader.test.ts | 12 ++++++------ src/config/schema.ts | 2 +- src/daemon/channels.ts | 20 +++++++++++--------- 7 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/cli/doctor.ts b/src/cli/doctor.ts index c3a7930..2897886 100644 --- a/src/cli/doctor.ts +++ b/src/cli/doctor.ts @@ -163,6 +163,9 @@ const checkTelegram: Check = async (ctx) => { if (!ctx.config) { return { status: 'skip', label: 'Telegram bot configured', detail: '(config invalid)' }; } + if (!ctx.config.telegram) { + return { status: 'skip', label: 'Telegram bot configured', detail: '(not configured)' }; + } if (!ctx.config.telegram.bot_token || ctx.config.telegram.bot_token.length < 10) { return { status: 'warn', label: 'Telegram bot configured', detail: 'token looks too short' }; } diff --git a/src/cli/shared.test.ts b/src/cli/shared.test.ts index b52607a..f572445 100644 --- a/src/cli/shared.test.ts +++ b/src/cli/shared.test.ts @@ -50,7 +50,7 @@ models: const result = loadConfigSafe(configPath); expect(result.config).toBeDefined(); expect(result.error).toBeUndefined(); - expect(result.config!.telegram.bot_token).toBe('test-token'); + expect(result.config!.telegram?.bot_token).toBe('test-token'); }); it('returns error when file not found', () => { diff --git a/src/cli/start.ts b/src/cli/start.ts index 6d46e2e..fa6c42c 100644 --- a/src/cli/start.ts +++ b/src/cli/start.ts @@ -29,7 +29,9 @@ export function registerStartCommand(program: Command): void { const { startDaemon } = await import('../daemon/index.js'); const daemon = await startDaemon(config); - console.log(`Allowed Telegram chat IDs: ${config.telegram.allowed_chat_ids.join(', ')}`); + if (config.telegram) { + console.log(`Allowed Telegram chat IDs: ${config.telegram.allowed_chat_ids.join(', ')}`); + } // Keep process alive await new Promise((resolve) => { diff --git a/src/cli/tui.ts b/src/cli/tui.ts index c4795a2..b8aa360 100644 --- a/src/cli/tui.ts +++ b/src/cli/tui.ts @@ -154,9 +154,13 @@ export function registerTuiCommand(program: Command): void { currentLocalProvider: config.models.local?.provider, onTransfer: (target) => { if (target === 'telegram') { - const telegramUserId = String(config.telegram.allowed_chat_ids[0]); - sessionManager.transferSession('tui', 'local', 'telegram', telegramUserId); - console.log(`Session transferred to Telegram (${telegramUserId})\n`); + if (config.telegram && config.telegram.allowed_chat_ids.length > 0) { + const telegramUserId = String(config.telegram.allowed_chat_ids[0]); + sessionManager.transferSession('tui', 'local', 'telegram', telegramUserId); + console.log(`Session transferred to Telegram (${telegramUserId})\n`); + } else { + console.log('Telegram not configured\n'); + } } else { console.log(`Unknown transfer target: ${target}\n`); } diff --git a/src/config/loader.test.ts b/src/config/loader.test.ts index e2eeeae..f2d2b5e 100644 --- a/src/config/loader.test.ts +++ b/src/config/loader.test.ts @@ -58,8 +58,8 @@ models: const config = loadConfig(configPath); - expect(config.telegram.bot_token).toBe('test-token'); - expect(config.telegram.allowed_chat_ids).toContain(123456789); + expect(config.telegram?.bot_token).toBe('test-token'); + expect(config.telegram?.allowed_chat_ids).toContain(123456789); expect(config.server.port).toBe(18800); expect(config.models.default.provider).toBe('anthropic'); @@ -84,7 +84,7 @@ models: const config = loadConfig(configPath); - expect(config.telegram.bot_token).toBe('env-token-value'); + expect(config.telegram?.bot_token).toBe('env-token-value'); delete process.env.TEST_BOT_TOKEN; rmSync(testDir, { recursive: true }); @@ -137,7 +137,7 @@ server: const config = loadConfig(basePath, overlayPath); expect(config.server.port).toBe(9999); - expect(config.telegram.bot_token).toBe('base-token'); + expect(config.telegram?.bot_token).toBe('base-token'); }); it('loads base-only when no overlay provided', () => { @@ -157,7 +157,7 @@ models: `); const config = loadConfig(basePath); - expect(config.telegram.bot_token).toBe('base-only-token'); + expect(config.telegram?.bot_token).toBe('base-only-token'); expect(config.server.port).toBe(18800); }); @@ -186,7 +186,7 @@ models: `); const config = loadConfig(basePath, overlayPath); - expect(config.telegram.bot_token).toBe('expanded-token'); + expect(config.telegram?.bot_token).toBe('expanded-token'); expect(config.models.default.model).toBe('gpt-4o'); }); diff --git a/src/config/schema.ts b/src/config/schema.ts index 7ff80ad..cb41148 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -349,7 +349,7 @@ const logLevelSchema = z.enum(['debug', 'info', 'warn', 'error', 'silent']).defa export const configSchema = z.object({ log_level: logLevelSchema, - telegram: telegramSchema, + telegram: telegramSchema.optional(), discord: discordSchema, slack: slackSchema, whatsapp: whatsappSchema, diff --git a/src/daemon/channels.ts b/src/daemon/channels.ts index ee581a2..15280c3 100644 --- a/src/daemon/channels.ts +++ b/src/daemon/channels.ts @@ -21,15 +21,17 @@ export interface ChannelsResult { export function registerChannels(deps: ChannelsDeps): ChannelsResult { const { config, channelRegistry, hookEngine, pairingManager, gateway } = deps; - // Register Telegram adapter - const telegramAdapter = new TelegramAdapter({ - botToken: config.telegram.bot_token, - allowedChatIds: config.telegram.allowed_chat_ids, - requireMention: config.telegram.require_mention, - hookEngine, - pairingManager, - }); - channelRegistry.register(telegramAdapter); + // Register Telegram adapter (if configured) + if (config.telegram) { + const telegramAdapter = new TelegramAdapter({ + botToken: config.telegram.bot_token, + allowedChatIds: config.telegram.allowed_chat_ids, + requireMention: config.telegram.require_mention, + hookEngine, + pairingManager, + }); + channelRegistry.register(telegramAdapter); + } // Register Discord adapter (if configured) if (config.discord) {