negotium 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/dist/canonical-mcp-bridge.js +2 -3
  2. package/dist/canonical-mcp-bridge.js.map +1 -1
  3. package/dist/chunk-a9y2rwxf.js.map +1 -1
  4. package/dist/{chunk-j0kjscb7.js → chunk-s2gez3wg.js} +20 -2
  5. package/dist/{chunk-j0kjscb7.js.map → chunk-s2gez3wg.js.map} +2 -2
  6. package/dist/cron.js +49 -25
  7. package/dist/cron.js.map +15 -14
  8. package/dist/hosted-agent.js +3012 -17
  9. package/dist/hosted-agent.js.map +30 -3
  10. package/dist/main.js +31323 -36
  11. package/dist/main.js.map +198 -3
  12. package/dist/prompts.js +11 -8
  13. package/dist/prompts.js.map +4 -4
  14. package/dist/runtime/src/application/submit-user-message.ts +3 -0
  15. package/dist/runtime/src/index.ts +7 -0
  16. package/dist/runtime/src/mcp/runtime-spec.ts +3 -0
  17. package/dist/runtime/src/mcp/session-comm/server.ts +1 -1
  18. package/dist/runtime/src/platform/mcp-config.ts +13 -0
  19. package/dist/runtime/src/prompts/builders.ts +20 -6
  20. package/dist/runtime/src/query/active-rooms.ts +2 -0
  21. package/dist/runtime/src/runtime/delivery-ack.ts +112 -0
  22. package/dist/runtime/src/runtime/errors.ts +12 -12
  23. package/dist/runtime/src/runtime/turn-runner.ts +12 -0
  24. package/dist/runtime/src/storage/runtime-turn-requests.ts +1 -0
  25. package/dist/runtime/src/types/api.ts +2 -0
  26. package/dist/runtime/src/types.ts +2 -0
  27. package/dist/runtime/src/version.ts +1 -1
  28. package/dist/runtime-helpers.js.map +1 -1
  29. package/dist/storage.js.map +1 -1
  30. package/dist/types/packages/core/src/mcp/runtime-spec.d.ts +2 -0
  31. package/dist/types/packages/core/src/platform/mcp-config.d.ts +4 -0
  32. package/dist/types/packages/core/src/prompts/builders.d.ts +2 -0
  33. package/dist/types/packages/core/src/types/api.d.ts +2 -0
  34. package/dist/types/packages/core/src/types.d.ts +2 -0
  35. package/dist/types/packages/core/src/version.d.ts +1 -1
  36. package/dist/vault.js.map +1 -1
  37. package/package.json +1 -1
  38. package/dist/chunk-00q25k7p.js +0 -2387
  39. package/dist/chunk-00q25k7p.js.map +0 -26
  40. package/dist/chunk-03kv7mvj.js +0 -2152
  41. package/dist/chunk-03kv7mvj.js.map +0 -15
  42. package/dist/chunk-05pm51dh.js +0 -589
  43. package/dist/chunk-05pm51dh.js.map +0 -11
  44. package/dist/chunk-0eh16bk1.js +0 -2936
  45. package/dist/chunk-0eh16bk1.js.map +0 -20
  46. package/dist/chunk-0yfqyv88.js +0 -108
  47. package/dist/chunk-0yfqyv88.js.map +0 -10
  48. package/dist/chunk-1k7t7bnx.js +0 -97
  49. package/dist/chunk-1k7t7bnx.js.map +0 -10
  50. package/dist/chunk-3gkfr9vb.js +0 -431
  51. package/dist/chunk-3gkfr9vb.js.map +0 -11
  52. package/dist/chunk-5akd1gbj.js +0 -281
  53. package/dist/chunk-5akd1gbj.js.map +0 -10
  54. package/dist/chunk-7k19pcg8.js +0 -577
  55. package/dist/chunk-7k19pcg8.js.map +0 -14
  56. package/dist/chunk-81tbfbmt.js +0 -10
  57. package/dist/chunk-81tbfbmt.js.map +0 -10
  58. package/dist/chunk-82qhv1mq.js +0 -512
  59. package/dist/chunk-82qhv1mq.js.map +0 -13
  60. package/dist/chunk-8dy7e2a9.js +0 -103
  61. package/dist/chunk-8dy7e2a9.js.map +0 -10
  62. package/dist/chunk-8f2sqmrj.js +0 -1712
  63. package/dist/chunk-8f2sqmrj.js.map +0 -18
  64. package/dist/chunk-9hjeemfz.js +0 -372
  65. package/dist/chunk-9hjeemfz.js.map +0 -10
  66. package/dist/chunk-a4aa2ccv.js +0 -141
  67. package/dist/chunk-a4aa2ccv.js.map +0 -10
  68. package/dist/chunk-bsg215q3.js +0 -3536
  69. package/dist/chunk-bsg215q3.js.map +0 -20
  70. package/dist/chunk-bxnfsc7w.js +0 -58
  71. package/dist/chunk-bxnfsc7w.js.map +0 -10
  72. package/dist/chunk-c500xe9z.js +0 -33
  73. package/dist/chunk-c500xe9z.js.map +0 -10
  74. package/dist/chunk-cngrf7ab.js +0 -149
  75. package/dist/chunk-cngrf7ab.js.map +0 -10
  76. package/dist/chunk-d7tprf06.js +0 -53
  77. package/dist/chunk-d7tprf06.js.map +0 -10
  78. package/dist/chunk-ddnrmkrv.js +0 -61
  79. package/dist/chunk-ddnrmkrv.js.map +0 -10
  80. package/dist/chunk-edb07sjp.js +0 -567
  81. package/dist/chunk-edb07sjp.js.map +0 -14
  82. package/dist/chunk-ejcm6zx8.js +0 -591
  83. package/dist/chunk-ejcm6zx8.js.map +0 -11
  84. package/dist/chunk-ezs352qs.js +0 -237
  85. package/dist/chunk-ezs352qs.js.map +0 -11
  86. package/dist/chunk-f5xgprg1.js +0 -59
  87. package/dist/chunk-f5xgprg1.js.map +0 -10
  88. package/dist/chunk-fbtb3v0s.js +0 -1339
  89. package/dist/chunk-fbtb3v0s.js.map +0 -16
  90. package/dist/chunk-ffefbd3r.js +0 -17
  91. package/dist/chunk-ffefbd3r.js.map +0 -10
  92. package/dist/chunk-gaknyw04.js +0 -708
  93. package/dist/chunk-gaknyw04.js.map +0 -14
  94. package/dist/chunk-gxmny6tq.js +0 -1637
  95. package/dist/chunk-gxmny6tq.js.map +0 -15
  96. package/dist/chunk-h7bj5zwb.js +0 -3069
  97. package/dist/chunk-h7bj5zwb.js.map +0 -32
  98. package/dist/chunk-hp4g7wx7.js +0 -46
  99. package/dist/chunk-hp4g7wx7.js.map +0 -10
  100. package/dist/chunk-hwy3n31w.js +0 -21
  101. package/dist/chunk-hwy3n31w.js.map +0 -9
  102. package/dist/chunk-jzz91jwh.js +0 -70
  103. package/dist/chunk-jzz91jwh.js.map +0 -10
  104. package/dist/chunk-k778y16p.js +0 -153
  105. package/dist/chunk-k778y16p.js.map +0 -11
  106. package/dist/chunk-mh5mexsf.js +0 -147
  107. package/dist/chunk-mh5mexsf.js.map +0 -11
  108. package/dist/chunk-mnwaext5.js +0 -318
  109. package/dist/chunk-mnwaext5.js.map +0 -10
  110. package/dist/chunk-nkgs40ch.js +0 -23
  111. package/dist/chunk-nkgs40ch.js.map +0 -10
  112. package/dist/chunk-pz57vwsm.js +0 -250
  113. package/dist/chunk-pz57vwsm.js.map +0 -11
  114. package/dist/chunk-r6kdp7gn.js +0 -252
  115. package/dist/chunk-r6kdp7gn.js.map +0 -10
  116. package/dist/chunk-rkvrkcgx.js +0 -117
  117. package/dist/chunk-rkvrkcgx.js.map +0 -10
  118. package/dist/chunk-s74rdyqe.js +0 -117
  119. package/dist/chunk-s74rdyqe.js.map +0 -12
  120. package/dist/chunk-sa874j5c.js +0 -9
  121. package/dist/chunk-sa874j5c.js.map +0 -10
  122. package/dist/chunk-sffqdkvq.js +0 -122
  123. package/dist/chunk-sffqdkvq.js.map +0 -10
  124. package/dist/chunk-tcs9qjps.js +0 -64
  125. package/dist/chunk-tcs9qjps.js.map +0 -10
  126. package/dist/chunk-wx83ep8e.js +0 -131
  127. package/dist/chunk-wx83ep8e.js.map +0 -10
  128. package/dist/chunk-xag86ng3.js +0 -122
  129. package/dist/chunk-xag86ng3.js.map +0 -10
  130. package/dist/chunk-xfdkep71.js +0 -371
  131. package/dist/chunk-xfdkep71.js.map +0 -11
  132. package/dist/chunk-xhm1rfpt.js +0 -2907
  133. package/dist/chunk-xhm1rfpt.js.map +0 -24
  134. package/dist/chunk-xpcps28p.js +0 -2138
  135. package/dist/chunk-xpcps28p.js.map +0 -29
  136. package/dist/chunk-yb4rbev9.js +0 -214
  137. package/dist/chunk-yb4rbev9.js.map +0 -10
