From 490bbd10fca0ab3e130c5074f394e8347dc60a39 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 9 Jan 2026 00:01:23 +0100 Subject: [PATCH] feat(telegram): show user id in pairing --- CHANGELOG.md | 1 + src/cli/pairing-cli.test.ts | 64 +++++++++++++++++++++++++++++++++++++ src/cli/pairing-cli.ts | 3 +- src/telegram/bot.test.ts | 3 ++ src/telegram/bot.ts | 4 +++ 5 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/cli/pairing-cli.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d95c11269..a88c16698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - Providers/Doctor: warn when Telegram config expects unmentioned group messages but Bot API privacy mode is likely enabled; surface WhatsApp login/disconnect hints. - Providers/Doctor: add last inbound/outbound activity timestamps in `providers status` and extend `--probe` with Discord channel permission + Telegram group membership audits. - Docs: add provider troubleshooting index (`/providers/troubleshooting`) and link it from the main troubleshooting guide. +- Telegram: include the user id in DM pairing messages and label it clearly in `clawdbot pairing list --provider telegram`. - Apps: refresh iOS/Android/macOS app icons for Clawdbot branding. (#521) — thanks @fishfisher - Docs: expand parameter descriptions for agent/wake hooks. (#532) — thanks @mcinteerj - Docs: add community showcase entries from Discord. (#476) — thanks @gupsammy diff --git a/src/cli/pairing-cli.test.ts b/src/cli/pairing-cli.test.ts new file mode 100644 index 000000000..51735b32f --- /dev/null +++ b/src/cli/pairing-cli.test.ts @@ -0,0 +1,64 @@ +import { Command } from "commander"; +import { describe, expect, it, vi } from "vitest"; + +const listProviderPairingRequests = vi.fn(); + +vi.mock("../pairing/pairing-store.js", () => ({ + listProviderPairingRequests, + approveProviderPairingCode: vi.fn(), +})); + +vi.mock("../telegram/send.js", () => ({ + sendMessageTelegram: vi.fn(), +})); + +vi.mock("../discord/send.js", () => ({ + sendMessageDiscord: vi.fn(), +})); + +vi.mock("../slack/send.js", () => ({ + sendMessageSlack: vi.fn(), +})); + +vi.mock("../signal/send.js", () => ({ + sendMessageSignal: vi.fn(), +})); + +vi.mock("../imessage/send.js", () => ({ + sendMessageIMessage: vi.fn(), +})); + +vi.mock("../config/config.js", () => ({ + loadConfig: vi.fn().mockReturnValue({}), +})); + +vi.mock("../telegram/token.js", () => ({ + resolveTelegramToken: vi.fn().mockReturnValue({ token: "t" }), +})); + +describe("pairing cli", () => { + it("labels Telegram ids as telegramUserId", async () => { + const { registerPairingCli } = await import("./pairing-cli.js"); + listProviderPairingRequests.mockResolvedValueOnce([ + { + id: "123", + code: "ABC123", + createdAt: "2026-01-08T00:00:00Z", + lastSeenAt: "2026-01-08T00:00:00Z", + meta: { username: "peter" }, + }, + ]); + + const log = vi.spyOn(console, "log").mockImplementation(() => {}); + const program = new Command(); + program.name("test"); + registerPairingCli(program); + await program.parseAsync(["pairing", "list", "--provider", "telegram"], { + from: "user", + }); + expect(log).toHaveBeenCalledWith( + expect.stringContaining("telegramUserId=123"), + ); + }); +}); + diff --git a/src/cli/pairing-cli.ts b/src/cli/pairing-cli.ts index d8b4d3cb6..f014e0ef3 100644 --- a/src/cli/pairing-cli.ts +++ b/src/cli/pairing-cli.ts @@ -93,8 +93,9 @@ export function registerPairingCli(program: Command) { } for (const r of requests) { const meta = r.meta ? JSON.stringify(r.meta) : ""; + const idLabel = provider === "telegram" ? "telegramUserId" : "id"; console.log( - `${r.code} id=${r.id}${meta ? ` meta=${meta}` : ""} ${r.createdAt}`, + `${r.code} ${idLabel}=${r.id}${meta ? ` meta=${meta}` : ""} ${r.createdAt}`, ); } }); diff --git a/src/telegram/bot.test.ts b/src/telegram/bot.test.ts index 095bab255..e71cdb5f9 100644 --- a/src/telegram/bot.test.ts +++ b/src/telegram/bot.test.ts @@ -284,6 +284,9 @@ describe("createTelegramBot", () => { expect(replySpy).not.toHaveBeenCalled(); expect(sendMessageSpy).toHaveBeenCalledTimes(1); expect(sendMessageSpy.mock.calls[0]?.[0]).toBe(1234); + expect(String(sendMessageSpy.mock.calls[0]?.[1])).toContain( + "Your Telegram user id: 999", + ); expect(String(sendMessageSpy.mock.calls[0]?.[1])).toContain( "Pairing code:", ); diff --git a/src/telegram/bot.ts b/src/telegram/bot.ts index 91f8f1bc9..5d3f4281c 100644 --- a/src/telegram/bot.ts +++ b/src/telegram/bot.ts @@ -390,8 +390,10 @@ export function createTelegramBot(opts: TelegramBotOptions) { first_name?: string; last_name?: string; username?: string; + id?: number; } | undefined; + const telegramUserId = from?.id ? String(from.id) : candidate; const { code, created } = await upsertTelegramPairingRequest({ chatId: candidate, username: from?.username, @@ -413,6 +415,8 @@ export function createTelegramBot(opts: TelegramBotOptions) { [ "Clawdbot: access not configured.", "", + `Your Telegram user id: ${telegramUserId}`, + "", `Pairing code: ${code}`, "", "Ask the bot owner to approve with:",