From a414f8e7f5d436a3b32cf7df0f4826cc5544809a Mon Sep 17 00:00:00 2001 From: Muhammed Mukhthar CM Date: Mon, 26 Jan 2026 07:07:20 +0000 Subject: [PATCH] telegram-user: add config directory listing --- extensions/telegram-user/src/channel.test.ts | 40 ++++++++++- extensions/telegram-user/src/channel.ts | 9 +++ .../telegram-user/src/directory-config.ts | 68 +++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 extensions/telegram-user/src/directory-config.ts diff --git a/extensions/telegram-user/src/channel.test.ts b/extensions/telegram-user/src/channel.test.ts index e114a2312..777a817c8 100644 --- a/extensions/telegram-user/src/channel.test.ts +++ b/extensions/telegram-user/src/channel.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { ClawdbotConfig } from "clawdbot/plugin-sdk"; +import type { ClawdbotConfig, RuntimeEnv } from "clawdbot/plugin-sdk"; const sendMediaTelegramUser = vi.fn< typeof import("./send.js").sendMediaTelegramUser @@ -75,4 +75,42 @@ describe("telegram-user channel plugin", () => { const [, , opts] = sendMediaTelegramUser.mock.calls[0] ?? []; expect(opts).not.toHaveProperty("maxBytes"); }); + + it("lists peers and groups from config like the telegram plugin directory", async () => { + const cfg = { + channels: { + "telegram-user": { + allowFrom: ["123", "@alice", "telegram-user:456", "user:@bob", "*"], + groupAllowFrom: ["tg:carol", 789], + groups: { + "-1001": {}, + "*": {}, + }, + }, + }, + } satisfies Partial as unknown as ClawdbotConfig; + + const mod = await import("./channel.js"); + const runtime = { + log: () => {}, + warn: () => {}, + error: () => {}, + exit: (): never => { + throw new Error("exit called"); + }, + } satisfies RuntimeEnv; + const peers = await mod.telegramUserPlugin.directory?.listPeers?.({ + cfg, + runtime, + }); + const groups = await mod.telegramUserPlugin.directory?.listGroups?.({ + cfg, + runtime, + }); + + expect(peers?.map((p) => p.id).sort()).toEqual( + ["123", "456", "@alice", "@bob", "@carol", "789"].sort(), + ); + expect(groups?.map((g) => g.id)).toEqual(["-1001"]); + }); }); diff --git a/extensions/telegram-user/src/channel.ts b/extensions/telegram-user/src/channel.ts index 161f6fae0..ab545bf24 100644 --- a/extensions/telegram-user/src/channel.ts +++ b/extensions/telegram-user/src/channel.ts @@ -23,6 +23,10 @@ import { type ResolvedTelegramUserAccount, } from "./accounts.js"; import { TelegramUserConfigSchema } from "./config-schema.js"; +import { + listTelegramUserDirectoryGroupsFromConfig, + listTelegramUserDirectoryPeersFromConfig, +} from "./directory-config.js"; import { loginTelegramUser } from "./login.js"; import { monitorTelegramUserProvider } from "./monitor/index.js"; import { @@ -117,6 +121,11 @@ export const telegramUserPlugin: ChannelPlugin = { hint: "", }, }, + directory: { + self: async () => null, + listPeers: async (params) => listTelegramUserDirectoryPeersFromConfig(params), + listGroups: async (params) => listTelegramUserDirectoryGroupsFromConfig(params), + }, reload: { configPrefixes: ["channels.telegram-user"] }, configSchema: buildChannelConfigSchema(TelegramUserConfigSchema), config: { diff --git a/extensions/telegram-user/src/directory-config.ts b/extensions/telegram-user/src/directory-config.ts new file mode 100644 index 000000000..e28755e63 --- /dev/null +++ b/extensions/telegram-user/src/directory-config.ts @@ -0,0 +1,68 @@ +import type { ChannelDirectoryEntry, ClawdbotConfig } from "clawdbot/plugin-sdk"; + +import { resolveTelegramUserAccount } from "./accounts.js"; +import type { CoreConfig } from "./types.js"; + +export type TelegramUserDirectoryConfigParams = { + cfg: ClawdbotConfig; + accountId?: string | null; + query?: string | null; + limit?: number | null; +}; + +function normalizePeerEntry(raw: string): string | null { + const trimmed = raw.trim(); + if (!trimmed) return null; + const cleaned = trimmed + .replace(/^(telegram-user|telegram|tg):/i, "") + .replace(/^user:/i, "") + .trim(); + if (!cleaned) return null; + if (/^-?\d+$/.test(cleaned)) return cleaned; + const withoutAt = cleaned.replace(/^@/, ""); + if (!withoutAt) return null; + return `@${withoutAt}`; +} + +export async function listTelegramUserDirectoryPeersFromConfig( + params: TelegramUserDirectoryConfigParams, +): Promise { + const account = resolveTelegramUserAccount({ + cfg: params.cfg as CoreConfig, + accountId: params.accountId, + }); + const q = params.query?.trim().toLowerCase() || ""; + const raw = [ + ...(account.config.allowFrom ?? []).map((entry) => String(entry)), + ...(account.config.groupAllowFrom ?? []).map((entry) => String(entry)), + ]; + return Array.from( + new Set( + raw + .map((entry) => entry.trim()) + .filter((entry) => Boolean(entry) && entry !== "*"), + ), + ) + .map((entry) => normalizePeerEntry(entry)) + .filter((id): id is string => Boolean(id)) + .filter((id) => (q ? id.toLowerCase().includes(q) : true)) + .slice(0, params.limit && params.limit > 0 ? params.limit : undefined) + .map((id) => ({ kind: "user", id }) as const); +} + +export async function listTelegramUserDirectoryGroupsFromConfig( + params: TelegramUserDirectoryConfigParams, +): Promise { + const account = resolveTelegramUserAccount({ + cfg: params.cfg as CoreConfig, + accountId: params.accountId, + }); + const q = params.query?.trim().toLowerCase() || ""; + return Object.keys(account.config.groups ?? {}) + .map((id) => id.trim()) + .filter((id) => Boolean(id) && id !== "*") + .filter((id) => (q ? id.toLowerCase().includes(q) : true)) + .slice(0, params.limit && params.limit > 0 ? params.limit : undefined) + .map((id) => ({ kind: "group", id }) as const); +} +