@@ -1,15 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../adapters/telegram/src/cli.ts", "../../../adapters/telegram/src/adapter.ts", "../../../packages/adapter-sdk/src/outbox.ts", "../../../adapters/telegram/src/mapping-store.ts", "../../../adapters/telegram/src/render.ts", "../../../adapters/telegram/src/index.ts"],
4
- "sourcesContent": [
5
- "#!/usr/bin/env bun\n\nimport type { NegotiumAdapterHandle } from \"@negotium/adapter-sdk\";\nimport { isAgentKind, onShutdown, waitForRequiredRuntimeProcessLease } from \"@negotium/core\";\nimport { type NodeHandle, startDefaultNode } from \"@negotium/node\";\nimport TelegramBot from \"node-telegram-bot-api\";\nimport { startTelegramAdapter, type TelegramAdapterHandle } from \"@/index\";\n\nexport interface TelegramEnvironmentHandle extends NegotiumAdapterHandle<\"telegram\"> {\n readonly adapter: TelegramAdapterHandle;\n readonly bot: TelegramBot;\n}\n\n/** Start only the Telegram channel. The embedding host owns the Negotium node. */\nexport function startTelegramFromEnv(): TelegramEnvironmentHandle {\n const token = process.env.TELEGRAM_BOT_TOKEN?.trim();\n if (!token) throw new Error(\"TELEGRAM_BOT_TOKEN is required\");\n\n const bot = new TelegramBot(token, { polling: true });\n const requestedAgent = process.env.TELEGRAM_DEFAULT_AGENT?.trim();\n const forumChatId = Number.parseInt(process.env.TELEGRAM_FORUM_CHAT_ID ?? \"\", 10);\n const adapter = startTelegramAdapter({\n client: bot,\n allowedUsers: (process.env.TELEGRAM_ALLOWED_USERS ?? \"\")\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean),\n ...(process.env.TELEGRAM_VAULT_OWNER_USER_ID?.trim()\n ? { vaultOwnerTelegramUserId: process.env.TELEGRAM_VAULT_OWNER_USER_ID.trim() }\n : {}),\n ...(isAgentKind(requestedAgent) ? { defaultAgent: requestedAgent } : {}),\n ...(Number.isFinite(forumChatId) ? { forumChatId } : {}),\n });\n let stopped = false;\n return {\n name: \"telegram\",\n adapter,\n bot,\n async stop(): Promise<void> {\n if (stopped) return;\n stopped = true;\n await adapter.stop();\n await bot.stopPolling({ cancel: true }).catch(() => {});\n },\n };\n}\n\n/** Environment-driven executable shipped with `@negotium/adapter-telegram`. */\nexport async function runTelegramCli(): Promise<void> {\n if (!process.env.TELEGRAM_BOT_TOKEN?.trim()) {\n throw new Error(\"TELEGRAM_BOT_TOKEN is required\");\n }\n let node: NodeHandle | undefined;\n const singleton = await waitForRequiredRuntimeProcessLease(\"adapter:telegram\", {\n workloadName: \"Telegram adapter\",\n onLost: () => {\n process.stderr.write(\"negotium-telegram: singleton lease lost; shutting down\\n\");\n void node?.stop();\n },\n });\n try {\n // Channel processes coordinate through SQLite, not a shared listening\n // port. An ephemeral port lets Terminal, Telegram, and Otium coexist.\n node = await startDefaultNode({ port: 0 });\n } catch (error) {\n singleton.stop();\n throw error;\n }\n let channel: TelegramEnvironmentHandle;\n try {\n channel = startTelegramFromEnv();\n } catch (error) {\n await node.stop();\n singleton.stop();\n throw error;\n }\n\n onShutdown(\"telegram-channel\", 100, () => channel.stop());\n onShutdown(\"telegram-singleton\", 90, () => singleton.stop());\n process.stdout.write(`negotium Telegram adapter listening through node :${node.port}\\n`);\n await node.completed;\n}\n\nif (import.meta.main) {\n runTelegramCli().catch((error) => {\n process.stderr.write(\n `negotium-telegram: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n });\n}\n",
6
- "/**\n * startTelegramAdapter — turn a negotium node into a Telegram bot.\n *\n * SINGLE-OPERATOR ADAPTER BY DESIGN: unlike clawgram (multi-user production\n * bot), this adapter serves exactly one human owner — the fixed negotium\n * `userId` (default \"local\"). `allowedUsers` is just a gate for that owner's\n * Telegram id(s) (one person, possibly several devices); there is no\n * per-user scoping, role logic, or cross-user isolation in commands.\n *\n * The adapter owns exactly the channel glue:\n * - (chatId, forum thread) → negotium topic mapping (a chat/thread shows\n * one topic; a topic may fan out to several chats/threads), persisted in\n * SQLite so restarts keep routing established threads,\n * - inbound text/media → whitelist check → slash commands (/new /topics\n * /agent /fork /spawn /del /del! /abort /vault) → attachment download into the\n * topic workspace (core `ingestAttachment`) → persisted user message +\n * AI turn; `/load` binds a topic created by another simultaneous adapter;\n * voice notes are transcribed via core's local pipeline (or a\n * custom `transcribe` hook); album items (shared `media_group_id`) are\n * debounce-buffered into ONE combined turn,\n * - RuntimeBus \"message\" events → markdown-to-Telegram-HTML rendering,\n * 4096-char splitting, per-chunk plain-text fallback, produced-file\n * delivery ([FILE:] tags → sendPhoto/sendDocument, sensitive paths\n * blocked), optional turn footer, and a durable SQLite retry outbox for\n * transient send failures (429/5xx/network),\n * - \"ai-status\" ai_active events → best-effort typing indicator,\n * - FORUM MODE (`forumChatId` set): runtime-created topics — spawn_subagent\n * children, /new from another host, ask-fork rooms — materialize as real\n * Telegram forum threads in that supergroup, and `topic-deleted` removes\n * the thread (best-effort).\n *\n * It deliberately does NOT construct the Telegram client, start the node's\n * HTTP/MCP server, or call `startSessionInboxWorker` — the embedding app\n * owns process-level wiring. Keeping those out of the library is what makes\n * it composable (any polling/webhook client works) and testable (tests\n * inject a fake client and never touch the network).\n */\n\nimport { existsSync } from \"node:fs\";\nimport type { NegotiumAdapterHandle } from \"@negotium/adapter-sdk\";\nimport { createDurableOutboxWorker } from \"@negotium/adapter-sdk/outbox\";\nimport {\n type AgentKind,\n composeAttachmentPrompt,\n ensurePersonalGeneral,\n errMsg,\n executeVaultCommand,\n extractFileTagPaths,\n getTopic,\n getTopicByNameForUser,\n type IngestedAttachment,\n ingestAttachment,\n isAgentKind,\n isSensitivePath,\n isTopicVisible,\n isTranscriptionConfigured,\n isVaultCommandLine,\n listTopics,\n logger,\n type MessageDto,\n type RegisterTopicOptions,\n renderTurnFooter,\n runtimeBus,\n startAiTurn,\n stripFileTags,\n submitUserMessage,\n TopicArchiveRequiredError,\n type TopicDto,\n TopicTitleConflictError,\n TopicValidationError,\n topicService,\n transcribeAudio,\n} from \"@negotium/core\";\nimport { type OutboxEntry, openMappingStore, type PersistedMapping } from \"@/mapping-store\";\nimport { renderOutbound } from \"@/render\";\nimport type {\n TelegramChatMember,\n TelegramClientLike,\n TelegramIncomingMessage,\n TelegramMyChatMemberUpdate,\n} from \"@/types\";\n\nexport interface TelegramAdapterOptions {\n client: TelegramClientLike;\n /** negotium user the bot acts as; defaults to \"local\". */\n userId?: string;\n /** Telegram user-id whitelist; empty/absent = allow all. */\n allowedUsers?: string[];\n /**\n * Telegram user id allowed to manage the shared node Vault. The owner must\n * also appear in `allowedUsers`. A sole allowlisted user is inferred for\n * backwards compatibility; multiple users require this option explicitly.\n * Vault commands are disabled when the allowlist is empty.\n */\n vaultOwnerTelegramUserId?: string;\n /** Agent for auto-created topics; unset = registerTopic's default (maestro). */\n defaultAgent?: \"claude\" | \"codex\" | \"maestro\";\n /** Turn dispatcher override for remote hosts and deterministic tests. */\n startTurn?: typeof startAiTurn;\n /** Topic title for a chat/thread; default `tg-{chatId}` / `tg-{chatId}-{threadId}`. */\n topicTitleFor?: (chatId: number, threadId?: number) => string;\n /**\n * FORUM MODE: id of a forum supergroup. Runtime-created topics materialize\n * as forum threads there via `client.createForumTopic`, and their bus\n * messages are delivered into the thread. Requires the client's forum\n * surface; without it the adapter logs a warning and behaves like DM mode.\n */\n forumChatId?: number;\n /** Mapping-db path override (tests); default `${DATA_DIR}/adapter-telegram.db`. */\n mappingDbPath?: string;\n /** Refresh interval for Telegram's short-lived typing action. Default 4s. */\n typingHeartbeatMs?: number;\n /** Per-delivery watchdog: a send that hasn't settled in this long is\n * abandoned so the topic's queue keeps draining. Override is a test hook;\n * default 60s. */\n sendTimeoutMs?: number;\n /** Voice-note transcriber. Defaults to core's local faster-whisper pipeline\n * (`transcribeAudio`); when neither this option nor the core pipeline is\n * configured, voice messages get a polite \"not configured\" reply. */\n transcribe?: (filePath: string) => Promise<string | null>;\n /** Append core's one-line turn footer (agent · model · tokens) to final AI\n * replies. Default off. */\n footer?: boolean;\n /** Durable retry-outbox tuning (test hooks; production defaults are fine). */\n outbox?: {\n pollMs?: number;\n baseDelayMs?: number;\n maxDelayMs?: number;\n maxAttempts?: number;\n };\n /** Media-group (album) buffering: `debounceMs` after the last item (albums\n * arrive over ~1s), `maxWaitMs` hard cap on total buffering so a trickling\n * group can't defer its turn forever. Test hooks; defaults 1s / 3s. */\n mediaGroup?: {\n debounceMs?: number;\n maxWaitMs?: number;\n };\n}\n\nexport interface TelegramAdapterHandle extends NegotiumAdapterHandle<\"telegram\"> {\n /** Bind an existing visible Negotium topic to a Telegram chat/thread. */\n loadTopic(chatId: number, topicId: string, threadId?: number): boolean;\n /** Remove only the Telegram binding; the shared Negotium topic is preserved. */\n unloadTopic(chatId: number, threadId?: number): boolean;\n /** Unsubscribe from the RuntimeBus, stop the retry flusher, close the\n * mapping store, and ignore further inbound messages. In-flight forum\n * thread creations are abandoned (their continuations check the stopped\n * flag before touching the store or sending). */\n stop(): void;\n}\n\n/** One live (chat, thread?) → topic binding. `threadId` is echoed back on\n * replies as `message_thread_id` so forum answers land in their thread.\n * Holds ids only — the TopicDto is re-read from storage when needed, so\n * mappings loaded from the persistent store need no hydration pass. */\ninterface ChatMapping {\n topicId: string;\n chatId: number;\n threadId?: number;\n}\n\n/** One outbound unit: rendered text plus files referenced by [FILE:] tags. */\ninterface OutboundPayload {\n text: string;\n files: string[];\n runtimeMessageId?: string;\n}\n\ninterface DeliveredMessageRef {\n chatId: number;\n threadId?: number;\n messageId: number;\n kind: \"text\" | \"media\";\n text?: string;\n html?: boolean;\n footer?: string;\n}\n\ninterface DeliveredTextRef {\n messageId: number;\n kind: \"text\";\n text: string;\n html: boolean;\n footer?: string;\n}\n\ninterface DeliveredMediaRef {\n messageId: number;\n kind: \"media\";\n}\n\ninterface ToolStatusRef {\n mapping: ChatMapping;\n messageId: number;\n}\n\ninterface ToolStatusState {\n closed: boolean;\n refs: Map<string, ToolStatusRef>;\n queue: Promise<void>;\n}\n\n/** Telegram caps forum topic names at 128 characters. */\nconst FORUM_TOPIC_NAME_MAX = 128;\n/** DM fallback: how far up the parentTopicId chain to look for a mapped\n * ancestor (spawn_subagent children can nest). */\nconst MAX_PARENT_HOPS = 5;\nconst DEFAULT_SEND_TIMEOUT_MS = 60_000;\n/** Extensions delivered via sendPhoto (mirrors clawgram's IMAGE_EXTS). */\nconst PHOTO_EXTS = new Set([\"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\"]);\n\nfunction onboardingGuide(botUsername?: string): string {\n const identity = botUsername ? `\\nBot username: @${botUsername.replace(/^@/, \"\")}\\n` : \"\\n\";\n return (\n \"Welcome to Negotium. This DM is your General manager: chat naturally here to create, \" +\n \"delegate work to, stop, or delete topics.\\n\\n\" +\n \"Connect a Telegram workspace:\\n\" +\n \"1. Create a supergroup and enable Topics.\\n\" +\n \"2. Add this bot to the group.\\n\" +\n '3. Promote the bot to administrator and enable \"Manage Topics\".\\n' +\n \"4. The group connects automatically; no /connect command is needed.\\n\" +\n identity +\n \"After connection, use the group's General topic as the manager and each forum topic as \" +\n \"an independent agent conversation.\"\n );\n}\n\nfunction isChatAdmin(member: TelegramChatMember): boolean {\n return member.status === \"administrator\" || member.status === \"creator\";\n}\n\nfunction canManageTopics(member: TelegramChatMember): boolean {\n return (\n member.status === \"creator\" ||\n (member.status === \"administrator\" && member.can_manage_topics === true)\n );\n}\n\nfunction isManageTopicsPermissionError(info: TelegramErrorInfo): boolean {\n return /not enough rights|need administrator rights|chat_admin_required|manage topics/i.test(\n info.description,\n );\n}\n\nfunction defaultTopicTitle(chatId: number, threadId?: number): string {\n return threadId === undefined ? `tg-${chatId}` : `tg-${chatId}-${threadId}`;\n}\n\n/** Extract the argument portion of a bot command, e.g. \"/new foo bar\" → \"foo bar\" */\nfunction extractCommandArg(text: string): string {\n return text.split(/\\s+/).slice(1).join(\" \").trim();\n}\n\n/** The parts of a Telegram API error the adapter classifies on.\n * `node-telegram-bot-api` throws errors with `response.statusCode` (Bot API\n * HTTP status) and `response.body` = the API's `{ description, parameters }`\n * payload; `message` repeats the description (\"ETELEGRAM: 400 Bad Request:\n * can't parse entities…\") and network failures carry `code` (\"EFATAL\",\n * \"ETIMEDOUT\", …). All fields are read defensively. */\ninterface TelegramErrorInfo {\n status?: number;\n code?: string;\n description: string;\n retryAfterSec?: number;\n}\n\nfunction telegramErrorInfo(err: unknown): TelegramErrorInfo {\n const e = err as {\n message?: unknown;\n code?: unknown;\n response?: {\n statusCode?: unknown;\n body?: { description?: unknown; parameters?: { retry_after?: unknown } };\n };\n };\n const status = typeof e?.response?.statusCode === \"number\" ? e.response.statusCode : undefined;\n const description = [e?.response?.body?.description, e?.message]\n .filter((s): s is string => typeof s === \"string\")\n .join(\" \");\n const retryRaw = e?.response?.body?.parameters?.retry_after;\n return {\n status,\n ...(typeof e?.code === \"string\" ? { code: e.code } : {}),\n description,\n ...(typeof retryRaw === \"number\" ? { retryAfterSec: retryRaw } : {}),\n };\n}\n\n/** Conservative \"Telegram rejected the HTML entities\" check: only a 400 (or an\n * error without a status code at all) whose description matches Telegram's\n * parse-rejection text warrants the plain-text resend. */\nfunction isHtmlParseError(info: TelegramErrorInfo): boolean {\n if (info.status !== undefined && info.status !== 400) return false;\n return /can't parse entities/i.test(info.description);\n}\n\nfunction isForumTopicAlreadyGone(info: TelegramErrorInfo): boolean {\n if (info.status !== undefined && info.status !== 400) return false;\n return /(?:message thread|forum topic).*not found|topic_id_invalid/i.test(info.description);\n}\n\n/** Transient failures worth a durable retry: rate limits, server errors, and\n * network-level failures. Everything else (403 blocked, 400 bad request…)\n * would fail identically on retry. */\nconst RETRYABLE_CODES = new Set([\"EFATAL\", \"ETIMEDOUT\", \"ECONNRESET\", \"ECONNREFUSED\", \"EAI_AGAIN\"]);\nfunction isRetryableSendError(info: TelegramErrorInfo): boolean {\n if (info.status === 429) return true;\n if (info.status !== undefined && info.status >= 500 && info.status < 600) return true;\n return info.code !== undefined && RETRYABLE_CODES.has(info.code);\n}\n\nexport function startTelegramAdapter(opts: TelegramAdapterOptions): TelegramAdapterHandle {\n const { client, forumChatId } = opts;\n const userId = opts.userId ?? \"local\";\n const allowed = new Set((opts.allowedUsers ?? []).map((s) => s.trim()).filter(Boolean));\n const configuredVaultOwner = opts.vaultOwnerTelegramUserId?.trim();\n if (configuredVaultOwner && !allowed.has(configuredVaultOwner)) {\n throw new Error(\"vaultOwnerTelegramUserId must appear in allowedUsers\");\n }\n const vaultOwnerTelegramUserId =\n configuredVaultOwner || (allowed.size === 1 ? allowed.values().next().value : undefined);\n const isAllowed = (telegramUserId: number | undefined): boolean =>\n allowed.size === 0 || allowed.has(String(telegramUserId));\n const isVaultOwner = (telegramUserId: number | undefined): boolean =>\n vaultOwnerTelegramUserId !== undefined && String(telegramUserId) === vaultOwnerTelegramUserId;\n const titleFor = opts.topicTitleFor ?? defaultTopicTitle;\n const sendTimeoutMs = opts.sendTimeoutMs ?? DEFAULT_SEND_TIMEOUT_MS;\n const typingHeartbeatMs = Math.max(250, opts.typingHeartbeatMs ?? 4_000);\n const footerEnabled = opts.footer === true;\n const dispatchTurn = opts.startTurn ?? startAiTurn;\n const store = openMappingStore(opts.mappingDbPath);\n const restoredForumChatId = store.loadForumChatId();\n const initialForumChatId = forumChatId ?? restoredForumChatId;\n let forumChat = initialForumChatId ?? 0;\n let forumMode = initialForumChatId !== undefined && typeof client.createForumTopic === \"function\";\n // A configured override is operator-authorized. A restored auto-connected\n // group is re-verified asynchronously before materializing new threads.\n let forumManageTopicsAvailable = forumMode && forumChatId !== undefined;\n if (forumChatId !== undefined) store.saveForumChatId(forumChatId);\n if (initialForumChatId !== undefined && !forumMode) {\n logger.warn(\n { forumChatId: initialForumChatId },\n \"telegram adapter: forumChatId set but client lacks createForumTopic — forum mode disabled\",\n );\n }\n const personalGeneral = ensurePersonalGeneral(userId);\n\n // ── mapping state ───────────────────────────────────────────────────\n // Two indexes over the same ChatMapping objects. byKey is 1:1 (a chat or\n // thread shows exactly one topic — UNIQUE(chat_id, thread_id) in the\n // store); byTopic fans out (a topic may render into several chats/threads,\n // e.g. a DM chat and a forum thread bound to the same room).\n const byKey = new Map<string, ChatMapping>(); // `${chatId}` | `${chatId}:${threadId}`\n const byTopic = new Map<string, Set<ChatMapping>>();\n const targetByQueryId = new Map<string, ChatMapping>();\n const typingHeartbeatByQueryId = new Map<string, ReturnType<typeof setInterval>>();\n const toolStatusByQueryId = new Map<string, ToolStatusState>();\n const runtimeMessages = new Map<string, MessageDto>();\n const deliveredByRuntimeMessageId = new Map<string, DeliveredMessageRef[]>();\n const deletedRuntimeMessageIds = new Set<string>();\n const activeRuntimeDeliveries = new Map<string, number>();\n const completedRuntimeMessageCleanup = new Set<string>();\n const forumCleanupInFlight = new Set<string>();\n const ownerDmChatIds = new Set<number>(\n [...allowed]\n .map((value) => Number.parseInt(value, 10))\n .filter((value) => Number.isSafeInteger(value) && value > 0),\n );\n let stopped = false;\n let botIdentity: Awaited<ReturnType<NonNullable<TelegramClientLike[\"getMe\"]>>> | undefined;\n let botIdentityPromise: Promise<typeof botIdentity> | undefined;\n\n function beginRuntimeDelivery(messageId: string | undefined): void {\n if (!messageId) return;\n activeRuntimeDeliveries.set(messageId, (activeRuntimeDeliveries.get(messageId) ?? 0) + 1);\n }\n\n function endRuntimeDelivery(messageId: string | undefined): void {\n if (!messageId) return;\n const remaining = (activeRuntimeDeliveries.get(messageId) ?? 1) - 1;\n if (remaining > 0) activeRuntimeDeliveries.set(messageId, remaining);\n else {\n activeRuntimeDeliveries.delete(messageId);\n if (completedRuntimeMessageCleanup.delete(messageId)) {\n deletedRuntimeMessageIds.delete(messageId);\n }\n }\n }\n\n function typingTargets(topicId: string, queryId?: string): ChatMapping[] {\n const target = queryId ? targetByQueryId.get(queryId) : undefined;\n return target ? [target] : [...(byTopic.get(topicId) ?? [])];\n }\n\n function sendTyping(topicId: string, queryId?: string): void {\n if (typeof client.sendChatAction !== \"function\") return;\n for (const mapping of typingTargets(topicId, queryId)) {\n void client\n .sendChatAction(mapping.chatId, \"typing\", threadOpts(mapping.threadId))\n .catch(() => {});\n }\n }\n\n function stopTypingHeartbeat(queryId: string): void {\n const timer = typingHeartbeatByQueryId.get(queryId);\n if (!timer) return;\n clearInterval(timer);\n typingHeartbeatByQueryId.delete(queryId);\n }\n\n function startTypingHeartbeat(topicId: string, queryId: string): void {\n stopTypingHeartbeat(queryId);\n sendTyping(topicId, queryId);\n const timer = setInterval(() => {\n if (stopped) {\n stopTypingHeartbeat(queryId);\n return;\n }\n sendTyping(topicId, queryId);\n }, typingHeartbeatMs);\n timer.unref?.();\n typingHeartbeatByQueryId.set(queryId, timer);\n }\n\n function resolveBotIdentity(): Promise<typeof botIdentity> {\n if (botIdentity) return Promise.resolve(botIdentity);\n if (typeof client.getMe !== \"function\") return Promise.resolve(undefined);\n if (botIdentityPromise) return botIdentityPromise;\n botIdentityPromise = (async () => {\n let attempt = 0;\n while (!stopped) {\n try {\n botIdentity = await client.getMe!();\n return botIdentity;\n } catch (err) {\n attempt += 1;\n const waitMs = Math.min(5_000, 250 * 2 ** Math.min(attempt - 1, 5));\n logger.warn(\n { err, attempt, waitMs },\n \"telegram adapter: getMe failed while resolving onboarding identity; retrying\",\n );\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n }\n return undefined;\n })().finally(() => {\n botIdentityPromise = undefined;\n });\n return botIdentityPromise;\n }\n\n // Warm the identity cache so the common first-DM path has no added latency.\n void resolveBotIdentity();\n\n const mappingKey = (chatId: number, threadId?: number): string =>\n threadId === undefined ? String(chatId) : `${chatId}:${threadId}`;\n\n const threadOpts = (threadId?: number): Record<string, unknown> =>\n threadId === undefined ? {} : { message_thread_id: threadId };\n\n function showToolStatus(topicId: string, queryId: string, label: string): void {\n // A status message is only safe when it can be removed at turn end.\n const deleteMessage = client.deleteMessage?.bind(client);\n if (!deleteMessage) return;\n let state = toolStatusByQueryId.get(queryId);\n if (!state) {\n state = { closed: false, refs: new Map(), queue: Promise.resolve() };\n toolStatusByQueryId.set(queryId, state);\n }\n const current = state;\n const text = `🔧 ${label}`.slice(0, 512);\n current.queue = current.queue.then(async () => {\n if (stopped || current.closed) return;\n for (const mapping of typingTargets(topicId, queryId)) {\n if (stopped || current.closed) return;\n const key = mappingKey(mapping.chatId, mapping.threadId);\n const existing = current.refs.get(key);\n if (existing && typeof client.editMessageText === \"function\") {\n try {\n await client.editMessageText(text, {\n chat_id: mapping.chatId,\n message_id: existing.messageId,\n });\n continue;\n } catch (err) {\n if (/message is not modified/i.test(telegramErrorInfo(err).description)) continue;\n current.refs.delete(key);\n await deleteMessage(mapping.chatId, existing.messageId).catch(() => {});\n }\n } else if (existing) {\n current.refs.delete(key);\n await deleteMessage(mapping.chatId, existing.messageId).catch(() => {});\n }\n try {\n const sent = await client.sendMessage(mapping.chatId, text, threadOpts(mapping.threadId));\n const messageId = sentMessageId(sent);\n if (messageId === null) continue;\n if (stopped || current.closed) {\n await deleteMessage(mapping.chatId, messageId).catch(() => {});\n } else {\n current.refs.set(key, { mapping, messageId });\n }\n } catch (err) {\n logger.warn(\n { err, topicId, queryId, chatId: mapping.chatId },\n \"telegram adapter: tool status send failed\",\n );\n }\n }\n if (!current.closed) sendTyping(topicId, queryId);\n });\n }\n\n function closeToolStatus(queryId: string): void {\n const state = toolStatusByQueryId.get(queryId);\n if (!state) return;\n state.closed = true;\n state.queue = state.queue.then(async () => {\n if (typeof client.deleteMessage === \"function\") {\n for (const { mapping, messageId } of state.refs.values()) {\n await client.deleteMessage(mapping.chatId, messageId).catch(() => {});\n }\n }\n state.refs.clear();\n if (toolStatusByQueryId.get(queryId) === state) toolStatusByQueryId.delete(queryId);\n });\n }\n\n /** Remove one mapping from the byTopic fan-out set (byKey untouched). */\n function detachFromTopic(mapping: ChatMapping): void {\n const set = byTopic.get(mapping.topicId);\n if (!set) return;\n set.delete(mapping);\n if (set.size === 0) byTopic.delete(mapping.topicId);\n }\n\n function bindMapping(\n chatId: number,\n threadId: number | undefined,\n topicId: string,\n { persist = true } = {},\n ): ChatMapping {\n const key = mappingKey(chatId, threadId);\n const prev = byKey.get(key);\n if (prev) {\n if (prev.topicId === topicId) return prev;\n // Re-bind (e.g. /new or /agent in an already-mapped chat/thread):\n // detach only THIS key from the old topic — its other bindings stay —\n // and log so the remap is never silent.\n detachFromTopic(prev);\n logger.info(\n { chatId, threadId, fromTopicId: prev.topicId, toTopicId: topicId },\n \"telegram adapter: re-binding chat/thread to a new topic\",\n );\n }\n const mapping: ChatMapping = {\n topicId,\n chatId,\n ...(threadId !== undefined ? { threadId } : {}),\n };\n byKey.set(key, mapping);\n let set = byTopic.get(topicId);\n if (!set) {\n set = new Set();\n byTopic.set(topicId, set);\n }\n set.add(mapping);\n if (persist) store.save({ chatId, threadId, topicId }); // upserts by (chat, thread)\n return mapping;\n }\n\n /** Drop every binding of a topic (topic deleted / vanished). */\n function unbindTopic(topicId: string, { persist = true } = {}): void {\n const set = byTopic.get(topicId);\n if (set) {\n for (const mapping of set) byKey.delete(mappingKey(mapping.chatId, mapping.threadId));\n byTopic.delete(topicId);\n }\n if (persist) store.deleteByTopic(topicId);\n }\n\n /** Keep a stale forum mapping durable until Telegram confirms deletion. If\n * the request fails or the process stops, startup reconciliation retries it. */\n function cleanupPersistedMapping(mapping: PersistedMapping, logMessage: string): void {\n if (mapping.threadId !== undefined && typeof client.deleteForumTopic === \"function\") {\n const key = mappingKey(mapping.chatId, mapping.threadId);\n if (forumCleanupInFlight.has(key)) return;\n forumCleanupInFlight.add(key);\n void client\n .deleteForumTopic(mapping.chatId, mapping.threadId)\n .then(() => {\n if (!stopped) store.deleteByChat(mapping.chatId, mapping.threadId);\n })\n .catch((err) => {\n if (isForumTopicAlreadyGone(telegramErrorInfo(err))) {\n if (!stopped) store.deleteByChat(mapping.chatId, mapping.threadId);\n return;\n }\n logger.warn({ err, topicId: mapping.topicId, threadId: mapping.threadId }, logMessage);\n })\n .finally(() => forumCleanupInFlight.delete(key));\n return;\n }\n store.deleteByChat(mapping.chatId, mapping.threadId);\n }\n\n function unloadMapping(chatId: number, threadId?: number): boolean {\n const key = mappingKey(chatId, threadId);\n const mapping = byKey.get(key);\n if (!mapping) return false;\n detachFromTopic(mapping);\n byKey.delete(key);\n store.deleteByChat(chatId, threadId);\n return true;\n }\n\n function loadExistingTopic(chatId: number, topicId: string, threadId?: number): boolean {\n const topic = getTopic(topicId);\n if (!topic?.participants.some((participant) => participant.userId === userId)) {\n return false;\n }\n bindMapping(chatId, threadId, topic.id);\n return true;\n }\n\n // Restore persisted routing so a restart keeps delivering into existing\n // chats/threads instead of materializing duplicates. Prune mappings whose\n // runtime topic disappeared while this adapter was offline; otherwise a\n // deleted topic leaves an orphan Telegram thread forever.\n for (const persisted of store.load()) {\n const topic = getTopic(persisted.topicId);\n if (topic?.participants.some((participant) => participant.userId === userId)) {\n bindMapping(persisted.chatId, persisted.threadId, persisted.topicId, { persist: false });\n continue;\n }\n cleanupPersistedMapping(persisted, \"telegram adapter: stale forum thread cleanup failed\");\n }\n\n function reconcileStaleMappings(): void {\n for (const persisted of store.load()) {\n const topic = getTopic(persisted.topicId);\n if (!topic?.participants.some((participant) => participant.userId === userId)) {\n cleanupPersistedMapping(persisted, \"telegram adapter: stale forum thread cleanup failed\");\n }\n }\n }\n\n // ── topic creation (adapter-initiated) ──────────────────────────────\n // registerTopic broadcasts `topic-created` SYNCHRONOUSLY on the in-process\n // bus, so the counter is guaranteed to still be >0 when the materializer's\n // subscriber runs — that synchronicity is the whole mechanism. If core ever\n // defers the broadcast (queue/microtask), this guard silently stops working\n // and adapter-created topics would double-materialize.\n // When the ADAPTER creates the topic (inbound auto-create, /new, /agent) it\n // binds its own mapping, so the forum-mode materializer must not race it\n // into a duplicate thread.\n let suppressMaterialize = 0;\n function registerTopicLocal(options: RegisterTopicOptions): TopicDto {\n suppressMaterialize++;\n try {\n return topicService.create(options);\n } finally {\n suppressMaterialize--;\n }\n }\n\n /** Reuse a topic by name if this node already has it, else create one. */\n function getOrCreateTopic(title: string, agent?: AgentKind): TopicDto {\n return (\n getTopicByNameForUser(title, userId) ??\n registerTopicLocal({ title, userId, kind: \"agent\", ...(agent ? { agent } : {}) })\n );\n }\n\n function resolveMapping(chatId: number, threadId?: number): TopicDto {\n const cached = byKey.get(mappingKey(chatId, threadId));\n if (cached) {\n const topic = getTopic(cached.topicId);\n if (topic) return topic;\n unbindTopic(cached.topicId); // topic vanished underneath the mapping\n }\n const topic = getOrCreateTopic(titleFor(chatId, threadId), opts.defaultAgent);\n bindMapping(chatId, threadId, topic.id);\n return topic;\n }\n\n // ── durable retry outbox ────────────────────────────────────────────\n // Simplified port of clawgram's telegram-outbox: transient send failures\n // (429/5xx/network) are persisted and re-tried with exponential backoff\n // (base→cap), max attempts then marked dead (row kept, never retried).\n const outboxCfg = {\n pollMs: opts.outbox?.pollMs ?? 500,\n baseDelayMs: opts.outbox?.baseDelayMs ?? 1_000,\n maxDelayMs: opts.outbox?.maxDelayMs ?? 60_000,\n maxAttempts: opts.outbox?.maxAttempts ?? 6,\n };\n\n interface TelegramOutboxDelivery {\n sentValue: unknown;\n sentText: string;\n sentAsHtml: boolean;\n }\n\n const outboxWorker = createDurableOutboxWorker<OutboxEntry, TelegramOutboxDelivery>({\n policy: outboxCfg,\n store: {\n due: (now) => store.outboxDue(now),\n hasPending: () => store.outboxAll().some((entry) => !entry.dead),\n acknowledge: async (entry, delivery) => {\n store.outboxDelete(entry.id);\n const telegramMessageId = sentMessageId(delivery.sentValue);\n if (!entry.runtimeMessageId || telegramMessageId === null) return;\n const ref: DeliveredMessageRef = {\n chatId: entry.chatId,\n threadId: entry.threadId,\n messageId: telegramMessageId,\n kind: \"text\",\n text: delivery.sentText,\n html: delivery.sentAsHtml,\n ...(entry.footer ? { footer: entry.footer } : {}),\n };\n if (deletedRuntimeMessageIds.has(entry.runtimeMessageId)) {\n await deleteDeliveredRefs(entry.runtimeMessageId, [ref]);\n } else {\n rememberDeliveredRefs(entry.runtimeMessageId, [ref]);\n }\n },\n discard: (entry) => {\n store.outboxDelete(entry.id);\n },\n retry: (entry, retry) => {\n store.outboxReschedule(entry.id, retry.attempts, retry.nextTryAt, retry.error);\n },\n deadLetter: (entry, retry) => {\n store.outboxMarkDead(entry.id, retry.attempts, retry.error);\n },\n },\n shouldDiscard: (entry) =>\n Boolean(entry.runtimeMessageId && deletedRuntimeMessageIds.has(entry.runtimeMessageId)),\n deliver: async (entry) => {\n try {\n const sentValue = await client.sendMessage(entry.chatId, entry.html, {\n ...threadOpts(entry.threadId),\n parse_mode: \"HTML\",\n });\n return { sentValue, sentText: entry.html, sentAsHtml: true };\n } catch (error) {\n if (!isHtmlParseError(telegramErrorInfo(error))) throw error;\n const sentValue = await client.sendMessage(\n entry.chatId,\n entry.plain,\n threadOpts(entry.threadId),\n );\n return { sentValue, sentText: entry.plain, sentAsHtml: false };\n }\n },\n classifyError: (error) => {\n const info = telegramErrorInfo(error);\n return {\n message: info.description || info.code || \"send failed\",\n ...(info.status === 429 && info.retryAfterSec !== undefined\n ? { retryAfterMs: Math.max(info.retryAfterSec * 1000, 0) }\n : {}),\n };\n },\n onEntryStart: (entry) => beginRuntimeDelivery(entry.runtimeMessageId),\n onEntryEnd: (entry) => endRuntimeDelivery(entry.runtimeMessageId),\n onDeadLetter: (entry, retry) => {\n logger.warn(\n { id: entry.id, chatId: entry.chatId, attempts: retry.attempts, error: retry.error },\n \"telegram adapter: outbox entry dead-lettered after max attempts\",\n );\n },\n onError: (error) => {\n logger.warn({ err: error }, \"telegram adapter: outbox flush failed\");\n },\n });\n outboxWorker.start();\n\n function enqueueOutbox(\n chatId: number,\n threadId: number | undefined,\n html: string,\n plain: string,\n info: TelegramErrorInfo,\n runtimeMessageId?: string,\n footer?: string,\n ): void {\n if (stopped) return;\n // A 429's retry_after is server truth — schedule the first retry there.\n const initialDelay =\n info.status === 429 && info.retryAfterSec !== undefined\n ? info.retryAfterSec * 1000\n : outboxCfg.baseDelayMs;\n store.outboxEnqueue({\n chatId,\n threadId,\n runtimeMessageId,\n footer,\n html,\n plain,\n nextTryAt: Date.now() + initialDelay,\n lastError: info.description || info.code || \"send failed\",\n });\n logger.warn(\n { chatId, threadId, status: info.status, code: info.code },\n \"telegram adapter: transient send failure — queued for retry\",\n );\n outboxWorker.wake();\n }\n\n // ── outbound delivery ───────────────────────────────────────────────\n /** Send one runtime message into a chat: HTML chunks, sequential awaits so\n * multi-chunk messages arrive in order. Per-chunk error policy:\n * - HTML parse rejection (400 \"can't parse entities\") → resend the chunk\n * as plain text,\n * - transient failure (429 honoring retry_after / 5xx / network) →\n * enqueue into the durable retry outbox,\n * - anything else → log and drop the chunk (don't misclassify e.g. a\n * 403 \"bot was blocked\" as a formatting problem).\n */\n function sentMessageId(value: unknown): number | null {\n if (!value || typeof value !== \"object\" || !(\"message_id\" in value)) return null;\n const id = (value as { message_id?: unknown }).message_id;\n return typeof id === \"number\" && Number.isSafeInteger(id) ? id : null;\n }\n\n function rememberDeliveredRefs(messageId: string, refs: DeliveredMessageRef[]): void {\n if (refs.length === 0) return;\n const current = deliveredByRuntimeMessageId.get(messageId) ?? [];\n current.push(...refs);\n deliveredByRuntimeMessageId.set(messageId, current);\n }\n\n async function deleteDeliveredRefs(\n runtimeMessageId: string,\n refs: DeliveredMessageRef[],\n topicId?: string,\n ): Promise<void> {\n if (typeof client.deleteMessage !== \"function\") return;\n for (const ref of refs) {\n await client\n .deleteMessage(ref.chatId, ref.messageId)\n .catch((err) =>\n logger.warn(\n { err, topicId, messageId: runtimeMessageId, telegramMessageId: ref.messageId },\n \"telegram adapter: superseded message cleanup failed\",\n ),\n );\n }\n }\n\n function isDeliveredTextRef(\n ref: DeliveredMessageRef,\n ): ref is DeliveredMessageRef & { kind: \"text\"; text: string; html: boolean } {\n return ref.kind === \"text\" && typeof ref.text === \"string\" && typeof ref.html === \"boolean\";\n }\n\n async function deliver(\n chatId: number,\n threadId: number | undefined,\n text: string,\n runtimeMessageId?: string,\n footer?: string,\n ): Promise<DeliveredTextRef[]> {\n const base = threadOpts(threadId);\n const htmlOpts = { ...base, parse_mode: \"HTML\" };\n const delivered: DeliveredTextRef[] = [];\n const chunks = renderOutbound(text);\n for (const [index, chunk] of chunks.entries()) {\n const chunkFooter = footer && index === chunks.length - 1 ? footer : undefined;\n try {\n const sent = await client.sendMessage(chatId, chunk.html, htmlOpts);\n const messageId = sentMessageId(sent);\n if (messageId !== null) {\n delivered.push({\n messageId,\n kind: \"text\",\n text: chunk.html,\n html: true,\n ...(chunkFooter ? { footer: chunkFooter } : {}),\n });\n }\n } catch (err) {\n const info = telegramErrorInfo(err);\n if (isHtmlParseError(info)) {\n // Telegram rejected the HTML (e.g. markdown cut mid-chunk produced\n // invalid tags) — clawgram's fallback: resend the chunk as plain text.\n try {\n const sent = await client.sendMessage(chatId, chunk.plain, base);\n const messageId = sentMessageId(sent);\n if (messageId !== null) {\n delivered.push({\n messageId,\n kind: \"text\",\n text: chunk.plain,\n html: false,\n ...(chunkFooter ? { footer: chunkFooter } : {}),\n });\n }\n } catch (fallbackErr) {\n const fallbackInfo = telegramErrorInfo(fallbackErr);\n if (isRetryableSendError(fallbackInfo)) {\n enqueueOutbox(\n chatId,\n threadId,\n chunk.plain,\n chunk.plain,\n fallbackInfo,\n runtimeMessageId,\n chunkFooter,\n );\n } else {\n logger.warn({ err: fallbackErr, chatId }, \"telegram adapter: plain fallback failed\");\n }\n }\n continue;\n }\n if (isRetryableSendError(info)) {\n enqueueOutbox(\n chatId,\n threadId,\n chunk.html,\n chunk.plain,\n info,\n runtimeMessageId,\n chunkFooter,\n );\n continue;\n }\n logger.warn({ err, chatId }, \"telegram adapter: send failed — dropping chunk\");\n }\n }\n return delivered;\n }\n\n /** Send one produced file (from a [FILE:] tag): photos by extension via\n * sendPhoto, everything else via sendDocument; sensitive paths blocked;\n * missing files surface as a plain-text notice (model intent was explicit). */\n async function sendFile(\n chatId: number,\n threadId: number | undefined,\n path: string,\n ): Promise<DeliveredMediaRef | null> {\n const base = threadOpts(threadId);\n if (isSensitivePath(path)) {\n logger.warn({ path, chatId }, \"telegram adapter: blocked sensitive file path\");\n return null;\n }\n if (!existsSync(path)) {\n const sent = await client.sendMessage(chatId, `File: ${path}`, base).catch(() => null);\n const messageId = sentMessageId(sent);\n return messageId === null ? null : { messageId, kind: \"media\" };\n }\n const ext = path.split(\".\").pop()?.toLowerCase() ?? \"\";\n try {\n let sent: unknown;\n if (PHOTO_EXTS.has(ext) && typeof client.sendPhoto === \"function\") {\n sent = await client.sendPhoto(chatId, path, base);\n } else if (typeof client.sendDocument === \"function\") {\n sent = await client.sendDocument(chatId, path, base);\n } else {\n // Client has no file surface — at least point the user at the path.\n sent = await client.sendMessage(chatId, `File: ${path}`, base);\n }\n const messageId = sentMessageId(sent);\n return messageId === null ? null : { messageId, kind: \"media\" };\n } catch (err) {\n logger.warn({ err, path, chatId }, \"telegram adapter: file send failed\");\n return null;\n }\n }\n\n async function deliverPayload(\n chatId: number,\n threadId: number | undefined,\n payload: OutboundPayload,\n ): Promise<void> {\n if (payload.runtimeMessageId && deletedRuntimeMessageIds.has(payload.runtimeMessageId)) return;\n beginRuntimeDelivery(payload.runtimeMessageId);\n const deliveredRefs: DeliveredMessageRef[] = [];\n try {\n let text = payload.text;\n let footer: string | null = null;\n if (payload.runtimeMessageId && footerEnabled) {\n const message = runtimeMessages.get(payload.runtimeMessageId);\n // Query-scoped segments before tools are not final replies. Their usage\n // patch (or the final text segment's usage) identifies the one message\n // that should carry the turn footer.\n const shouldRenderFooter = message && (!message.queryId || message.usage);\n footer = shouldRenderFooter ? renderTurnFooter(message) : null;\n if (footer) {\n text = text ? `${text}\\n\\n*${footer}*` : `*${footer}*`;\n }\n }\n if (text) {\n const delivered = await deliver(\n chatId,\n threadId,\n text,\n payload.runtimeMessageId,\n footer ?? undefined,\n );\n deliveredRefs.push(\n ...delivered.map((item) => ({\n ...item,\n chatId,\n threadId,\n })),\n );\n }\n for (const path of payload.files) {\n if (payload.runtimeMessageId && deletedRuntimeMessageIds.has(payload.runtimeMessageId)) {\n break;\n }\n const delivered = await sendFile(chatId, threadId, path);\n if (delivered) deliveredRefs.push({ ...delivered, chatId, threadId });\n }\n if (payload.runtimeMessageId && deliveredRefs.length > 0) {\n if (deletedRuntimeMessageIds.has(payload.runtimeMessageId)) {\n await deleteDeliveredRefs(payload.runtimeMessageId, deliveredRefs);\n } else {\n rememberDeliveredRefs(payload.runtimeMessageId, deliveredRefs);\n }\n }\n } finally {\n endRuntimeDelivery(payload.runtimeMessageId);\n }\n }\n\n // Per-topic send chains keep messages ordered even when materialization\n // flushes a buffer while new bus events keep arriving. Each link is capped\n // by a watchdog so one hung sendMessage can't wedge the topic forever, and\n // a drained chain removes its map entry so long-lived processes don't\n // accumulate one settled promise per topic ever spoken to.\n const sendQueues = new Map<string, Promise<void>>();\n function enqueueSend(topicId: string, task: () => Promise<void>): void {\n const prev = sendQueues.get(topicId) ?? Promise.resolve();\n const next = prev.then(\n () =>\n new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n logger.warn(\n { topicId, sendTimeoutMs },\n \"telegram adapter: send timed out — abandoning it and continuing the queue\",\n );\n resolve();\n }, sendTimeoutMs);\n task()\n .catch((err) => logger.warn({ err, topicId }, \"telegram adapter: send task failed\"))\n .finally(() => {\n clearTimeout(timer);\n resolve();\n });\n }),\n );\n sendQueues.set(topicId, next);\n void next.then(() => {\n // Chain-end cleanup: only the tail may delete the entry (a newer link\n // may already have replaced `next`).\n if (sendQueues.get(topicId) === next) sendQueues.delete(topicId);\n });\n }\n\n /** Deliver into every chat/thread currently bound to the topic, in order. */\n function enqueueFanout(\n topicId: string,\n mappings: Iterable<ChatMapping>,\n payload: OutboundPayload,\n ): void {\n const targets = [...mappings];\n enqueueSend(topicId, async () => {\n for (const m of targets) await deliverPayload(m.chatId, m.threadId, payload);\n });\n }\n\n function enqueueTarget(topicId: string, target: ChatMapping, payload: OutboundPayload): void {\n enqueueSend(topicId, () => deliverPayload(target.chatId, target.threadId, payload));\n }\n\n // ── forum mode: materialize runtime topics as forum threads ─────────\n /** One in-flight `createForumTopic`: messages arriving meanwhile are\n * buffered (flushed in order once the thread exists); `cancelled` is set\n * by topic-deleted so the continuation discards the orphan thread. */\n interface PendingMaterialization {\n buffer: OutboundPayload[];\n cancelled: boolean;\n }\n const pendingByTopic = new Map<string, PendingMaterialization>();\n /** Topics waiting for the bot's Manage Topics permission. Unlike permanent\n * tombstones, these are retried when Telegram reports the permission was\n * granted. */\n const permissionBlockedTopics = new Map<string, string>();\n /** topicId → title for topics whose thread creation failed: subsequent\n * messages go to the general chat with a `[title]` prefix instead of\n * re-attempting creation on every message. Persisted so restarts keep the\n * fallback instead of dropping messages or re-failing creation. */\n const materializeTombstones = new Map<string, string>();\n if (forumMode) {\n for (const t of store.loadTombstones()) materializeTombstones.set(t.topicId, t.title);\n }\n\n function deliverFallback(title: string, payload: OutboundPayload): Promise<void> {\n return deliverPayload(forumChat, undefined, {\n text: payload.text ? `[${title}] ${payload.text}` : \"\",\n files: payload.files,\n runtimeMessageId: payload.runtimeMessageId,\n });\n }\n\n function flushBuffered(\n topicId: string,\n buffer: OutboundPayload[],\n send: (payload: OutboundPayload) => Promise<void>,\n ): void {\n for (const payload of buffer) enqueueSend(topicId, () => send(payload));\n }\n\n function materializeTopic(topic: TopicDto): void {\n if (\n !forumManageTopicsAvailable ||\n suppressMaterialize > 0 ||\n byTopic.has(topic.id) ||\n pendingByTopic.has(topic.id) ||\n permissionBlockedTopics.has(topic.id) ||\n materializeTombstones.has(topic.id)\n ) {\n return;\n }\n if (!isTopicVisible(topic)) return;\n // Only rooms the adapter's (single) negotium user can see.\n if (!topic.participants?.some((p) => p.userId === userId)) return;\n const materializationChat = forumChat;\n const pending: PendingMaterialization = { buffer: [], cancelled: false };\n pendingByTopic.set(topic.id, pending);\n void (async () => {\n let created: { message_thread_id: number };\n try {\n // forumMode implies createForumTopic exists (checked at start).\n created = await client.createForumTopic!(\n materializationChat,\n topic.title.slice(0, FORUM_TOPIC_NAME_MAX),\n );\n } catch (err) {\n if (pendingByTopic.get(topic.id) === pending) pendingByTopic.delete(topic.id);\n // Adapter stopped or topic deleted while the call was in flight —\n // not a creation failure; don't tombstone (store may be closed).\n if (stopped || pending.cancelled) return;\n const errorInfo = telegramErrorInfo(err);\n if (isManageTopicsPermissionError(errorInfo)) {\n const permissionWasAvailable = forumManageTopicsAvailable;\n forumManageTopicsAvailable = false;\n permissionBlockedTopics.set(topic.id, topic.title);\n logger.warn(\n { err, topicId: topic.id, title: topic.title },\n \"telegram adapter: Manage Topics unavailable — waiting for permission recovery\",\n );\n if (permissionWasAvailable) {\n reply(\n forumChat,\n undefined,\n 'Forum topic creation is paused. Enable the bot administrator permission \"Manage Topics\"; pending topics will be retried automatically.',\n );\n }\n flushBuffered(topic.id, pending.buffer, (payload) =>\n deliverFallback(topic.title, payload),\n );\n return;\n }\n logger.warn(\n { err, topicId: topic.id, title: topic.title },\n \"telegram adapter: createForumTopic failed permanently — falling back to general chat\",\n );\n materializeTombstones.set(topic.id, topic.title);\n store.saveTombstone(topic.id, topic.title);\n flushBuffered(topic.id, pending.buffer, (payload) => deliverFallback(topic.title, payload));\n return;\n }\n if (pendingByTopic.get(topic.id) === pending) pendingByTopic.delete(topic.id);\n const threadId = created.message_thread_id;\n if (stopped || pending.cancelled) {\n // Cancelled = the topic was deleted while creation was in flight:\n // persist cleanup intent before deleting the just-created orphan so a\n // failed request can be retried after restart. Bind nothing in memory.\n // Stopped = abandon silently (no post-stop sends, no closed-DB save).\n if (pending.cancelled && typeof client.deleteForumTopic === \"function\") {\n const orphan = { chatId: materializationChat, threadId, topicId: topic.id };\n store.save(orphan);\n cleanupPersistedMapping(orphan, \"telegram adapter: orphan thread cleanup failed\");\n }\n return;\n }\n bindMapping(materializationChat, threadId, topic.id);\n flushBuffered(topic.id, pending.buffer, (payload) =>\n deliverPayload(materializationChat, threadId, payload),\n );\n })();\n }\n\n function handleTopicDeleted(topicId: string): void {\n if (materializeTombstones.delete(topicId)) store.deleteTombstone(topicId);\n const pending = pendingByTopic.get(topicId);\n if (pending) pending.cancelled = true; // in-flight creation — its continuation cleans up\n for (const [messageId, message] of runtimeMessages) {\n if (message.topicId === topicId) deleteDeliveredRuntimeMessage(topicId, messageId);\n }\n const set = byTopic.get(topicId);\n if (!set) return;\n const mappings = [...set];\n // Stop routing immediately, but keep forum mappings durable until the\n // Telegram API confirms deletion so failures can be retried on restart.\n unbindTopic(topicId, { persist: false });\n for (const mapping of mappings) {\n cleanupPersistedMapping(mapping, \"telegram adapter: deleteForumTopic failed\");\n }\n }\n\n // ── outbound message routing ────────────────────────────────────────\n /** DM fallback target: nearest mapped ancestor up the parentTopicId chain\n * (bounded hops + cycle guard — parent links come from storage). */\n function findMappedAncestor(topic: TopicDto): Set<ChatMapping> | undefined {\n const seen = new Set<string>([topic.id]);\n let current: TopicDto | null = topic;\n for (let hop = 0; hop < MAX_PARENT_HOPS && current; hop++) {\n const parentId = current.parentTopicId;\n if (!parentId || seen.has(parentId)) return undefined;\n seen.add(parentId);\n const mappings = byTopic.get(parentId);\n if (mappings && mappings.size > 0) return mappings;\n current = getTopic(parentId);\n }\n return undefined;\n }\n\n function routeMessage(topicId: string, payload: OutboundPayload, queryId?: string): void {\n const pending = pendingByTopic.get(topicId);\n if (pending) {\n pending.buffer.push(payload); // thread creation in flight — flushed in order later\n return;\n }\n const specificTarget = queryId ? targetByQueryId.get(queryId) : undefined;\n if (specificTarget) {\n enqueueTarget(topicId, specificTarget, payload);\n return;\n }\n const mappings = byTopic.get(topicId);\n if (mappings && mappings.size > 0) {\n // A Telegram-owned query has a specific target above. Events produced by\n // Terminal or another surface intentionally fan out to every mapped\n // personal General so the owner's channel views stay synchronized.\n enqueueFanout(topicId, mappings, payload);\n return;\n }\n const tombstoneTitle = materializeTombstones.get(topicId);\n if (tombstoneTitle !== undefined) {\n enqueueSend(topicId, () => deliverFallback(tombstoneTitle, payload));\n return;\n }\n const topic = getTopic(topicId);\n if (!topic) return;\n if (forumMode) {\n if (!forumManageTopicsAvailable || permissionBlockedTopics.has(topicId)) {\n enqueueSend(topicId, () => deliverFallback(topic.title, payload));\n return;\n }\n // Lazy materialization: first message for a live topic with no binding\n // (topic predates the adapter, missed topic-created, dropped binding…)\n // — create its thread now instead of silently discarding the message.\n // Same suppress/participant rules as the topic-created path.\n materializeTopic(topic);\n pendingByTopic.get(topicId)?.buffer.push(payload);\n return;\n }\n // DM fallback: a child room (spawn_subagent, fork) descending from a\n // mapped chat topic forwards into that chat with a `[title]` prefix so\n // subagent output stays visible without forum mode.\n const ancestorMappings = findMappedAncestor(topic);\n if (ancestorMappings) {\n enqueueFanout(topicId, ancestorMappings, {\n text: payload.text ? `[${topic.title}] ${payload.text}` : \"\",\n files: payload.files,\n runtimeMessageId: payload.runtimeMessageId,\n });\n }\n }\n\n function deleteDeliveredRuntimeMessage(topicId: string, messageId: string): void {\n deletedRuntimeMessageIds.add(messageId);\n completedRuntimeMessageCleanup.delete(messageId);\n runtimeMessages.delete(messageId);\n const pending = pendingByTopic.get(topicId);\n if (pending) {\n pending.buffer = pending.buffer.filter((payload) => payload.runtimeMessageId !== messageId);\n }\n store.outboxDeleteByRuntimeMessageId(messageId);\n enqueueSend(topicId, async () => {\n const refs = deliveredByRuntimeMessageId.get(messageId) ?? [];\n deliveredByRuntimeMessageId.delete(messageId);\n await deleteDeliveredRefs(messageId, refs, topicId);\n if ((activeRuntimeDeliveries.get(messageId) ?? 0) > 0) {\n completedRuntimeMessageCleanup.add(messageId);\n } else {\n completedRuntimeMessageCleanup.delete(messageId);\n deletedRuntimeMessageIds.delete(messageId);\n }\n });\n }\n\n function attachUpdatedFooter(topicId: string, messageId: string, footer: string): void {\n enqueueSend(topicId, async () => {\n if (deletedRuntimeMessageIds.has(messageId)) return;\n const refs = deliveredByRuntimeMessageId.get(messageId) ?? [];\n type StoredTextRef = DeliveredMessageRef & {\n kind: \"text\";\n text: string;\n html: boolean;\n };\n const refsByTarget = new Map<string, StoredTextRef[]>();\n for (const ref of refs) {\n if (!isDeliveredTextRef(ref)) continue;\n const key = `${ref.chatId}:${ref.threadId ?? \"root\"}`;\n const targetRefs = refsByTarget.get(key) ?? [];\n targetRefs.push(ref);\n refsByTarget.set(key, targetRefs);\n }\n const footerChunk = renderOutbound(`*${footer}*`)[0];\n if (!footerChunk) return;\n for (const targetRefs of refsByTarget.values()) {\n const ref =\n targetRefs.findLast((candidate) => candidate.footer !== undefined) ?? targetRefs.at(-1);\n if (!ref) continue;\n if (ref.footer === footer) continue;\n if (typeof client.editMessageText === \"function\") {\n const suffix = ref.html ? footerChunk.html : footerChunk.plain;\n const previousFooterChunk = ref.footer ? renderOutbound(`*${ref.footer}*`)[0] : undefined;\n const previousSuffix = previousFooterChunk\n ? ref.html\n ? previousFooterChunk.html\n : previousFooterChunk.plain\n : \"\";\n const previousTrailer = previousSuffix ? `\\n\\n${previousSuffix}` : \"\";\n const baseText =\n previousTrailer && ref.text.endsWith(previousTrailer)\n ? ref.text.slice(0, -previousTrailer.length)\n : ref.text;\n const text = `${baseText}\\n\\n${suffix}`;\n const editOptions = {\n chat_id: ref.chatId,\n message_id: ref.messageId,\n ...(ref.html ? { parse_mode: \"HTML\" } : {}),\n };\n try {\n await client.editMessageText(text, editOptions);\n ref.text = text;\n ref.footer = footer;\n continue;\n } catch (err) {\n let editError = err;\n const info = telegramErrorInfo(err);\n if (isRetryableSendError(info)) {\n const retryDelayMs = Math.max(0, (info.retryAfterSec ?? 0) * 1000);\n // Keep this topic's queue bounded. For a long rate limit, leave\n // the existing message untouched rather than risk a duplicate\n // footer from an ambiguous edit result.\n if (retryDelayMs > 30_000) {\n logger.warn(\n { err, topicId, messageId, retryDelayMs },\n \"telegram adapter: footer edit rate-limited; leaving footer unchanged\",\n );\n continue;\n }\n if (retryDelayMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, retryDelayMs));\n }\n try {\n await client.editMessageText(text, editOptions);\n ref.text = text;\n ref.footer = footer;\n continue;\n } catch (retryErr) {\n if (isRetryableSendError(telegramErrorInfo(retryErr))) {\n logger.warn(\n { err: retryErr, topicId, messageId, telegramMessageId: ref.messageId },\n \"telegram adapter: footer edit retry failed; leaving footer unchanged\",\n );\n continue;\n }\n editError = retryErr;\n }\n }\n logger.warn(\n { err: editError, topicId, messageId, telegramMessageId: ref.messageId },\n \"telegram adapter: footer edit failed permanently; sending footer separately\",\n );\n }\n }\n const delivered = await deliver(ref.chatId, ref.threadId, `*${footer}*`, messageId, footer);\n refs.push(\n ...delivered.map((item) => ({\n ...item,\n chatId: ref.chatId,\n threadId: ref.threadId,\n footer,\n })),\n );\n }\n deliveredByRuntimeMessageId.set(messageId, refs);\n });\n }\n\n function clearQueryDeliveryState(queryId: string): void {\n const timer = setTimeout(() => {\n for (const [messageId, message] of runtimeMessages) {\n if (message.queryId !== queryId) continue;\n runtimeMessages.delete(messageId);\n deliveredByRuntimeMessageId.delete(messageId);\n deletedRuntimeMessageIds.delete(messageId);\n }\n }, 5 * 60_000);\n timer.unref?.();\n }\n\n // ── inbound: Telegram → runtime ─────────────────────────────────────\n /** Fire-and-forget plain-text reply (command feedback, error notices). */\n function reply(chatId: number, threadId: number | undefined, text: string): void {\n void client\n .sendMessage(chatId, text, threadOpts(threadId))\n .catch((err) => logger.warn({ err, chatId }, \"telegram adapter: reply failed\"));\n }\n\n async function sendOnboardingGuide(chatId: number, threadId?: number): Promise<void> {\n const bot = await resolveBotIdentity();\n if (stopped) return;\n await client\n .sendMessage(chatId, onboardingGuide(bot?.username), threadOpts(threadId))\n .catch((err) => logger.warn({ err, chatId }, \"telegram adapter: onboarding guide failed\"));\n }\n\n function materializeVisibleTopics(): void {\n if (!forumMode || !forumManageTopicsAvailable) return;\n for (const topic of listTopics()) {\n if (\n isTopicVisible(topic) &&\n topic.participants.some((participant) => participant.userId === userId)\n ) {\n materializeTopic(topic);\n }\n }\n }\n\n function restoreForumTopicCreation({ retryPermanent = false } = {}): void {\n forumManageTopicsAvailable = true;\n permissionBlockedTopics.clear();\n if (retryPermanent) {\n materializeTombstones.clear();\n store.clearTombstones();\n }\n reconcileStaleMappings();\n materializeVisibleTopics();\n }\n\n async function notifyOwnerDms(text: string): Promise<void> {\n await Promise.allSettled([...ownerDmChatIds].map((chatId) => client.sendMessage(chatId, text)));\n }\n\n async function disconnectForum(chatId: number): Promise<boolean> {\n if (!forumMode || forumChat !== chatId) return false;\n\n for (const [topicId, pending] of pendingByTopic) {\n pending.cancelled = true;\n if (pendingByTopic.get(topicId) === pending) pendingByTopic.delete(topicId);\n }\n for (const mapping of [...byKey.values()]) {\n if (mapping.chatId === chatId) unloadMapping(mapping.chatId, mapping.threadId);\n }\n for (const [queryId, target] of targetByQueryId) {\n if (target.chatId === chatId) targetByQueryId.delete(queryId);\n }\n\n permissionBlockedTopics.clear();\n materializeTombstones.clear();\n store.clearTombstones();\n store.outboxDeleteByChat(chatId);\n store.clearForumChatId();\n forumMode = false;\n forumManageTopicsAvailable = false;\n forumChat = 0;\n\n await notifyOwnerDms(\n \"The Telegram forum was disconnected because the bot left or was removed. Your Negotium topics were preserved; promote the bot in a forum group to reconnect.\",\n );\n logger.info({ userId, forumChatId: chatId }, \"telegram adapter: forum disconnected\");\n return true;\n }\n\n async function linkForumAndAnnounce(\n ownerTelegramId: number,\n chat: { id: number; title?: string },\n botMember: TelegramChatMember,\n ): Promise<boolean> {\n if (typeof client.createForumTopic !== \"function\") {\n reply(\n ownerTelegramId,\n undefined,\n \"This Telegram client cannot create forum topics, so the group was not connected.\",\n );\n return false;\n }\n if (forumMode && forumChat !== chat.id) {\n reply(\n ownerTelegramId,\n undefined,\n `A different forum group (${forumChat}) is already connected to this Negotium node.`,\n );\n return false;\n }\n const hasManageTopics = canManageTopics(botMember);\n if (forumMode && forumChat === chat.id) {\n const recovered = hasManageTopics && !forumManageTopicsAvailable;\n const lostPermission = !hasManageTopics && forumManageTopicsAvailable;\n if (hasManageTopics) {\n restoreForumTopicCreation({ retryPermanent: recovered });\n if (recovered) {\n await Promise.allSettled([\n client.sendMessage(\n chat.id,\n \"Manage Topics permission confirmed. Pending Negotium topics are being created now.\",\n ),\n notifyOwnerDms(\n `Manage Topics permission confirmed for “${chat.title?.trim() || chat.id}”. Pending topics are being retried.`,\n ),\n ]);\n }\n } else {\n forumManageTopicsAvailable = false;\n if (lostPermission) {\n await notifyOwnerDms(\n `Manage Topics permission was removed from “${chat.title?.trim() || chat.id}”. Existing topics are preserved; restore the permission to resume topic creation.`,\n );\n }\n }\n return true;\n }\n\n forumChat = chat.id;\n forumMode = true;\n forumManageTopicsAvailable = hasManageTopics;\n permissionBlockedTopics.clear();\n materializeTombstones.clear();\n store.clearTombstones();\n store.saveForumChatId(chat.id);\n bindMapping(chat.id, undefined, personalGeneral.id);\n ownerDmChatIds.add(ownerTelegramId);\n\n // Existing agent rooms become forum topics just like rooms created after\n // connection. General is already mapped above and therefore skipped.\n materializeVisibleTopics();\n\n const title = chat.title?.trim() || String(chat.id);\n const permissionWarning = hasManageTopics\n ? \"\"\n : '\\n\\nWarning: enable the bot administrator permission \"Manage Topics\" before creating or deleting topics.';\n await Promise.allSettled([\n client.sendMessage(\n chat.id,\n `Negotium connected to “${title}”. Use this General topic to create and manage topics in natural language.${permissionWarning}`,\n ),\n client.sendMessage(\n ownerTelegramId,\n `Connected forum group “${title}” (${chat.id}). No /connect command is needed.${permissionWarning}`,\n ),\n ]);\n logger.info(\n {\n userId,\n ownerTelegramId,\n forumChatId: chat.id,\n canManageTopics: hasManageTopics,\n },\n \"telegram adapter: auto-connected forum group\",\n );\n return true;\n }\n\n async function tryAutoConnectFromMessage(msg: TelegramIncomingMessage): Promise<boolean> {\n const senderId = msg.from?.id;\n if (\n msg.chat.type !== \"supergroup\" ||\n !msg.chat.is_forum ||\n senderId === undefined ||\n !isAllowed(senderId)\n ) {\n return false;\n }\n if (forumMode && msg.chat.id !== forumChat) return false;\n if (forumMode && forumManageTopicsAvailable) return true;\n if (typeof client.getMe !== \"function\" || typeof client.getChatMember !== \"function\") {\n return false;\n }\n\n try {\n const bot = await resolveBotIdentity();\n if (!bot) return false;\n const [botMember, senderMember] = await Promise.all([\n client.getChatMember(msg.chat.id, bot.id),\n client.getChatMember(msg.chat.id, senderId),\n ]);\n if (!isChatAdmin(botMember) || !isChatAdmin(senderMember)) return false;\n await linkForumAndAnnounce(senderId, msg.chat, botMember);\n return forumMode && forumChat === msg.chat.id;\n } catch (err) {\n logger.debug(\n { err, groupId: msg.chat.id, senderId },\n \"telegram adapter: lazy forum auto-connect check failed\",\n );\n return false;\n }\n }\n\n async function verifyInitialForumPermissions(): Promise<void> {\n if (!forumMode) return;\n if (forumChatId !== undefined) return;\n if (typeof client.getMe !== \"function\" || typeof client.getChatMember !== \"function\") {\n // Embedded legacy clients cannot expose membership state. Preserve the\n // previous configured-forum behavior instead of disabling the adapter.\n forumManageTopicsAvailable = true;\n return;\n }\n try {\n const bot = await resolveBotIdentity();\n if (!bot || stopped || !forumMode) return;\n const member = await client.getChatMember(forumChat, bot.id);\n if (member.status === \"left\" || member.status === \"kicked\") {\n await disconnectForum(forumChat);\n return;\n }\n if (canManageTopics(member)) {\n const restoredAutoConnection =\n forumChatId === undefined && restoredForumChatId !== undefined;\n restoreForumTopicCreation({ retryPermanent: restoredAutoConnection });\n } else {\n forumManageTopicsAvailable = false;\n }\n } catch (err) {\n logger.warn(\n { err, forumChatId: forumChat },\n \"telegram adapter: initial forum permission check failed\",\n );\n }\n }\n\n void verifyInitialForumPermissions();\n\n /** Persist the user message and start the AI turn (single fixed userId). */\n function runTurn(\n topic: TopicDto,\n prompt: string,\n chatId: number,\n threadId: number | undefined,\n ): void {\n const target: ChatMapping = {\n topicId: topic.id,\n chatId,\n ...(threadId !== undefined ? { threadId } : {}),\n };\n const rememberTarget = (queryId: string): void => {\n targetByQueryId.set(queryId, target);\n };\n const { queryId } = submitUserMessage({\n topic,\n userId,\n text: prompt,\n sourceAdapter: \"telegram\",\n visualTools: false,\n onDispatched: rememberTarget,\n startTurn: dispatchTurn,\n });\n if (queryId) rememberTarget(queryId);\n }\n\n // Preserve Telegram arrival order per chat/thread even when attachment\n // downloads or album debounce complete later than a following text message.\n const inboundQueues = new Map<string, Promise<void>>();\n function enqueueInbound(\n chatId: number,\n threadId: number | undefined,\n task: () => Promise<void> | void,\n ): void {\n const key = mappingKey(chatId, threadId);\n const previous = inboundQueues.get(key);\n const run = async (): Promise<void> => {\n if (stopped) return;\n await task();\n };\n // Keep the first task's synchronous prefix synchronous (topic creation,\n // mapping and plain-text persistence historically happened before the\n // Telegram callback returned). Only later arrivals need a promise hop.\n const next = (previous ? previous.catch(() => {}).then(run) : run()).catch((err) =>\n logger.warn({ err, chatId, threadId }, \"telegram adapter: inbound task failed\"),\n );\n inboundQueues.set(key, next);\n void next.then(() => {\n if (inboundQueues.get(key) === next) inboundQueues.delete(key);\n });\n }\n\n // ── inbound attachments ─────────────────────────────────────────────\n const transcriber = opts.transcribe ?? ((filePath: string) => transcribeAudio(filePath));\n const transcriptionAvailable = (): boolean =>\n opts.transcribe !== undefined || isTranscriptionConfigured();\n\n /** Download a Telegram file into the topic workspace via core's intake. */\n async function downloadToTopic(\n topicId: string,\n fileId: string,\n filename: string,\n ): Promise<IngestedAttachment> {\n // getFileLink presence is checked by the caller.\n const url = await client.getFileLink!(fileId);\n const res = await fetch(url);\n if (!res.ok) throw new Error(`attachment download failed: HTTP ${res.status}`);\n return ingestAttachment({\n topicId,\n filename,\n bytes: new Uint8Array(await res.arrayBuffer()),\n });\n }\n\n /** Ingest one message's photo/document into the topic workspace and return\n * the canonical prompt lines (shared by single-media and album paths). */\n async function ingestMessageFiles(\n topicId: string,\n msg: TelegramIncomingMessage,\n ): Promise<string[]> {\n const lines: string[] = [];\n if (msg.photo && msg.photo.length > 0) {\n // Highest-resolution variant is last (Telegram API contract).\n const photo = msg.photo[msg.photo.length - 1]!;\n lines.push((await downloadToTopic(topicId, photo.file_id, \"photo.jpg\")).promptLine);\n }\n if (msg.document) {\n const filename = msg.document.file_name || \"file\";\n lines.push((await downloadToTopic(topicId, msg.document.file_id, filename)).promptLine);\n }\n return lines;\n }\n\n /** Media message → download attachments → core prompt convention → turn.\n * Mirrors clawgram's buildPromptFromMessage, minus PII/video. */\n async function handleMediaMessage(\n msg: TelegramIncomingMessage,\n chatId: number,\n threadId: number | undefined,\n ): Promise<void> {\n const caption = (msg.text ?? msg.caption ?? \"\").trim();\n const topic = resolveMapping(chatId, threadId);\n\n if (typeof client.getFileLink !== \"function\") {\n logger.warn(\n { chatId },\n \"telegram adapter: media message but client lacks getFileLink — caption only\",\n );\n if (caption) runTurn(topic, caption, chatId, threadId);\n else reply(chatId, threadId, \"this bot cannot download attachments\");\n return;\n }\n\n let promptLines: string[] = [];\n let voiceText = \"\";\n try {\n promptLines = await ingestMessageFiles(topic.id, msg);\n if (msg.voice) {\n if (!transcriptionAvailable()) {\n reply(\n chatId,\n threadId,\n \"voice transcription is not configured on this bot — please send text\",\n );\n } else {\n const ingested = await downloadToTopic(topic.id, msg.voice.file_id, \"voice.ogg\");\n const transcript = (await transcriber(ingested.path))?.trim();\n if (transcript) {\n voiceText = `[Voice transcript]\\n${transcript}`;\n } else {\n reply(chatId, threadId, \"voice transcription failed — please send text\");\n }\n }\n }\n } catch (err) {\n logger.warn({ err, chatId, topicId: topic.id }, \"telegram adapter: attachment intake failed\");\n reply(chatId, threadId, errMsg(err, \"attachment download failed\"));\n }\n if (stopped) return;\n\n const userText = voiceText ? (caption ? `${voiceText}\\n\\n${caption}` : voiceText) : caption;\n if (!userText && promptLines.length === 0) return;\n runTurn(topic, composeAttachmentPrompt(userText, promptLines), chatId, threadId);\n }\n\n // ── media groups (albums) ───────────────────────────────────────────\n // Telegram splits a multi-photo upload into separate messages sharing one\n // `media_group_id`, arriving over ~1s. Without buffering each item would\n // start its own turn and abort-on-new-message would keep only the last.\n // Clawgram's bufferMediaGroup semantics: buffer per (chatId, groupId), a\n // debounce timer resets on every new item, then ONE flush combines every\n // caption + attachment into a single turn. On top of clawgram we add a\n // hard cap (maxWaitMs) so a trickling group can't defer its turn forever.\n const mediaGroupCfg = {\n debounceMs: opts.mediaGroup?.debounceMs ?? 1_000,\n maxWaitMs: opts.mediaGroup?.maxWaitMs ?? 3_000,\n };\n interface MediaGroupEntry {\n messages: TelegramIncomingMessage[];\n chatId: number;\n threadId?: number;\n firstSeenAt: number;\n timer: ReturnType<typeof setTimeout>;\n ready: Promise<void>;\n release: () => void;\n }\n const mediaGroups = new Map<string, MediaGroupEntry>(); // `${chatId}:${media_group_id}`\n\n function flushMediaGroup(key: string): void {\n const entry = mediaGroups.get(key);\n if (!entry) return;\n mediaGroups.delete(key);\n entry.release();\n }\n\n function bufferMediaGroup(\n msg: TelegramIncomingMessage,\n chatId: number,\n threadId: number | undefined,\n ): void {\n const key = `${chatId}:${msg.media_group_id}`;\n const existing = mediaGroups.get(key);\n if (existing) {\n existing.messages.push(msg);\n clearTimeout(existing.timer);\n // Debounce resets per item, but never beyond the cap from first sight.\n const remaining = existing.firstSeenAt + mediaGroupCfg.maxWaitMs - Date.now();\n const wait = Math.max(0, Math.min(mediaGroupCfg.debounceMs, remaining));\n existing.timer = setTimeout(() => flushMediaGroup(key), wait);\n return;\n }\n let releaseReady!: () => void;\n const ready = new Promise<void>((resolve) => {\n releaseReady = resolve;\n });\n const entry: MediaGroupEntry = {\n messages: [msg],\n chatId,\n ...(threadId !== undefined ? { threadId } : {}),\n firstSeenAt: Date.now(),\n timer: setTimeout(\n () => flushMediaGroup(key),\n Math.min(mediaGroupCfg.debounceMs, mediaGroupCfg.maxWaitMs),\n ),\n ready,\n release: releaseReady,\n };\n mediaGroups.set(key, entry);\n // Reserve the first album item's arrival position. Later items can still\n // extend the buffer while this queue entry waits for the debounce signal.\n enqueueInbound(chatId, threadId, async () => {\n await entry.ready;\n if (stopped) return;\n await handleMediaGroupFlush(entry);\n });\n }\n\n /** One combined turn for a whole album: every caption + every attachment. */\n async function handleMediaGroupFlush(entry: MediaGroupEntry): Promise<void> {\n const { messages, chatId, threadId } = entry;\n const topic = resolveMapping(chatId, threadId);\n const captions = messages\n .map((m) => (m.text ?? m.caption ?? \"\").trim())\n .filter((caption) => caption.length > 0);\n\n if (typeof client.getFileLink !== \"function\") {\n logger.warn(\n { chatId },\n \"telegram adapter: media group but client lacks getFileLink — captions only\",\n );\n if (captions.length > 0) runTurn(topic, captions.join(\"\\n\"), chatId, threadId);\n else reply(chatId, threadId, \"this bot cannot download attachments\");\n return;\n }\n\n const promptLines: string[] = [];\n for (const msg of messages) {\n try {\n promptLines.push(...(await ingestMessageFiles(topic.id, msg)));\n } catch (err) {\n logger.warn(\n { err, chatId, topicId: topic.id },\n \"telegram adapter: media group attachment intake failed\",\n );\n reply(chatId, threadId, errMsg(err, \"attachment download failed\"));\n }\n }\n if (stopped) return;\n const userText = captions.join(\"\\n\");\n if (!userText && promptLines.length === 0) return;\n runTurn(topic, composeAttachmentPrompt(userText, promptLines), chatId, threadId);\n }\n\n // ── commands ────────────────────────────────────────────────────────\n /** Handle a leading-slash command. Commands never start an AI turn. */\n async function handleCommand(\n text: string,\n chatId: number,\n threadId?: number,\n telegramUserId?: number,\n ): Promise<void> {\n const [rawCmd = \"\"] = text.split(/\\s+/);\n const addressedUsername = rawCmd.match(/@(\\w+)$/)?.[1];\n if (addressedUsername) {\n const bot = await resolveBotIdentity();\n if (!bot?.username || bot.username.toLowerCase() !== addressedUsername.toLowerCase()) return;\n }\n\n if (isVaultCommandLine(text)) {\n if (!isVaultOwner(telegramUserId)) return;\n const vaultResponse = executeVaultCommand(userId, text);\n if (vaultResponse !== null) reply(chatId, threadId, vaultResponse);\n return;\n }\n const cmd = rawCmd.replace(/@\\w+$/, \"\"); // tolerate \"/abort@MyBot\" in groups\n const arg = extractCommandArg(text);\n switch (cmd) {\n case \"/start\": {\n await sendOnboardingGuide(chatId, threadId);\n return;\n }\n case \"/abort\": {\n const mapping = byKey.get(mappingKey(chatId, threadId));\n reply(\n chatId,\n threadId,\n mapping && topicService.abortTurn(mapping.topicId, userId)\n ? \"aborted\"\n : \"nothing running\",\n );\n return;\n }\n case \"/agent\": {\n if (!isAgentKind(arg)) {\n reply(chatId, threadId, \"usage: /agent <claude|codex|maestro>\");\n return;\n }\n // Agent switch = remap to an agent-suffixed sibling topic (e.g.\n // `tg-123-claude`) so each agent keeps its own session history.\n try {\n const topic = getOrCreateTopic(`${titleFor(chatId, threadId)}-${arg}`, arg);\n bindMapping(chatId, threadId, topic.id);\n reply(chatId, threadId, `agent set to ${arg} — topic \"${topic.title}\"`);\n } catch (err) {\n reply(chatId, threadId, errMsg(err, \"agent switch failed\"));\n }\n return;\n }\n case \"/topics\": {\n const mine = listTopics().filter(\n (t) => isTopicVisible(t) && t.participants.some((p) => p.userId === userId),\n );\n reply(\n chatId,\n threadId,\n mine.length\n ? mine.map((t) => `- ${t.title}${t.agent ? ` (${t.agent})` : \"\"}`).join(\"\\n\")\n : \"no topics\",\n );\n return;\n }\n case \"/new\": {\n if (!arg) {\n const mapping = byKey.get(mappingKey(chatId, threadId));\n const topic = mapping ? getTopic(mapping.topicId) : null;\n if (!topic) {\n reply(chatId, threadId, \"nothing to reset — this chat has no topic yet\");\n return;\n }\n try {\n const result = await topicService.reset({\n topicId: topic.id,\n userId,\n reason: \"telegram-session-reset\",\n });\n reply(chatId, threadId, result.text);\n } catch (err) {\n reply(chatId, threadId, errMsg(err, \"session reset failed\"));\n }\n return;\n }\n try {\n const createOptions: RegisterTopicOptions = {\n title: arg,\n userId,\n kind: \"agent\",\n ...(opts.defaultAgent ? { agent: opts.defaultAgent } : {}),\n };\n const fromForumGeneral = forumMode && chatId === forumChat && threadId === undefined;\n // General is the forum's control surface. Keep it bound to Personal\n // General and let topic-created materialize a real Telegram thread.\n // DM chats and existing forum threads retain their switch-in-place\n // behavior.\n const topic = fromForumGeneral\n ? topicService.create(createOptions)\n : registerTopicLocal(createOptions);\n if (fromForumGeneral) {\n reply(chatId, threadId, `creating new topic \"${topic.title}\"`);\n return;\n }\n bindMapping(chatId, threadId, topic.id);\n reply(chatId, threadId, `switched to new topic \"${topic.title}\"`);\n } catch (err) {\n if (err instanceof TopicValidationError) {\n reply(chatId, threadId, err.message);\n } else {\n reply(chatId, threadId, errMsg(err, \"topic create failed\"));\n }\n }\n return;\n }\n case \"/load\": {\n if (!arg) {\n reply(chatId, threadId, \"usage: /load <topic>\");\n return;\n }\n const candidate = getTopicByNameForUser(arg, userId) ?? getTopic(arg);\n const topic = candidate && isTopicVisible(candidate) ? candidate : null;\n if (!topic || !loadExistingTopic(chatId, topic.id, threadId)) {\n reply(chatId, threadId, `no visible topic matching \"${arg}\"`);\n return;\n }\n reply(chatId, threadId, `loaded topic \"${topic.title}\"`);\n return;\n }\n case \"/unload\": {\n if (!unloadMapping(chatId, threadId)) {\n reply(chatId, threadId, \"this chat has no loaded topic\");\n return;\n }\n reply(chatId, threadId, \"unloaded topic; the Negotium topic was preserved\");\n return;\n }\n case \"/fork\":\n case \"/spawn\": {\n const label = cmd.slice(1);\n const mapping = byKey.get(mappingKey(chatId, threadId));\n if (!mapping) {\n reply(chatId, threadId, `nothing to ${label} — this chat has no topic yet`);\n return;\n }\n // fork = config + history copy; spawn = config only, fresh session.\n const copyHistory = cmd === \"/fork\";\n void topicService\n .derive({\n sourceTopicId: mapping.topicId,\n userId,\n copyHistory,\n ...(arg ? { name: arg } : {}),\n })\n .then((derived) => {\n if (!derived) {\n reply(chatId, threadId, `${label} failed`);\n return;\n }\n // Forum mode materializes the new topic's thread via its\n // topic-created broadcast — nothing else to do here.\n reply(\n chatId,\n threadId,\n `${copyHistory ? \"forked into\" : \"spawned\"} \"${derived.title}\"`,\n );\n })\n .catch((err) => {\n reply(\n chatId,\n threadId,\n err instanceof TopicTitleConflictError ? err.message : errMsg(err, `${label} failed`),\n );\n });\n return;\n }\n case \"/del\":\n case \"/del!\": {\n const force = cmd === \"/del!\";\n const mapping = byKey.get(mappingKey(chatId, threadId));\n const topic = arg\n ? getTopicByNameForUser(arg, userId)\n : mapping\n ? getTopic(mapping.topicId)\n : null;\n if (!topic) {\n reply(\n chatId,\n threadId,\n arg ? `no topic named \"${arg}\"` : \"this chat has no topic — usage: /del [name]\",\n );\n return;\n }\n // Notice BEFORE the cascade — if the target is this forum thread, the\n // thread is gone right after (clawgram's ordering quirk).\n reply(chatId, threadId, `deleting topic \"${topic.title}\"…`);\n // Mapping/thread cleanup rides the core topic-deleted bus event.\n void topicService.delete({ topicId: topic.id, userId, force }).catch((err) => {\n if (err instanceof TopicArchiveRequiredError) {\n reply(\n chatId,\n threadId,\n `delete blocked: archiving \"${topic.title}\" failed and deleting now would lose its history. ` +\n `Retry after fixing the archive, or force with: /del!${arg ? ` ${arg}` : \"\"}`,\n );\n } else {\n reply(chatId, threadId, errMsg(err, \"delete failed\"));\n }\n });\n return;\n }\n default:\n reply(\n chatId,\n threadId,\n \"commands: /new [name], /topics, /agent <claude|codex|maestro>, \" +\n \"/load <topic>, /unload, /fork [name], /spawn [name], \" +\n \"/del [name], /del! [name], /abort, /vault <list|set|del>\",\n );\n }\n }\n\n function handleIncomingMessage(msg: TelegramIncomingMessage): void {\n if (stopped) return;\n const chatId = msg.chat.id;\n // General can contain generic reply threads with message_thread_id, but it\n // is not a forum topic. Only is_topic_message=true may select an agent room.\n const generalForumMessage =\n msg.chat.type === \"supergroup\" && msg.chat.is_forum === true && msg.is_topic_message !== true;\n const threadId = generalForumMessage ? undefined : msg.message_thread_id;\n const text = msg.text?.trim();\n const hasMedia = Boolean(msg.photo?.length || msg.document || msg.voice);\n const privateDm = msg.chat.type === \"private\";\n const firstPrivateContact = privateDm && !byKey.has(mappingKey(chatId));\n\n if (privateDm) ownerDmChatIds.add(chatId);\n if (privateDm || (forumMode && chatId === forumChat && threadId === undefined)) {\n bindMapping(chatId, threadId, personalGeneral.id);\n }\n if (firstPrivateContact && text !== \"/start\") {\n void sendOnboardingGuide(chatId);\n }\n\n if (text?.startsWith(\"/\")) {\n // Abort is an out-of-band control and must not wait behind a slow file\n // download. Other commands participate in arrival ordering because they\n // can change the chat's topic mapping.\n const command = text.split(/\\s+/, 1)[0]?.replace(/@\\w+$/, \"\");\n if (command === \"/abort\") {\n void handleCommand(text, chatId, threadId, msg.from?.id);\n } else {\n enqueueInbound(chatId, threadId, () => handleCommand(text, chatId, threadId, msg.from?.id));\n }\n return;\n }\n if (hasMedia) {\n if (msg.media_group_id) {\n bufferMediaGroup(msg, chatId, threadId); // album item — one turn on flush\n return;\n }\n enqueueInbound(chatId, threadId, () => handleMediaMessage(msg, chatId, threadId));\n return;\n }\n if (!text) return;\n enqueueInbound(chatId, threadId, () =>\n runTurn(resolveMapping(chatId, threadId), text, chatId, threadId),\n );\n }\n\n client.on(\"message\", (msg: TelegramIncomingMessage) => {\n if (stopped) return;\n // Whitelist rejection is silent — same posture as clawgram (don't leak\n // the bot's existence to strangers) and no topic is ever created.\n if (!isAllowed(msg.from?.id)) return;\n\n if (msg.chat.type === \"supergroup\" && msg.chat.is_forum) {\n if (forumMode && msg.chat.id !== forumChat) return;\n if (!forumMode || !forumManageTopicsAvailable) {\n void tryAutoConnectFromMessage(msg).then((connected) => {\n if (connected && !stopped) handleIncomingMessage(msg);\n });\n return;\n }\n }\n handleIncomingMessage(msg);\n });\n\n client.on(\"my_chat_member\", (update: TelegramMyChatMemberUpdate) => {\n if (stopped || update.chat.type !== \"supergroup\" || !update.chat.is_forum) return;\n const status = update.new_chat_member?.status;\n if ((status === \"left\" || status === \"kicked\") && forumChat === update.chat.id) {\n void disconnectForum(update.chat.id).catch((err) =>\n logger.warn({ err, groupId: update.chat.id }, \"telegram adapter: forum disconnect failed\"),\n );\n return;\n }\n if (\n forumMode &&\n forumChat === update.chat.id &&\n status !== \"administrator\" &&\n status !== \"creator\"\n ) {\n const permissionWasAvailable = forumManageTopicsAvailable;\n forumManageTopicsAvailable = false;\n if (permissionWasAvailable) {\n void notifyOwnerDms(\n 'The bot no longer has forum administrator access. Existing topics are preserved; restore administrator + \"Manage Topics\" to resume topic creation.',\n );\n }\n return;\n }\n if (\n (status !== \"administrator\" && status !== \"creator\") ||\n update.from?.id === undefined ||\n (!isAllowed(update.from.id) && (!forumMode || forumChat !== update.chat.id))\n ) {\n return;\n }\n void linkForumAndAnnounce(update.from.id, update.chat, update.new_chat_member!).catch((err) =>\n logger.warn({ err, groupId: update.chat.id }, \"telegram adapter: forum auto-connect failed\"),\n );\n });\n\n // ── outbound: RuntimeBus → Telegram ─────────────────────────────────\n const unsubscribe = runtimeBus().subscribe((event) => {\n if (stopped) return;\n if (event.type === \"topic-created\" && forumMode) {\n materializeTopic(event.payload as TopicDto);\n return;\n }\n if (event.type === \"topic-deleted\") {\n handleTopicDeleted(event.topicId);\n return;\n }\n if (event.type === \"message-updated\") {\n const payload = event.payload as {\n messageId?: string;\n patch?: Partial<MessageDto>;\n };\n if (!payload.messageId || !payload.patch) return;\n if (payload.patch.deleted) {\n deleteDeliveredRuntimeMessage(event.topicId, payload.messageId);\n return;\n }\n const current = runtimeMessages.get(payload.messageId);\n if (!current) return;\n const updated = { ...current, ...payload.patch };\n runtimeMessages.set(payload.messageId, updated);\n if (footerEnabled && payload.patch.usage && updated.authorId === \"ai\") {\n const footer = renderTurnFooter(updated);\n if (footer) attachUpdatedFooter(event.topicId, payload.messageId, footer);\n }\n return;\n }\n if (event.type === \"ai-status\") {\n // Telegram typing actions expire after a few seconds. Keep refreshing\n // while the turn is active so long tool/model waits still look alive.\n const status = event.payload as { kind?: string; queryId?: string; label?: string } | null;\n if (status?.kind === \"ai_active\" && typeof client.sendChatAction === \"function\") {\n if (status.queryId) startTypingHeartbeat(event.topicId, status.queryId);\n else sendTyping(event.topicId);\n }\n if (\n status?.queryId &&\n (status.kind === \"ai_done\" || status.kind === \"ai_error\" || status.kind === \"ai_aborted\")\n ) {\n closeToolStatus(status.queryId);\n stopTypingHeartbeat(status.queryId);\n targetByQueryId.delete(status.queryId);\n clearQueryDeliveryState(status.queryId);\n }\n if (status?.kind === \"tool_call\" && status.queryId && status.label) {\n showToolStatus(event.topicId, status.queryId, status.label);\n }\n return;\n }\n if (event.type !== \"message\") return;\n const msg = event.payload as MessageDto;\n if (msg.authorId === userId && msg.sourceAdapter === \"telegram\") return;\n if (msg.kind === \"tool\") return; // tool chatter stays off the chat\n if (!msg.text) return;\n const runtimeMessageId = msg.authorId === \"ai\" ? msg.id : undefined;\n if (runtimeMessageId) {\n runtimeMessages.set(runtimeMessageId, msg);\n if (!msg.queryId) {\n const timer = setTimeout(() => {\n runtimeMessages.delete(runtimeMessageId);\n deliveredByRuntimeMessageId.delete(runtimeMessageId);\n }, 5 * 60_000);\n timer.unref?.();\n }\n }\n // Produced files ride as real attachments; the raw [FILE:] tags are noise.\n const files = extractFileTagPaths(msg.text);\n const rawText = files.length > 0 ? stripFileTags(msg.text) : msg.text;\n const text = msg.authorId === userId && rawText ? `[From: User] ${rawText}` : rawText;\n if (!text && files.length === 0) return;\n routeMessage(event.topicId, { text, files, runtimeMessageId }, msg.queryId);\n });\n\n if (forumMode) {\n // The configured forum's General topic is always the control surface.\n // Reconcile after subscribing so topics created while the adapter was\n // offline (or between startup reads) are materialized without an event gap.\n bindMapping(forumChat, undefined, personalGeneral.id);\n materializeVisibleTopics();\n }\n\n return {\n name: \"telegram\",\n loadTopic: loadExistingTopic,\n unloadTopic: unloadMapping,\n stop(): void {\n if (stopped) return;\n stopped = true;\n outboxWorker.stop();\n for (const timer of typingHeartbeatByQueryId.values()) clearInterval(timer);\n typingHeartbeatByQueryId.clear();\n for (const queryId of toolStatusByQueryId.keys()) closeToolStatus(queryId);\n // Clawgram's clearMediaGroupBuffer behavior: cancel timers and DROP\n // buffered album items — a flush must not fire into a stopped adapter.\n for (const entry of mediaGroups.values()) {\n clearTimeout(entry.timer);\n entry.release();\n }\n mediaGroups.clear();\n inboundQueues.clear();\n unsubscribe();\n store.close();\n },\n };\n}\n",
7
- "export type OutboxAwaitable<T> = T | Promise<T>;\n\nexport interface DurableOutboxEntry {\n attempts: number;\n}\n\nexport interface DurableOutboxFailure {\n message: string;\n retryAfterMs?: number;\n}\n\nexport interface DurableOutboxRetry {\n attempts: number;\n nextTryAt: number;\n error: string;\n}\n\nexport interface DurableOutboxPolicy {\n pollMs: number;\n baseDelayMs: number;\n maxDelayMs: number;\n maxAttempts: number;\n}\n\nexport interface DurableOutboxStore<Entry extends DurableOutboxEntry, Delivery> {\n due(now: number): OutboxAwaitable<readonly Entry[]>;\n hasPending(): OutboxAwaitable<boolean>;\n acknowledge(entry: Entry, delivery: Delivery): OutboxAwaitable<void>;\n discard(entry: Entry): OutboxAwaitable<void>;\n retry(entry: Entry, retry: DurableOutboxRetry): OutboxAwaitable<void>;\n deadLetter(entry: Entry, retry: Omit<DurableOutboxRetry, \"nextTryAt\">): OutboxAwaitable<void>;\n}\n\nexport interface DurableOutboxWorkerOptions<\n Entry extends DurableOutboxEntry,\n Delivery,\n Timer = ReturnType<typeof setTimeout>,\n> {\n store: DurableOutboxStore<Entry, Delivery>;\n deliver(entry: Entry): Promise<Delivery>;\n classifyError(error: unknown): DurableOutboxFailure;\n policy: DurableOutboxPolicy;\n shouldDiscard?(entry: Entry): OutboxAwaitable<boolean>;\n onEntryStart?(entry: Entry): void;\n onEntryEnd?(entry: Entry): void;\n onDeadLetter?(entry: Entry, retry: Omit<DurableOutboxRetry, \"nextTryAt\">): void;\n onError?(error: unknown): void;\n now?: () => number;\n schedule?: (callback: () => void, delayMs: number) => Timer;\n cancel?: (timer: Timer) => void;\n}\n\nexport interface DurableOutboxWorker {\n start(): void;\n wake(): void;\n flush(): Promise<void>;\n stop(): void;\n}\n\nexport function exponentialOutboxBackoff(\n attempts: number,\n policy: Pick<DurableOutboxPolicy, \"baseDelayMs\" | \"maxDelayMs\">,\n): number {\n return Math.min(policy.baseDelayMs * 2 ** Math.max(0, attempts - 1), policy.maxDelayMs);\n}\n\n/** Drive a durable store without coupling retry policy to a transport or database. */\nexport function createDurableOutboxWorker<\n Entry extends DurableOutboxEntry,\n Delivery,\n Timer = ReturnType<typeof setTimeout>,\n>(options: DurableOutboxWorkerOptions<Entry, Delivery, Timer>): DurableOutboxWorker {\n const now = options.now ?? Date.now;\n const schedule =\n options.schedule ??\n ((callback: () => void, delayMs: number) => setTimeout(callback, delayMs) as Timer);\n const cancel =\n options.cancel ?? ((timer: Timer) => clearTimeout(timer as ReturnType<typeof setTimeout>));\n let timer: Timer | undefined;\n let started = false;\n let stopped = false;\n let flushing: Promise<void> | null = null;\n let pendingAcknowledgement: { entry: Entry; delivery: Delivery } | null = null;\n\n const reportError = (error: unknown): void => {\n try {\n options.onError?.(error);\n } catch {\n // An observer must not stop durable delivery recovery.\n }\n };\n\n const scheduleFlush = (): void => {\n if (!started || stopped || timer !== undefined) return;\n timer = schedule(() => {\n timer = undefined;\n void flush();\n }, options.policy.pollMs);\n };\n\n const performFlush = async (): Promise<void> => {\n let entries: readonly Entry[] = [];\n const released = new Set<Entry>();\n const release = (entry: Entry): void => {\n if (released.has(entry)) return;\n released.add(entry);\n options.onEntryEnd?.(entry);\n };\n try {\n if (pendingAcknowledgement) {\n const pending = pendingAcknowledgement;\n try {\n await options.store.acknowledge(pending.entry, pending.delivery);\n pendingAcknowledgement = null;\n } catch (error) {\n reportError(error);\n return;\n }\n }\n entries = await options.store.due(now());\n for (const entry of entries) options.onEntryStart?.(entry);\n for (const entry of entries) {\n if (stopped) return;\n if (await options.shouldDiscard?.(entry)) {\n await options.store.discard(entry);\n release(entry);\n continue;\n }\n let delivery: Delivery;\n try {\n delivery = await options.deliver(entry);\n } catch (error) {\n if (stopped) return;\n const failure = options.classifyError(error);\n const attempts = entry.attempts + 1;\n const retry = { attempts, error: failure.message };\n if (attempts >= options.policy.maxAttempts) {\n await options.store.deadLetter(entry, retry);\n options.onDeadLetter?.(entry, retry);\n } else {\n const delay =\n failure.retryAfterMs ?? exponentialOutboxBackoff(attempts, options.policy);\n await options.store.retry(entry, {\n ...retry,\n nextTryAt: now() + Math.max(0, delay),\n });\n }\n release(entry);\n continue;\n }\n if (stopped) return;\n pendingAcknowledgement = { entry, delivery };\n try {\n await options.store.acknowledge(entry, delivery);\n pendingAcknowledgement = null;\n } catch (error) {\n reportError(error);\n release(entry);\n return;\n }\n release(entry);\n }\n } catch (error) {\n if (!stopped) reportError(error);\n } finally {\n for (const entry of entries) release(entry);\n if (!stopped && started) {\n let hasPending = pendingAcknowledgement !== null;\n if (!hasPending) {\n try {\n hasPending = await options.store.hasPending();\n } catch (error) {\n reportError(error);\n hasPending = true;\n }\n }\n if (hasPending) scheduleFlush();\n }\n }\n };\n\n const flush = (): Promise<void> => {\n if (stopped) return Promise.resolve();\n if (flushing) return flushing;\n flushing = performFlush().finally(() => {\n flushing = null;\n });\n return flushing;\n };\n\n return {\n start(): void {\n if (started || stopped) return;\n started = true;\n scheduleFlush();\n },\n wake(): void {\n scheduleFlush();\n },\n flush,\n stop(): void {\n if (stopped) return;\n stopped = true;\n if (timer !== undefined) cancel(timer);\n timer = undefined;\n },\n };\n}\n",
8
- "/**\n * Persistent (chatId, threadId) ↔ negotium-topic mapping.\n *\n * Forum mode materializes runtime topics as real Telegram forum threads; the\n * thread id Telegram assigns exists nowhere else, so the binding must survive\n * restarts or every subagent room would grow a duplicate thread on reboot.\n * One SQLite file (default `${DATA_DIR}/adapter-telegram.db`) holds all\n * mappings.\n *\n * Schema semantics:\n * - a chat/thread routes to exactly one topic (UNIQUE (chat_id, thread_id);\n * re-binding replaces that one row),\n * - a topic MAY be bound by several chats/threads (fan-out) — there is\n * deliberately no UNIQUE on topic_id, so binding a topic somewhere new\n * never steals it from an existing chat.\n * - `tombstones` records topics whose forum-thread creation failed, so a\n * restart keeps delivering them into the general chat (with a `[title]`\n * prefix) instead of re-attempting creation or dropping messages.\n */\n\nimport { Database } from \"bun:sqlite\";\nimport { mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { DATA_DIR } from \"@negotium/core\";\n\nexport interface PersistedMapping {\n chatId: number;\n /** Absent = the whole chat (DM / supergroup general), not a forum thread. */\n threadId?: number;\n topicId: string;\n}\n\nexport interface PersistedTombstone {\n topicId: string;\n title: string;\n}\n\n/** One durable outbound-retry entry (clawgram's telegram-outbox pattern,\n * simplified to a SQLite table in the adapter's own db). */\nexport interface OutboxEntry {\n id: number;\n chatId: number;\n threadId?: number;\n /** Runtime source message, used to cancel superseded retries. */\n runtimeMessageId?: string;\n /** Footer already embedded in this chunk, if any. */\n footer?: string;\n html: string;\n plain: string;\n attempts: number;\n /** Epoch ms before which the flusher must not retry. */\n nextTryAt: number;\n /** 1 = permanently failed (kept for operator visibility, never retried). */\n dead: boolean;\n lastError?: string;\n}\n\nexport interface TelegramMappingStore {\n load(): PersistedMapping[];\n /** Upsert by (chatId, threadId). Never touches other rows of the same topic. */\n save(mapping: PersistedMapping): void;\n deleteByChat(chatId: number, threadId?: number): void;\n deleteByTopic(topicId: string): void;\n loadTombstones(): PersistedTombstone[];\n saveTombstone(topicId: string, title: string): void;\n deleteTombstone(topicId: string): void;\n clearTombstones(): void;\n /** Forum supergroup selected by auto-connect. A configured environment\n * value may overwrite it, but normal restarts recover it from here. */\n loadForumChatId(): number | undefined;\n saveForumChatId(chatId: number): void;\n clearForumChatId(): void;\n // ── outbound retry queue ──────────────────────────────────────────\n outboxEnqueue(entry: {\n chatId: number;\n threadId?: number;\n runtimeMessageId?: string;\n footer?: string;\n html: string;\n plain: string;\n nextTryAt: number;\n lastError?: string;\n }): void;\n /** Live (non-dead) entries due at `now`, oldest first. */\n outboxDue(now: number): OutboxEntry[];\n /** Write back a transient failure: bump attempts, reschedule. */\n outboxReschedule(id: number, attempts: number, nextTryAt: number, lastError: string): void;\n outboxMarkDead(id: number, attempts: number, lastError: string): void;\n outboxDelete(id: number): void;\n outboxDeleteByChat(chatId: number): void;\n outboxDeleteByRuntimeMessageId(runtimeMessageId: string): void;\n /** All entries (tests/operator inspection). */\n outboxAll(): OutboxEntry[];\n close(): void;\n}\n\n/** Telegram thread ids start at 1, so 0 safely encodes \"no thread\" — needed\n * because SQLite UNIQUE treats NULLs as distinct and would allow duplicate\n * (chat_id, NULL) rows. */\nconst NO_THREAD = 0;\n\ninterface MappingRow {\n chat_id: number;\n thread_id: number;\n topic_id: string;\n}\n\ninterface TombstoneRow {\n topic_id: string;\n title: string;\n}\n\ninterface OutboxRow {\n id: number;\n chat_id: number;\n thread_id: number;\n runtime_message_id: string | null;\n footer: string | null;\n html: string;\n plain: string;\n attempts: number;\n next_try_at: number;\n dead: number;\n last_error: string | null;\n}\n\nfunction outboxRowToEntry(row: OutboxRow): OutboxEntry {\n return {\n id: row.id,\n chatId: row.chat_id,\n ...(row.thread_id !== NO_THREAD ? { threadId: row.thread_id } : {}),\n ...(row.runtime_message_id !== null ? { runtimeMessageId: row.runtime_message_id } : {}),\n ...(row.footer !== null ? { footer: row.footer } : {}),\n html: row.html,\n plain: row.plain,\n attempts: row.attempts,\n nextTryAt: row.next_try_at,\n dead: row.dead === 1,\n ...(row.last_error !== null ? { lastError: row.last_error } : {}),\n };\n}\n\n/** v1 schema had `UNIQUE (topic_id)`, which let INSERT OR REPLACE silently\n * delete another chat's binding of the same topic. SQLite can't drop a\n * constraint in place, so rebuild the young table without it. */\nfunction migrateLegacySchema(db: Database): void {\n const existing = db\n .query(\"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'mappings'\")\n .get() as { sql?: string } | null;\n if (!existing?.sql?.includes(\"UNIQUE (topic_id)\")) return;\n db.run(\"DROP TABLE IF EXISTS mappings_legacy\");\n db.run(\"ALTER TABLE mappings RENAME TO mappings_legacy\");\n createTables(db);\n db.run(\n `INSERT OR IGNORE INTO mappings (chat_id, thread_id, topic_id)\n SELECT chat_id, thread_id, topic_id FROM mappings_legacy`,\n );\n db.run(\"DROP TABLE mappings_legacy\");\n}\n\nfunction createTables(db: Database): void {\n db.run(\n `CREATE TABLE IF NOT EXISTS mappings (\n chat_id INTEGER NOT NULL,\n thread_id INTEGER NOT NULL DEFAULT ${NO_THREAD},\n topic_id TEXT NOT NULL,\n UNIQUE (chat_id, thread_id)\n )`,\n );\n db.run(\n `CREATE TABLE IF NOT EXISTS tombstones (\n topic_id TEXT PRIMARY KEY,\n title TEXT NOT NULL\n )`,\n );\n db.run(\n `CREATE TABLE IF NOT EXISTS outbox (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n chat_id INTEGER NOT NULL,\n thread_id INTEGER NOT NULL DEFAULT ${NO_THREAD},\n runtime_message_id TEXT,\n footer TEXT,\n html TEXT NOT NULL,\n plain TEXT NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n next_try_at INTEGER NOT NULL,\n dead INTEGER NOT NULL DEFAULT 0,\n last_error TEXT\n )`,\n );\n db.run(\n `CREATE TABLE IF NOT EXISTS settings (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )`,\n );\n}\n\nfunction migrateOutboxSchema(db: Database): void {\n try {\n db.run(\"ALTER TABLE outbox ADD COLUMN runtime_message_id TEXT\");\n } catch {\n // Column already exists.\n }\n try {\n db.run(\"ALTER TABLE outbox ADD COLUMN footer TEXT\");\n } catch {\n // Column already exists.\n }\n db.run(\n \"CREATE INDEX IF NOT EXISTS idx_telegram_outbox_runtime_message ON outbox(runtime_message_id)\",\n );\n}\n\n/** Open (creating if needed) the mapping database. `path` is injectable for\n * tests; production uses the node's data dir. */\nexport function openMappingStore(path?: string): TelegramMappingStore {\n const dbPath = path ?? join(DATA_DIR, \"adapter-telegram.db\");\n if (dbPath !== \":memory:\") mkdirSync(dirname(dbPath), { recursive: true });\n const db = new Database(dbPath);\n migrateLegacySchema(db);\n createTables(db);\n migrateOutboxSchema(db);\n return {\n load(): PersistedMapping[] {\n const rows = db\n .query(\"SELECT chat_id, thread_id, topic_id FROM mappings\")\n .all() as MappingRow[];\n return rows.map((row) => ({\n chatId: row.chat_id,\n topicId: row.topic_id,\n ...(row.thread_id !== NO_THREAD ? { threadId: row.thread_id } : {}),\n }));\n },\n save(mapping: PersistedMapping): void {\n // OR REPLACE only collides on (chat_id, thread_id) — re-binding a\n // chat/thread replaces its own row and leaves the topic's other\n // bindings intact.\n db.run(\n `INSERT OR REPLACE INTO mappings (chat_id, thread_id, topic_id)\n VALUES (?, ?, ?)`,\n [mapping.chatId, mapping.threadId ?? NO_THREAD, mapping.topicId],\n );\n },\n deleteByChat(chatId: number, threadId?: number): void {\n db.run(\"DELETE FROM mappings WHERE chat_id = ? AND thread_id = ?\", [\n chatId,\n threadId ?? NO_THREAD,\n ]);\n },\n deleteByTopic(topicId: string): void {\n db.run(\"DELETE FROM mappings WHERE topic_id = ?\", [topicId]);\n },\n loadTombstones(): PersistedTombstone[] {\n const rows = db.query(\"SELECT topic_id, title FROM tombstones\").all() as TombstoneRow[];\n return rows.map((row) => ({ topicId: row.topic_id, title: row.title }));\n },\n saveTombstone(topicId: string, title: string): void {\n db.run(\"INSERT OR REPLACE INTO tombstones (topic_id, title) VALUES (?, ?)\", [topicId, title]);\n },\n deleteTombstone(topicId: string): void {\n db.run(\"DELETE FROM tombstones WHERE topic_id = ?\", [topicId]);\n },\n clearTombstones(): void {\n db.run(\"DELETE FROM tombstones\");\n },\n loadForumChatId(): number | undefined {\n const row = db.query(\"SELECT value FROM settings WHERE key = 'forum_chat_id'\").get() as {\n value: string;\n } | null;\n if (!row) return undefined;\n const value = Number.parseInt(row.value, 10);\n return Number.isSafeInteger(value) ? value : undefined;\n },\n saveForumChatId(chatId: number): void {\n db.run(\"INSERT OR REPLACE INTO settings (key, value) VALUES ('forum_chat_id', ?)\", [\n String(chatId),\n ]);\n },\n clearForumChatId(): void {\n db.run(\"DELETE FROM settings WHERE key = 'forum_chat_id'\");\n },\n outboxEnqueue(entry): void {\n db.run(\n `INSERT INTO outbox\n (chat_id, thread_id, runtime_message_id, footer, html, plain, attempts, next_try_at, last_error)\n VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?)`,\n [\n entry.chatId,\n entry.threadId ?? NO_THREAD,\n entry.runtimeMessageId ?? null,\n entry.footer ?? null,\n entry.html,\n entry.plain,\n entry.nextTryAt,\n entry.lastError ?? null,\n ],\n );\n },\n outboxDue(now: number): OutboxEntry[] {\n const rows = db\n .query(\"SELECT * FROM outbox WHERE dead = 0 AND next_try_at <= ? ORDER BY id ASC\")\n .all(now) as OutboxRow[];\n return rows.map(outboxRowToEntry);\n },\n outboxReschedule(id: number, attempts: number, nextTryAt: number, lastError: string): void {\n db.run(\"UPDATE outbox SET attempts = ?, next_try_at = ?, last_error = ? WHERE id = ?\", [\n attempts,\n nextTryAt,\n lastError,\n id,\n ]);\n },\n outboxMarkDead(id: number, attempts: number, lastError: string): void {\n db.run(\"UPDATE outbox SET dead = 1, attempts = ?, last_error = ? WHERE id = ?\", [\n attempts,\n lastError,\n id,\n ]);\n },\n outboxDelete(id: number): void {\n db.run(\"DELETE FROM outbox WHERE id = ?\", [id]);\n },\n outboxDeleteByChat(chatId: number): void {\n db.run(\"DELETE FROM outbox WHERE chat_id = ?\", [chatId]);\n },\n outboxDeleteByRuntimeMessageId(runtimeMessageId: string): void {\n db.run(\"DELETE FROM outbox WHERE runtime_message_id = ?\", [runtimeMessageId]);\n },\n outboxAll(): OutboxEntry[] {\n const rows = db.query(\"SELECT * FROM outbox ORDER BY id ASC\").all() as OutboxRow[];\n return rows.map(outboxRowToEntry);\n },\n close(): void {\n db.close();\n },\n };\n}\n",
9
- "/**\n * Telegram rendering helpers — ported from clawgram's battle-tested\n * `src/telegram/helpers.ts` (pure functions only; no client, retry, or\n * outbox code — the adapter layers delivery policy on top).\n *\n * Telegram supports only a small HTML subset (`<b> <i> <s> <a> <code> <pre>\n * <blockquote>`), so `markdownToTelegramHtml` converts markdown to exactly\n * that subset and escapes everything else. `splitMessage` enforces\n * Telegram's hard 4096-char message limit.\n */\n\n/** Escape HTML entities */\nexport function escapeHtml(text: string): string {\n return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\n/**\n * Convert Markdown to Telegram-compatible HTML.\n * Handles: code blocks, inline code, bold, italic, strikethrough, links, headings, blockquotes.\n */\nexport function markdownToTelegramHtml(md: string): string {\n // 1. Extract code blocks first to protect their content\n const codeBlocks: string[] = [];\n let text = md.replace(/```(\\w*)\\n([\\s\\S]*?)```/g, (_match, lang, code) => {\n const escaped = escapeHtml(code.replace(/\\n$/, \"\"));\n const tag = lang\n ? `<pre><code class=\"language-${escapeHtml(lang)}\">${escaped}</code></pre>`\n : `<pre>${escaped}</pre>`;\n codeBlocks.push(tag);\n return `\\x00CODEBLOCK${codeBlocks.length - 1}\\x00`;\n });\n\n // 2. Extract inline code\n const inlineCodes: string[] = [];\n text = text.replace(/`([^`\\n]+)`/g, (_match, code) => {\n inlineCodes.push(`<code>${escapeHtml(code)}</code>`);\n return `\\x00INLINE${inlineCodes.length - 1}\\x00`;\n });\n\n // 3. Escape HTML in remaining text\n text = escapeHtml(text);\n\n // 4. Headings → bold (### before ## before #)\n text = text.replace(/^#{1,6}\\s+(.+)$/gm, \"<b>$1</b>\");\n\n // 5. Bold + italic (***text***)\n text = text.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, \"<b><i>$1</i></b>\");\n\n // 6. Bold (**text**)\n text = text.replace(/\\*\\*(.+?)\\*\\*/g, \"<b>$1</b>\");\n\n // 7. Italic (*text*) — avoid matching inside words like file_*name*\n text = text.replace(/(?<!\\w)\\*([^\\s*](?:.*?[^\\s*])?)\\*(?!\\w)/g, \"<i>$1</i>\");\n\n // 8. Strikethrough (~~text~~)\n text = text.replace(/~~(.+?)~~/g, \"<s>$1</s>\");\n\n // 9. Links [text](url)\n text = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\">$1</a>');\n\n // 10. Blockquotes (> lines → <blockquote>)\n text = text.replace(/(?:^&gt; .+\\n?)+/gm, (block) => {\n const content = block.replace(/^&gt; /gm, \"\").trim();\n return `<blockquote>${content}</blockquote>`;\n });\n\n // 11. Restore inline code\n // biome-ignore lint/suspicious/noControlCharactersInRegex: NUL sentinel guards escape sequences\n text = text.replace(/\\x00INLINE(\\d+)\\x00/g, (_m, i) => inlineCodes[Number(i)] as string);\n\n // 12. Restore code blocks\n // biome-ignore lint/suspicious/noControlCharactersInRegex: NUL sentinel guards escape sequences\n text = text.replace(/\\x00CODEBLOCK(\\d+)\\x00/g, (_m, i) => codeBlocks[Number(i)] as string);\n\n return text;\n}\n\n/** Split message into chunks of max 4096 chars */\nexport function splitMessage(text: string, maxLen = 4096): string[] {\n if (text.length <= maxLen) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= maxLen) {\n chunks.push(remaining);\n break;\n }\n // Try to split at newline\n let splitAt = remaining.lastIndexOf(\"\\n\", maxLen);\n const atNewline = splitAt >= maxLen / 2;\n if (!atNewline) splitAt = maxLen;\n chunks.push(remaining.slice(0, splitAt));\n // If we split at a newline, skip it so the next chunk doesn't start with \\n\n remaining = remaining.slice(atNewline ? splitAt + 1 : splitAt);\n }\n return chunks;\n}\n\n/** One deliverable Telegram message: HTML first, plain text as fallback. */\nexport interface OutboundChunk {\n /** Chunk converted to Telegram HTML — send with `parse_mode: \"HTML\"`. */\n html: string;\n /** The original plain chunk — resend this when Telegram rejects the HTML. */\n plain: string;\n}\n\n/**\n * Render an outbound message the way clawgram's `sendSplitHtmlMsg` does:\n * split the PLAIN text into ≤4096-char chunks first (so the limit is\n * measured on what the plain fallback will actually send), then convert\n * each chunk to Telegram HTML independently. Converting per chunk keeps the\n * HTML fallback per chunk — when a `**bold**` span or code fence is cut\n * mid-chunk and yields HTML Telegram rejects with a 400, only that chunk\n * degrades to plain text instead of the whole message.\n */\nexport function renderOutbound(text: string, maxLen = 4096): OutboundChunk[] {\n return splitMessage(text, maxLen).map((plain) => ({\n plain,\n html: markdownToTelegramHtml(plain),\n }));\n}\n",
10
- "/**\n * @negotium/adapter-telegram public API.\n *\n * `startTelegramAdapter` is the whole product: hand it a Telegram client and\n * a negotium node becomes a Telegram bot. Render helpers are exported for\n * hosts that deliver Telegram messages through their own send path.\n */\n\nimport { defineNegotiumAdapter } from \"@negotium/adapter-sdk\";\nimport { startTelegramAdapter } from \"@/adapter\";\n\nexport type { TelegramAdapterHandle, TelegramAdapterOptions } from \"@/adapter\";\nexport type {\n OutboxEntry,\n PersistedMapping,\n PersistedTombstone,\n TelegramMappingStore,\n} from \"@/mapping-store\";\nexport { openMappingStore } from \"@/mapping-store\";\nexport type { OutboundChunk } from \"@/render\";\nexport { escapeHtml, markdownToTelegramHtml, renderOutbound, splitMessage } from \"@/render\";\nexport type { TelegramClientLike, TelegramIncomingMessage } from \"@/types\";\nexport { startTelegramAdapter };\n\n/** Declarative form used by hosts that load adapters from a registry. */\nexport const telegramAdapter = defineNegotiumAdapter({\n name: \"telegram\",\n capabilities: {\n localUserInput: true,\n topicManagement: true,\n externalPlacedTurn: false,\n },\n projection: {\n transcript: \"live-only\",\n historyBackfill: false,\n externalAuthors: \"relayed\",\n },\n start: startTelegramAdapter,\n});\n"
11
- ],
12
- "mappings": "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",
13
- "debugId": "42F29D9EFE4D3DE164756E2164756E21",
14
- "names": []
15
- }