diff --git a/CHANGELOG.md b/CHANGELOG.md index abe4a9bbf7..dcfbf9fe70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ Docs: https://docs.openclaw.ai - Telegram: render markdown spoilers with `` HTML tags. (#11543) Thanks @ezhikkk. - Telegram: truncate command registration to 100 entries to avoid `BOT_COMMANDS_TOO_MUCH` failures on startup. (#12356) Thanks @arosstale. - Telegram: match DM `allowFrom` against sender user id (fallback to chat id) and clarify pairing logs. (#12779) Thanks @liuxiaopai-ai. +- Pairing/Telegram: include the actual pairing code in approve commands, route Telegram pairing replies through the shared pairing message builder, and add regression checks to prevent `` placeholder drift. - Onboarding: QuickStart now auto-installs shell completion (prompt only in Manual). - Docker: make `docker-setup.sh` compatible with macOS Bash 3.2 and empty extra mounts. (#9441) Thanks @mateusz-michalik. - Auth: strip embedded line breaks from pasted API keys and tokens before storing/resolving credentials. diff --git a/src/pairing/pairing-messages.test.ts b/src/pairing/pairing-messages.test.ts index d12be19c3a..e63083560a 100644 --- a/src/pairing/pairing-messages.test.ts +++ b/src/pairing/pairing-messages.test.ts @@ -18,6 +18,11 @@ describe("buildPairingReply", () => { }); const cases = [ + { + channel: "telegram", + idLine: "Your Telegram user id: 42", + code: "QRS678", + }, { channel: "discord", idLine: "Your Discord user id: 1", diff --git a/src/telegram/bot-message-context.ts b/src/telegram/bot-message-context.ts index 8f52c6b513..710b38ed5a 100644 --- a/src/telegram/bot-message-context.ts +++ b/src/telegram/bot-message-context.ts @@ -25,11 +25,11 @@ import { formatLocationText, toLocationContext } from "../channels/location.js"; import { logInboundDrop } from "../channels/logging.js"; import { resolveMentionGatingWithBypass } from "../channels/mention-gating.js"; import { recordInboundSession } from "../channels/session.js"; -import { formatCliCommand } from "../cli/command-format.js"; import { loadConfig } from "../config/config.js"; import { readSessionUpdatedAt, resolveStorePath } from "../config/sessions.js"; import { logVerbose, shouldLogVerbose } from "../globals.js"; import { recordChannelActivity } from "../infra/channel-activity.js"; +import { buildPairingReply } from "../pairing/pairing-messages.js"; import { upsertChannelPairingRequest } from "../pairing/pairing-store.js"; import { resolveAgentRoute } from "../routing/resolve-route.js"; import { resolveThreadSessionKeys } from "../routing/session-key.js"; @@ -281,16 +281,11 @@ export const buildTelegramMessageContext = async ({ fn: () => bot.api.sendMessage( chatId, - [ - "OpenClaw: access not configured.", - "", - `Your Telegram user id: ${telegramUserId}`, - "", - `Pairing code: ${code}`, - "", - "Ask the bot owner to approve with:", - formatCliCommand(`openclaw pairing approve telegram ${code}`), - ].join("\n"), + buildPairingReply({ + channel: "telegram", + idLine: `Your Telegram user id: ${telegramUserId}`, + code, + }), ), }); } diff --git a/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts b/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts index 292c257fa8..1b43886f19 100644 --- a/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts +++ b/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts @@ -378,9 +378,12 @@ 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:"); - expect(String(sendMessageSpy.mock.calls[0]?.[1])).toContain("PAIRME12"); + const pairingText = String(sendMessageSpy.mock.calls[0]?.[1]); + expect(pairingText).toContain("Your Telegram user id: 999"); + expect(pairingText).toContain("Pairing code:"); + expect(pairingText).toContain("PAIRME12"); + expect(pairingText).toContain("openclaw pairing approve telegram PAIRME12"); + expect(pairingText).not.toContain(""); }); it("does not resend pairing code when a request is already pending", async () => { onSpy.mockReset(); diff --git a/src/telegram/bot.test.ts b/src/telegram/bot.test.ts index 05b6590914..3c2c63a7d4 100644 --- a/src/telegram/bot.test.ts +++ b/src/telegram/bot.test.ts @@ -591,9 +591,12 @@ 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:"); - expect(String(sendMessageSpy.mock.calls[0]?.[1])).toContain("PAIRME12"); + const pairingText = String(sendMessageSpy.mock.calls[0]?.[1]); + expect(pairingText).toContain("Your Telegram user id: 999"); + expect(pairingText).toContain("Pairing code:"); + expect(pairingText).toContain("PAIRME12"); + expect(pairingText).toContain("openclaw pairing approve telegram PAIRME12"); + expect(pairingText).not.toContain(""); }); it("does not resend pairing code when a request is already pending", async () => {