@openacp/cli 0.6.8 → 0.6.10

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 (99) hide show
  1. package/README.md +100 -154
  2. package/dist/{action-detect-6M5GCGAU.js → action-detect-P7ZE4NEM.js} +2 -1
  3. package/dist/{adapter-7GY3N4ZH.js → adapter-ZOANORGM.js} +8 -7
  4. package/dist/{adapter-7GY3N4ZH.js.map → adapter-ZOANORGM.js.map} +1 -1
  5. package/dist/{admin-2HAFXQBG.js → admin-6SYB6XCZ.js} +2 -1
  6. package/dist/{agent-catalog-SBZQRYOD.js → agent-catalog-FC3HGDEQ.js} +2 -1
  7. package/dist/{agent-dependencies-QY5QSULV.js → agent-dependencies-4OWBMZWZ.js} +2 -1
  8. package/dist/{agent-registry-KZFSIRSJ.js → agent-registry-WT4NXPYG.js} +2 -1
  9. package/dist/{agent-store-CGE4G6PA.js → agent-store-VZLFPTZU.js} +2 -1
  10. package/dist/{agents-QJPHNWK2.js → agents-QO7DKARJ.js} +2 -1
  11. package/dist/{api-client-BH2JFHQW.js → api-client-CFQT5U7D.js} +2 -1
  12. package/dist/{autostart-6M3FZAKW.js → autostart-X33OGMX6.js} +2 -1
  13. package/dist/{chunk-RHE2JSYE.js → chunk-2HMQOC7N.js} +2 -2
  14. package/dist/{chunk-SHHMBGB3.js → chunk-33RP6K2O.js} +2 -2
  15. package/dist/{chunk-5SXG7X5D.js → chunk-CS3KCJ5D.js} +103 -55
  16. package/dist/chunk-CS3KCJ5D.js.map +1 -0
  17. package/dist/{chunk-47B7GNOE.js → chunk-LCRLAV4G.js} +541 -191
  18. package/dist/chunk-LCRLAV4G.js.map +1 -0
  19. package/dist/{chunk-LO4Y5WQ7.js → chunk-LGP2YGRL.js} +7 -7
  20. package/dist/{chunk-LO4Y5WQ7.js.map → chunk-LGP2YGRL.js.map} +1 -1
  21. package/dist/{chunk-MZXWCDBU.js → chunk-MKHUZLII.js} +4 -4
  22. package/dist/chunk-MKHUZLII.js.map +1 -0
  23. package/dist/{chunk-YEOY2PBJ.js → chunk-NVPG6JCL.js} +3 -3
  24. package/dist/{chunk-JUYDFUSN.js → chunk-OWP7RZ62.js} +38 -14
  25. package/dist/chunk-OWP7RZ62.js.map +1 -0
  26. package/dist/{chunk-5OVPEDUB.js → chunk-VOIJ6OY4.js} +2 -2
  27. package/dist/chunk-VUNV25KB.js +16 -0
  28. package/dist/{chunk-2J2RBYWN.js → chunk-WTZDAYZX.js} +2 -2
  29. package/dist/cli.js +53 -47
  30. package/dist/cli.js.map +1 -1
  31. package/dist/{config-CQAS6YHR.js → config-6S355X75.js} +3 -2
  32. package/dist/config-editor-QQTZMWGD.js +13 -0
  33. package/dist/{config-registry-HDXFES2D.js → config-registry-AHYI4MYL.js} +2 -1
  34. package/dist/{daemon-K33ZPSEZ.js → daemon-4CS6HMB5.js} +4 -3
  35. package/dist/{discord-VOHXRTCH.js → discord-OMC52Y54.js} +251 -94
  36. package/dist/discord-OMC52Y54.js.map +1 -0
  37. package/dist/dist-UHQK5CXN.js +21151 -0
  38. package/dist/dist-UHQK5CXN.js.map +1 -0
  39. package/dist/doctor-HZZ5BSHB.js +10 -0
  40. package/dist/{doctor-HASEBMUD.js → doctor-OLYBO3V3.js} +5 -4
  41. package/dist/index.js +11 -10
  42. package/dist/{install-cloudflared-FSILDS5J.js → install-cloudflared-Z7VCGOVG.js} +2 -1
  43. package/dist/{install-cloudflared-FSILDS5J.js.map → install-cloudflared-Z7VCGOVG.js.map} +1 -1
  44. package/dist/{install-jq-P6RUBKPV.js → install-jq-HUYSQWKR.js} +2 -1
  45. package/dist/{install-jq-P6RUBKPV.js.map → install-jq-HUYSQWKR.js.map} +1 -1
  46. package/dist/{integrate-O4OCR4SN.js → integrate-PNEHRY2I.js} +2 -1
  47. package/dist/{integrate-O4OCR4SN.js.map → integrate-PNEHRY2I.js.map} +1 -1
  48. package/dist/{log-RCVBXLTN.js → log-NXABYJTT.js} +2 -1
  49. package/dist/{main-DUXVFTDD.js → main-XOZCLFUK.js} +21 -20
  50. package/dist/main-XOZCLFUK.js.map +1 -0
  51. package/dist/{menu-XR2GET2B.js → menu-YY5MKHEK.js} +2 -1
  52. package/dist/{new-session-NHK7TOEW.js → new-session-FEO4J4VU.js} +2 -1
  53. package/dist/{post-upgrade-62LUHDJO.js → post-upgrade-CJG5I7M2.js} +6 -5
  54. package/dist/{post-upgrade-62LUHDJO.js.map → post-upgrade-CJG5I7M2.js.map} +1 -1
  55. package/dist/{session-O6ZPLJIZ.js → session-IUSI7P5S.js} +2 -1
  56. package/dist/{settings-6TF4WIGJ.js → settings-RQPAM4KC.js} +2 -1
  57. package/dist/{setup-RJCEB6FS.js → setup-XHS4OMPM.js} +6 -3
  58. package/dist/{suggest-RST5VOHB.js → suggest-7D6B542M.js} +3 -1
  59. package/dist/{suggest-RST5VOHB.js.map → suggest-7D6B542M.js.map} +1 -1
  60. package/dist/{tunnel-service-NJJH4I26.js → tunnel-service-CJLUH6SZ.js} +3 -2
  61. package/dist/{tunnel-service-NJJH4I26.js.map → tunnel-service-CJLUH6SZ.js.map} +1 -1
  62. package/dist/{version-AXXV6IV2.js → version-NQZBM5M7.js} +2 -1
  63. package/dist/version-NQZBM5M7.js.map +1 -0
  64. package/package.json +15 -1
  65. package/dist/chunk-47B7GNOE.js.map +0 -1
  66. package/dist/chunk-5SXG7X5D.js.map +0 -1
  67. package/dist/chunk-JUYDFUSN.js.map +0 -1
  68. package/dist/chunk-MZXWCDBU.js.map +0 -1
  69. package/dist/config-editor-37BM56WF.js +0 -12
  70. package/dist/discord-VOHXRTCH.js.map +0 -1
  71. package/dist/doctor-W4VGLDVM.js +0 -9
  72. package/dist/main-DUXVFTDD.js.map +0 -1
  73. /package/dist/{action-detect-6M5GCGAU.js.map → action-detect-P7ZE4NEM.js.map} +0 -0
  74. /package/dist/{admin-2HAFXQBG.js.map → admin-6SYB6XCZ.js.map} +0 -0
  75. /package/dist/{agent-catalog-SBZQRYOD.js.map → agent-catalog-FC3HGDEQ.js.map} +0 -0
  76. /package/dist/{agent-dependencies-QY5QSULV.js.map → agent-dependencies-4OWBMZWZ.js.map} +0 -0
  77. /package/dist/{agent-registry-KZFSIRSJ.js.map → agent-registry-WT4NXPYG.js.map} +0 -0
  78. /package/dist/{agent-store-CGE4G6PA.js.map → agent-store-VZLFPTZU.js.map} +0 -0
  79. /package/dist/{agents-QJPHNWK2.js.map → agents-QO7DKARJ.js.map} +0 -0
  80. /package/dist/{api-client-BH2JFHQW.js.map → api-client-CFQT5U7D.js.map} +0 -0
  81. /package/dist/{autostart-6M3FZAKW.js.map → autostart-X33OGMX6.js.map} +0 -0
  82. /package/dist/{chunk-RHE2JSYE.js.map → chunk-2HMQOC7N.js.map} +0 -0
  83. /package/dist/{chunk-SHHMBGB3.js.map → chunk-33RP6K2O.js.map} +0 -0
  84. /package/dist/{chunk-YEOY2PBJ.js.map → chunk-NVPG6JCL.js.map} +0 -0
  85. /package/dist/{chunk-5OVPEDUB.js.map → chunk-VOIJ6OY4.js.map} +0 -0
  86. /package/dist/{config-CQAS6YHR.js.map → chunk-VUNV25KB.js.map} +0 -0
  87. /package/dist/{chunk-2J2RBYWN.js.map → chunk-WTZDAYZX.js.map} +0 -0
  88. /package/dist/{config-editor-37BM56WF.js.map → config-6S355X75.js.map} +0 -0
  89. /package/dist/{config-registry-HDXFES2D.js.map → config-editor-QQTZMWGD.js.map} +0 -0
  90. /package/dist/{daemon-K33ZPSEZ.js.map → config-registry-AHYI4MYL.js.map} +0 -0
  91. /package/dist/{doctor-HASEBMUD.js.map → daemon-4CS6HMB5.js.map} +0 -0
  92. /package/dist/{doctor-W4VGLDVM.js.map → doctor-HZZ5BSHB.js.map} +0 -0
  93. /package/dist/{log-RCVBXLTN.js.map → doctor-OLYBO3V3.js.map} +0 -0
  94. /package/dist/{menu-XR2GET2B.js.map → log-NXABYJTT.js.map} +0 -0
  95. /package/dist/{new-session-NHK7TOEW.js.map → menu-YY5MKHEK.js.map} +0 -0
  96. /package/dist/{session-O6ZPLJIZ.js.map → new-session-FEO4J4VU.js.map} +0 -0
  97. /package/dist/{settings-6TF4WIGJ.js.map → session-IUSI7P5S.js.map} +0 -0
  98. /package/dist/{setup-RJCEB6FS.js.map → settings-RQPAM4KC.js.map} +0 -0
  99. /package/dist/{version-AXXV6IV2.js.map → setup-XHS4OMPM.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/telegram/adapter.ts","../../src/adapters/telegram/topics.ts","../../src/adapters/telegram/commands/new-session.ts","../../src/adapters/telegram/formatting.ts","../../src/adapters/telegram/commands/admin.ts","../../src/adapters/telegram/commands/session.ts","../../src/adapters/telegram/commands/agents.ts","../../src/adapters/telegram/commands/integrate.ts","../../src/adapters/telegram/commands/resume.ts","../../src/adapters/telegram/commands/settings.ts","../../src/adapters/telegram/commands/doctor.ts","../../src/adapters/telegram/commands/tunnel.ts","../../src/adapters/telegram/commands/index.ts","../../src/adapters/telegram/permissions.ts","../../src/adapters/telegram/assistant.ts","../../src/adapters/telegram/activity.ts","../../src/adapters/telegram/send-queue.ts","../../src/adapters/telegram/action-detect.ts","../../src/adapters/telegram/tool-call-tracker.ts","../../src/adapters/telegram/streaming.ts","../../src/adapters/telegram/draft-manager.ts","../../src/adapters/telegram/skill-command-manager.ts"],"sourcesContent":["import { Bot, InputFile } from \"grammy\";\nimport path from \"node:path\";\nimport {\n ChannelAdapter,\n type OpenACPCore,\n type OutgoingMessage,\n type PermissionRequest,\n type NotificationMessage,\n type Session,\n type AgentCommand,\n type FileService,\n} from \"../../core/index.js\";\nimport { createChildLogger } from \"../../core/log.js\";\nconst log = createChildLogger({ module: \"telegram\" });\nimport type { TelegramChannelConfig } from \"./types.js\";\nimport {\n ensureTopics,\n createSessionTopic,\n renameSessionTopic,\n deleteSessionTopic,\n} from \"./topics.js\";\nimport {\n setupCommands,\n setupMenuCallbacks,\n setupDangerousModeCallbacks,\n setupTTSCallbacks,\n setupVerbosityCallbacks,\n setupIntegrateCallbacks,\n buildMenuKeyboard,\n handlePendingWorkspaceInput,\n handlePendingResumeInput,\n STATIC_COMMANDS,\n} from \"./commands/index.js\";\nimport { PermissionHandler } from \"./permissions.js\";\nimport {\n spawnAssistant,\n handleAssistantMessage,\n redirectToAssistant,\n buildWelcomeMessage,\n type SpawnAssistantResult,\n} from \"./assistant.js\";\nimport { escapeHtml } from \"./formatting.js\";\nimport { ActivityTracker } from \"./activity.js\";\nimport { TelegramSendQueue } from \"./send-queue.js\";\nimport { setupActionCallbacks } from \"./action-detect.js\";\nimport { ToolCallTracker } from \"./tool-call-tracker.js\";\nimport { DraftManager } from \"./draft-manager.js\";\nimport { SkillCommandManager } from \"./skill-command-manager.js\";\nimport {\n dispatchMessage,\n type MessageHandlers,\n} from \"../shared/message-dispatcher.js\";\nimport type { DisplayVerbosity } from \"../shared/format-types.js\";\nimport { evaluateNoise } from \"../shared/message-formatter.js\";\n\ninterface TelegramMessageCtx {\n sessionId: string;\n threadId: number;\n}\n\nimport type { ToolCallMeta, ToolUpdateMeta } from \"../shared/format-types.js\";\n\ninterface PlanMetadata {\n entries: Array<{ content: string; status: string; priority: string }>;\n}\n\ninterface UsageMetadata {\n tokensUsed?: number;\n contextSize?: number;\n}\n\n/**\n * Wraps native fetch to work around grammY's polyfilled AbortController.\n * grammY uses abort-controller polyfill whose AbortSignal fails instanceof\n * checks in Node 24+ native fetch. This wrapper re-creates a native\n * AbortSignal from the polyfilled one before passing it to fetch.\n */\nfunction patchedFetch(\n input: RequestInfo | URL,\n init?: RequestInit,\n): Promise<Response> {\n if (init?.signal && !(init.signal instanceof AbortSignal)) {\n const nativeController = new AbortController();\n const polyfillSignal = init.signal as unknown as {\n aborted: boolean;\n addEventListener: (event: string, fn: () => void) => void;\n };\n if (polyfillSignal.aborted) {\n nativeController.abort();\n } else {\n polyfillSignal.addEventListener(\"abort\", () => nativeController.abort());\n }\n init = { ...init, signal: nativeController.signal };\n }\n return fetch(input, init);\n}\n\nexport class TelegramAdapter extends ChannelAdapter<OpenACPCore> {\n private bot!: Bot;\n private telegramConfig: TelegramChannelConfig;\n private permissionHandler!: PermissionHandler;\n private assistantSession: Session | null = null;\n private assistantInitializing = false;\n private notificationTopicId!: number;\n private assistantTopicId!: number;\n private sendQueue = new TelegramSendQueue(3000);\n\n // Extracted managers\n private toolTracker!: ToolCallTracker;\n private draftManager!: DraftManager;\n private skillManager!: SkillCommandManager;\n private fileService!: FileService;\n private sessionTrackers: Map<string, ActivityTracker> = new Map();\n\n private get verbosity(): DisplayVerbosity {\n const live = this.core.configManager.get().channels?.telegram as\n | Record<string, unknown>\n | undefined;\n const v =\n live?.displayVerbosity ??\n (this.telegramConfig as Record<string, unknown>).displayVerbosity;\n if (v === \"low\" || v === \"high\") return v;\n return \"medium\";\n }\n\n private getOrCreateTracker(\n sessionId: string,\n threadId: number,\n ): ActivityTracker {\n let tracker = this.sessionTrackers.get(sessionId);\n if (!tracker) {\n tracker = new ActivityTracker(\n this.bot.api,\n this.telegramConfig.chatId,\n threadId,\n this.sendQueue,\n );\n this.sessionTrackers.set(sessionId, tracker);\n }\n return tracker;\n }\n\n constructor(core: OpenACPCore, config: TelegramChannelConfig) {\n super(core, config);\n this.telegramConfig = config;\n }\n\n async start(): Promise<void> {\n this.bot = new Bot(this.telegramConfig.botToken, {\n client: {\n baseFetchConfig: { duplex: \"half\" } as RequestInit,\n fetch: patchedFetch,\n },\n });\n this.fileService = this.core.fileService;\n\n // Initialize extracted managers\n this.toolTracker = new ToolCallTracker(\n this.bot,\n this.telegramConfig.chatId,\n this.sendQueue,\n );\n this.draftManager = new DraftManager(\n this.bot,\n this.telegramConfig.chatId,\n this.sendQueue,\n );\n this.skillManager = new SkillCommandManager(\n this.bot,\n this.telegramConfig.chatId,\n this.sendQueue,\n this.core.sessionManager,\n );\n\n // Global error handler — prevent unhandled errors from crashing the bot\n this.bot.catch((err) => {\n const rootCause = err.error instanceof Error ? err.error : err;\n log.error({ err: rootCause }, \"Telegram bot error\");\n });\n\n // Auto-retry on 429 (Too Many Requests)\n this.bot.api.config.use(async (prev, method, payload, signal) => {\n const maxRetries = 3;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const result = await prev(method, payload, signal);\n if (\n result.ok ||\n (result as { error_code?: number }).error_code !== 429 ||\n attempt === maxRetries\n ) {\n return result;\n }\n const retryAfter =\n ((result as { parameters?: { retry_after?: number } }).parameters\n ?.retry_after ?? 5) + 1;\n const rateLimitedMethods = [\n \"sendMessage\",\n \"editMessageText\",\n \"editMessageReplyMarkup\",\n ];\n if (rateLimitedMethods.includes(method)) {\n this.sendQueue.onRateLimited();\n }\n log.warn(\n { method, retryAfter, attempt: attempt + 1 },\n \"Rate limited by Telegram, retrying\",\n );\n await new Promise((r) => setTimeout(r, retryAfter * 1000));\n }\n return prev(method, payload, signal);\n });\n\n // Ensure allowed_updates includes callback_query on every poll\n this.bot.api.config.use((prev, method, payload, signal) => {\n if (method === \"getUpdates\") {\n const p = payload as Record<string, unknown>;\n p.allowed_updates = (p.allowed_updates as string[] | undefined) ?? [\n \"message\",\n \"callback_query\",\n ];\n }\n return prev(method, payload, signal);\n });\n\n // Register static commands for Telegram autocomplete\n await this.bot.api.setMyCommands(STATIC_COMMANDS, {\n scope: { type: \"chat\", chat_id: this.telegramConfig.chatId },\n });\n\n // Middleware: only accept updates from configured chatId\n this.bot.use((ctx, next) => {\n const chatId = ctx.chat?.id ?? ctx.callbackQuery?.message?.chat?.id;\n if (chatId !== this.telegramConfig.chatId) return;\n return next();\n });\n\n // Ensure system topics exist\n const topics = await ensureTopics(\n this.bot,\n this.telegramConfig.chatId,\n this.telegramConfig,\n async (updates) => {\n await this.core.configManager.save({\n channels: { telegram: updates },\n });\n },\n );\n this.notificationTopicId = topics.notificationTopicId;\n this.assistantTopicId = topics.assistantTopicId;\n\n // Setup permission handler\n this.permissionHandler = new PermissionHandler(\n this.bot,\n this.telegramConfig.chatId,\n (sessionId) => this.core.sessionManager.getSession(sessionId),\n (notification) => this.sendNotification(notification),\n );\n\n // Callback registration order matters!\n setupDangerousModeCallbacks(this.bot, this.core as OpenACPCore);\n setupTTSCallbacks(this.bot, this.core as OpenACPCore);\n setupVerbosityCallbacks(this.bot, this.core as OpenACPCore);\n setupActionCallbacks(\n this.bot,\n this.core as OpenACPCore,\n this.telegramConfig.chatId,\n () => this.assistantSession?.id,\n );\n setupIntegrateCallbacks(this.bot, this.core as OpenACPCore);\n setupMenuCallbacks(\n this.bot,\n this.core as OpenACPCore,\n this.telegramConfig.chatId,\n {\n notificationTopicId: this.notificationTopicId,\n assistantTopicId: this.assistantTopicId,\n },\n () => {\n if (!this.assistantSession) return undefined;\n return {\n topicId: this.assistantTopicId,\n enqueuePrompt: (p: string) => this.assistantSession!.enqueuePrompt(p),\n };\n },\n );\n setupCommands(\n this.bot,\n this.core as OpenACPCore,\n this.telegramConfig.chatId,\n {\n topicId: this.assistantTopicId,\n getSession: () => this.assistantSession,\n respawn: async () => {\n if (this.assistantSession) {\n await this.assistantSession.destroy();\n this.assistantSession = null;\n }\n const { session, ready } = await spawnAssistant(\n this.core as OpenACPCore,\n this,\n this.assistantTopicId,\n );\n this.assistantSession = session;\n this.assistantInitializing = true;\n ready.then(() => {\n this.assistantInitializing = false;\n });\n },\n },\n );\n this.permissionHandler.setupCallbackHandler();\n\n // /handoff command\n this.bot.command(\"handoff\", async (ctx) => {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) return;\n\n if (\n threadId === this.notificationTopicId ||\n threadId === this.assistantTopicId\n ) {\n await ctx.reply(\"This command only works in session topics.\", {\n message_thread_id: threadId,\n });\n return;\n }\n\n const session = this.core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n const record = session\n ? undefined\n : this.core.sessionManager.getRecordByThread(\n \"telegram\",\n String(threadId),\n );\n\n const agentName = session?.agentName ?? record?.agentName;\n const agentSessionId = session?.agentSessionId ?? record?.agentSessionId;\n\n if (!agentName || !agentSessionId) {\n await ctx.reply(\"No session found for this topic.\", {\n message_thread_id: threadId,\n });\n return;\n }\n\n const { getAgentCapabilities } =\n await import(\"../../core/agent-registry.js\");\n const caps = getAgentCapabilities(agentName);\n\n if (!caps.supportsResume || !caps.resumeCommand) {\n await ctx.reply(\"This agent does not support session transfer.\", {\n message_thread_id: threadId,\n });\n return;\n }\n\n const command = caps.resumeCommand(agentSessionId);\n\n await ctx.reply(\n `Run this in your terminal to continue the session:\\n\\n<code>${command}</code>`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n },\n );\n });\n\n // Setup message routing\n this.setupRoutes();\n\n // Start bot polling\n this.bot.start({\n allowed_updates: [\"message\", \"callback_query\"],\n onStart: () =>\n log.info(\n { chatId: this.telegramConfig.chatId },\n \"Telegram bot started\",\n ),\n });\n\n // Send welcome message\n try {\n const config = this.core.configManager.get();\n const agents = this.core.agentManager.getAvailableAgents();\n const allRecords = this.core.sessionManager.listRecords();\n\n const welcomeText = buildWelcomeMessage({\n activeCount: allRecords.filter(\n (r) => r.status === \"active\" || r.status === \"initializing\",\n ).length,\n errorCount: allRecords.filter((r) => r.status === \"error\").length,\n totalCount: allRecords.length,\n agents: agents.map((a) => a.name),\n defaultAgent: config.defaultAgent,\n });\n\n await this.bot.api.sendMessage(this.telegramConfig.chatId, welcomeText, {\n message_thread_id: this.assistantTopicId,\n parse_mode: \"HTML\",\n reply_markup: buildMenuKeyboard(),\n });\n } catch (err) {\n log.warn({ err }, \"Failed to send welcome message\");\n }\n\n // Spawn assistant in background\n try {\n log.info(\"Spawning assistant session...\");\n const { session, ready } = await spawnAssistant(\n this.core as OpenACPCore,\n this,\n this.assistantTopicId,\n );\n this.assistantSession = session;\n this.assistantInitializing = true;\n log.info(\n { sessionId: session.id },\n \"Assistant session ready, system prompt running in background\",\n );\n ready.then(() => {\n this.assistantInitializing = false;\n log.info(\n { sessionId: session.id },\n \"Assistant ready for user messages\",\n );\n });\n } catch (err) {\n log.error({ err }, \"Failed to spawn assistant\");\n this.bot.api\n .sendMessage(\n this.telegramConfig.chatId,\n `⚠️ <b>Failed to start assistant session.</b>\\n\\n<code>${err instanceof Error ? err.message : String(err)}</code>`,\n { message_thread_id: this.assistantTopicId, parse_mode: \"HTML\" },\n )\n .catch(() => {});\n }\n }\n\n async stop(): Promise<void> {\n if (this.assistantSession) {\n await this.assistantSession.destroy();\n }\n await this.bot.stop();\n log.info(\"Telegram bot stopped\");\n }\n\n private setupRoutes(): void {\n this.bot.on(\"message:text\", async (ctx) => {\n const threadId = ctx.message.message_thread_id;\n const text = ctx.message.text;\n\n // Check for pending workspace input from interactive /new flow\n if (\n await handlePendingWorkspaceInput(\n ctx,\n this.core,\n this.telegramConfig.chatId,\n this.assistantTopicId,\n )\n ) {\n return;\n }\n\n // Check for pending workspace input from interactive /resume flow\n if (\n await handlePendingResumeInput(\n ctx,\n this.core,\n this.telegramConfig.chatId,\n this.assistantTopicId,\n )\n ) {\n return;\n }\n\n // General topic or no thread → redirect to assistant\n if (!threadId) {\n const html = redirectToAssistant(\n this.telegramConfig.chatId,\n this.assistantTopicId,\n );\n await ctx.reply(html, { parse_mode: \"HTML\" });\n return;\n }\n\n // Notification topic → ignore\n if (threadId === this.notificationTopicId) return;\n\n // Strip leading \"/\" from unrecognized commands — registered commands\n // (e.g. /new, /cancel) are already handled by bot.command() above.\n // Unrecognized slash commands can cause agent subprocesses to hang.\n const forwardText = text.startsWith(\"/\") ? text.slice(1) : text;\n\n // Assistant topic → forward to assistant session\n if (threadId === this.assistantTopicId) {\n if (!this.assistantSession) {\n await ctx.reply(\n \"⚠️ Assistant is not available yet. Please try again shortly.\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n await this.draftManager.finalize(\n this.assistantSession.id,\n this.assistantSession.id,\n );\n ctx.replyWithChatAction(\"typing\").catch(() => {});\n handleAssistantMessage(this.assistantSession, forwardText).catch(\n (err) => log.error({ err }, \"Assistant error\"),\n );\n return;\n }\n\n // Session topic → forward to core\n const sessionId = this.core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n )?.id;\n if (sessionId)\n await this.draftManager.finalize(sessionId, this.assistantSession?.id);\n if (sessionId) {\n const tracker = this.sessionTrackers.get(sessionId);\n if (tracker) await tracker.onNewPrompt();\n }\n ctx.replyWithChatAction(\"typing\").catch(() => {});\n this.core\n .handleMessage({\n channelId: \"telegram\",\n threadId: String(threadId),\n userId: String(ctx.from.id),\n text: forwardText,\n })\n .catch((err) => log.error({ err }, \"handleMessage error\"));\n });\n\n // --- Incoming media handlers ---\n\n this.bot.on(\"message:photo\", async (ctx) => {\n const threadId = ctx.message.message_thread_id;\n if (!threadId || threadId === this.notificationTopicId) return;\n\n const photos = ctx.message.photo;\n const largest = photos[photos.length - 1];\n const ext = \".jpg\";\n await this.handleIncomingMedia(\n threadId,\n ctx.from.id,\n largest.file_id,\n `photo${ext}`,\n \"image/jpeg\",\n ctx.message.caption || undefined,\n );\n });\n\n this.bot.on(\"message:document\", async (ctx) => {\n const threadId = ctx.message.message_thread_id;\n if (!threadId || threadId === this.notificationTopicId) return;\n\n const doc = ctx.message.document;\n await this.handleIncomingMedia(\n threadId,\n ctx.from.id,\n doc.file_id,\n doc.file_name || \"document\",\n doc.mime_type || \"application/octet-stream\",\n ctx.message.caption || undefined,\n );\n });\n\n this.bot.on(\"message:voice\", async (ctx) => {\n const threadId = ctx.message.message_thread_id;\n if (!threadId || threadId === this.notificationTopicId) return;\n\n const voice = ctx.message.voice;\n await this.handleIncomingMedia(\n threadId,\n ctx.from.id,\n voice.file_id,\n \"voice.wav\",\n \"audio/wav\",\n undefined,\n true,\n );\n });\n\n this.bot.on(\"message:audio\", async (ctx) => {\n const threadId = ctx.message.message_thread_id;\n if (!threadId || threadId === this.notificationTopicId) return;\n\n const audio = ctx.message.audio;\n await this.handleIncomingMedia(\n threadId,\n ctx.from.id,\n audio.file_id,\n audio.file_name || \"audio.mp3\",\n audio.mime_type || \"audio/mpeg\",\n ctx.message.caption || undefined,\n );\n });\n\n this.bot.on(\"message:video_note\", async (ctx) => {\n const threadId = ctx.message.message_thread_id;\n if (!threadId || threadId === this.notificationTopicId) return;\n\n const videoNote = ctx.message.video_note;\n await this.handleIncomingMedia(\n threadId,\n ctx.from.id,\n videoNote.file_id,\n \"video_note.mp4\",\n \"video/mp4\",\n );\n });\n }\n\n // --- MessageHandlers for dispatchMessage ---\n\n private messageHandlers: MessageHandlers<TelegramMessageCtx> = {\n onThought: async (ctx, _content) => {\n const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);\n await tracker.onThought();\n },\n\n onText: async (ctx, content) => {\n // CRITICAL: This handler must be fully synchronous to preserve text ordering.\n // sendMessage() is not awaited in wireSessionEvents, so multiple text events\n // run concurrently. Any await here creates a gap where subsequent text events\n // process first, causing out-of-order buffer accumulation.\n if (!this.draftManager.hasDraft(ctx.sessionId)) {\n const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);\n tracker.onTextStart().catch(() => {}); // Fire-and-forget, no await\n }\n const draft = this.draftManager.getOrCreate(ctx.sessionId, ctx.threadId);\n draft.append(content.text);\n this.draftManager.appendText(ctx.sessionId, content.text);\n },\n\n onToolCall: async (ctx, content) => {\n const meta = (content.metadata ?? {}) as Partial<ToolCallMeta>;\n const toolName = meta.name ?? content.text ?? \"Tool\";\n const toolKind = String(meta.kind ?? \"other\");\n const noiseAction = evaluateNoise(toolName, toolKind, meta.rawInput);\n if (noiseAction === \"hide\" && this.verbosity !== \"high\") return;\n if (noiseAction === \"collapse\" && this.verbosity === \"low\") return;\n\n const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);\n await tracker.onToolCall();\n await this.draftManager.finalize(\n ctx.sessionId,\n this.assistantSession?.id,\n );\n await this.toolTracker.trackNewCall(\n ctx.sessionId,\n ctx.threadId,\n {\n id: meta.id ?? \"\",\n name: meta.name ?? content.text ?? \"Tool\",\n kind: meta.kind,\n status: meta.status,\n content: meta.content,\n rawInput: meta.rawInput,\n viewerLinks: meta.viewerLinks,\n viewerFilePath: meta.viewerFilePath,\n displaySummary: meta.displaySummary as string | undefined,\n displayTitle: meta.displayTitle as string | undefined,\n displayKind: meta.displayKind as string | undefined,\n },\n this.verbosity,\n );\n },\n\n onToolUpdate: async (ctx, content) => {\n const meta = (content.metadata ?? {}) as Partial<ToolUpdateMeta>;\n await this.toolTracker.updateCall(\n ctx.sessionId,\n {\n id: meta.id ?? \"\",\n name: meta.name ?? content.text ?? \"\",\n kind: meta.kind,\n status: meta.status ?? \"completed\",\n content: meta.content,\n rawInput: meta.rawInput,\n viewerLinks: meta.viewerLinks,\n viewerFilePath: meta.viewerFilePath,\n displaySummary: meta.displaySummary as string | undefined,\n displayTitle: meta.displayTitle as string | undefined,\n displayKind: meta.displayKind as string | undefined,\n },\n this.verbosity,\n );\n },\n\n onPlan: async (ctx, content) => {\n const meta = (content.metadata ?? {}) as Partial<PlanMetadata>;\n const entries = meta.entries ?? [];\n const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);\n await tracker.onPlan(\n entries.map((e) => ({\n content: e.content,\n status: e.status as \"pending\" | \"in_progress\" | \"completed\",\n priority: (e.priority ?? \"medium\") as \"high\" | \"medium\" | \"low\",\n })),\n this.verbosity,\n );\n },\n\n onUsage: async (ctx, content) => {\n const meta = content.metadata as UsageMetadata | undefined;\n await this.draftManager.finalize(\n ctx.sessionId,\n this.assistantSession?.id,\n );\n const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);\n await tracker.sendUsage(meta ?? {}, this.verbosity);\n\n // Notify the Notifications topic that a prompt has completed\n if (\n this.notificationTopicId &&\n ctx.sessionId !== this.assistantSession?.id\n ) {\n const sess = this.core.sessionManager.getSession(ctx.sessionId);\n const sessionName = sess?.name || \"Session\";\n const chatIdStr = String(this.telegramConfig.chatId);\n const numericId = chatIdStr.startsWith(\"-100\")\n ? chatIdStr.slice(4)\n : chatIdStr.replace(\"-\", \"\");\n const usageMsgId = tracker.getUsageMsgId();\n const deepLink = usageMsgId\n ? `https://t.me/c/${numericId}/${ctx.threadId}/${usageMsgId}`\n : `https://t.me/c/${numericId}/${ctx.threadId}`;\n const text = `✅ <b>${escapeHtml(sessionName)}</b>\\nTask completed.\\n\\n<a href=\"${deepLink}\">→ Go to topic</a>`;\n this.sendQueue\n .enqueue(() =>\n this.bot.api.sendMessage(this.telegramConfig.chatId, text, {\n message_thread_id: this.notificationTopicId,\n parse_mode: \"HTML\",\n disable_notification: false,\n }),\n )\n .catch(() => {});\n }\n },\n\n onAttachment: async (ctx, content) => {\n if (!content.attachment) return;\n const { attachment } = content;\n\n // Telegram bot API upload limit: 50MB\n if (attachment.size > 50 * 1024 * 1024) {\n log.warn(\n {\n sessionId: ctx.sessionId,\n fileName: attachment.fileName,\n size: attachment.size,\n },\n \"File too large for Telegram (>50MB)\",\n );\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n `⚠️ File too large to send (${Math.round(attachment.size / 1024 / 1024)}MB): ${escapeHtml(attachment.fileName)}`,\n { message_thread_id: ctx.threadId, parse_mode: \"HTML\" },\n ),\n );\n return;\n }\n\n try {\n const inputFile = new InputFile(attachment.filePath);\n if (attachment.type === \"image\") {\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendPhoto(this.telegramConfig.chatId, inputFile, {\n message_thread_id: ctx.threadId,\n }),\n );\n } else if (attachment.type === \"audio\") {\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendVoice(this.telegramConfig.chatId, inputFile, {\n message_thread_id: ctx.threadId,\n }),\n );\n // Strip [TTS]...[/TTS] block from the text message after voice is sent\n const draft = this.draftManager.getDraft(ctx.sessionId);\n if (draft) {\n draft.stripPattern(/\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/g).catch(() => {});\n }\n } else {\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendDocument(this.telegramConfig.chatId, inputFile, {\n message_thread_id: ctx.threadId,\n }),\n );\n }\n } catch (err) {\n log.error(\n { err, sessionId: ctx.sessionId, fileName: attachment.fileName },\n \"Failed to send attachment\",\n );\n }\n },\n\n onSessionEnd: async (ctx, _content) => {\n await this.draftManager.finalize(\n ctx.sessionId,\n this.assistantSession?.id,\n );\n this.draftManager.cleanup(ctx.sessionId);\n this.toolTracker.cleanup(ctx.sessionId);\n await this.skillManager.cleanup(ctx.sessionId);\n const tracker = this.sessionTrackers.get(ctx.sessionId);\n if (tracker) {\n await tracker.onComplete();\n tracker.destroy();\n this.sessionTrackers.delete(ctx.sessionId);\n } else {\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n `✅ <b>Done</b>`,\n {\n message_thread_id: ctx.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n );\n }\n },\n\n onError: async (ctx, content) => {\n await this.draftManager.finalize(\n ctx.sessionId,\n this.assistantSession?.id,\n );\n const tracker = this.sessionTrackers.get(ctx.sessionId);\n if (tracker) {\n tracker.destroy();\n this.sessionTrackers.delete(ctx.sessionId);\n }\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n `❌ <b>Error:</b> ${escapeHtml(content.text)}`,\n {\n message_thread_id: ctx.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n );\n },\n\n onSystemMessage: async (ctx, content) => {\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(\n this.telegramConfig.chatId,\n escapeHtml(content.text),\n {\n message_thread_id: ctx.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n ),\n );\n },\n };\n\n // --- ChannelAdapter implementations ---\n\n async sendMessage(\n sessionId: string,\n content: OutgoingMessage,\n ): Promise<void> {\n // Suppress assistant messages during system prompt\n if (this.assistantInitializing && sessionId === this.assistantSession?.id)\n return;\n\n const session = this.core.sessionManager.getSession(sessionId);\n if (!session) return;\n\n // Drop messages while topic is being recreated (archive in progress)\n if (session.archiving) return;\n const threadId = Number(session.threadId);\n if (!threadId || isNaN(threadId)) {\n log.warn(\n { sessionId, threadId: session.threadId },\n \"Session has no valid threadId, skipping message\",\n );\n return;\n }\n\n const ctx: TelegramMessageCtx = { sessionId, threadId };\n await dispatchMessage(this.messageHandlers, ctx, content, this.verbosity);\n }\n\n async sendPermissionRequest(\n sessionId: string,\n request: PermissionRequest,\n ): Promise<void> {\n log.info({ sessionId, requestId: request.id }, \"Permission request sent\");\n const session = this.core.sessionManager.getSession(sessionId);\n if (!session) return;\n\n await this.sendQueue.enqueue(() =>\n this.permissionHandler.sendPermissionRequest(session, request),\n );\n }\n\n async sendNotification(notification: NotificationMessage): Promise<void> {\n if (notification.sessionId === this.assistantSession?.id) return;\n\n log.info(\n { sessionId: notification.sessionId, type: notification.type },\n \"Notification sent\",\n );\n if (!this.notificationTopicId) return;\n const emoji: Record<string, string> = {\n completed: \"✅\",\n error: \"❌\",\n permission: \"🔐\",\n input_required: \"💬\",\n };\n let text = `${emoji[notification.type] || \"ℹ️\"} <b>${escapeHtml(notification.sessionName || \"New session\")}</b>\\n`;\n text += escapeHtml(notification.summary);\n\n const deepLink =\n notification.deepLink ??\n (() => {\n const session = this.core.sessionManager.getSession(\n notification.sessionId,\n );\n const threadId = session?.threadId;\n if (!threadId) return undefined;\n const chatIdStr = String(this.telegramConfig.chatId);\n const numericId = chatIdStr.startsWith(\"-100\")\n ? chatIdStr.slice(4)\n : chatIdStr.replace(\"-\", \"\");\n return `https://t.me/c/${numericId}/${threadId}`;\n })();\n\n if (deepLink) {\n text += `\\n\\n<a href=\"${deepLink}\">→ Go to topic</a>`;\n }\n\n // Add Summary button for completed sessions\n const replyMarkup =\n notification.type === \"completed\"\n ? {\n inline_keyboard: [\n [\n {\n text: \"📋 Summary\",\n callback_data: `sm:summary:${notification.sessionId}`,\n },\n ],\n ],\n }\n : undefined;\n\n await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(this.telegramConfig.chatId, text, {\n message_thread_id: this.notificationTopicId,\n parse_mode: \"HTML\",\n disable_notification: false,\n reply_markup: replyMarkup,\n }),\n );\n }\n\n async createSessionThread(sessionId: string, name: string): Promise<string> {\n log.info({ sessionId, name }, \"Session topic created\");\n return String(\n await createSessionTopic(this.bot, this.telegramConfig.chatId, name),\n );\n }\n\n async renameSessionThread(sessionId: string, newName: string): Promise<void> {\n const session = this.core.sessionManager.getSession(sessionId);\n if (!session) return;\n await renameSessionTopic(\n this.bot,\n this.telegramConfig.chatId,\n Number(session.threadId),\n newName,\n );\n await this.core.sessionManager.patchRecord(sessionId, { name: newName });\n }\n\n async deleteSessionThread(sessionId: string): Promise<void> {\n const record = this.core.sessionManager.getSessionRecord(sessionId);\n const platform = record?.platform as\n | import(\"../../core/types.js\").TelegramPlatformData\n | undefined;\n const topicId = platform?.topicId;\n if (!topicId) return;\n\n try {\n await this.bot.api.deleteForumTopic(this.telegramConfig.chatId, topicId);\n } catch (err) {\n log.warn(\n { err, sessionId, topicId },\n \"Failed to delete forum topic (may already be deleted)\",\n );\n }\n }\n\n async sendSkillCommands(\n sessionId: string,\n commands: AgentCommand[],\n ): Promise<void> {\n if (sessionId === this.assistantSession?.id) return;\n\n const session = this.core.sessionManager.getSession(sessionId);\n if (!session) return;\n const threadId = Number(session.threadId);\n if (!threadId) return;\n\n await this.skillManager.send(sessionId, threadId, commands);\n }\n\n private resolveSessionId(threadId: number): string | undefined {\n return this.core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n )?.id;\n }\n\n private async downloadTelegramFile(\n fileId: string,\n ): Promise<{ buffer: Buffer; filePath: string } | null> {\n try {\n const file = await this.bot.api.getFile(fileId);\n if (!file.file_path) return null;\n const url = `https://api.telegram.org/file/bot${this.telegramConfig.botToken}/${file.file_path}`;\n const response = await fetch(url);\n if (!response.ok) return null;\n const buffer = Buffer.from(await response.arrayBuffer());\n return { buffer, filePath: file.file_path };\n } catch (err) {\n log.error({ err }, \"Failed to download file from Telegram\");\n return null;\n }\n }\n\n private async handleIncomingMedia(\n threadId: number,\n userId: number,\n fileId: string,\n fileName: string,\n mimeType: string,\n caption?: string,\n convertOggToWav?: boolean,\n ): Promise<void> {\n const downloaded = await this.downloadTelegramFile(fileId);\n if (!downloaded) return;\n\n let buffer = downloaded.buffer;\n let originalFilePath: string | undefined;\n const sessionId = this.resolveSessionId(threadId) || \"unknown\";\n\n if (convertOggToWav) {\n // Save original OGG for STT (smaller, API-compatible)\n const oggAtt = await this.fileService.saveFile(\n sessionId,\n \"voice.ogg\",\n downloaded.buffer,\n \"audio/ogg\",\n );\n originalFilePath = oggAtt.filePath;\n\n try {\n buffer = await this.fileService.convertOggToWav(buffer);\n } catch (err) {\n log.warn({ err }, \"OGG→WAV conversion failed, saving original OGG\");\n fileName = \"voice.ogg\";\n mimeType = \"audio/ogg\";\n originalFilePath = undefined;\n }\n }\n\n const att = await this.fileService.saveFile(\n sessionId,\n fileName,\n buffer,\n mimeType,\n );\n if (originalFilePath) {\n att.originalFilePath = originalFilePath;\n }\n\n const rawText =\n caption ||\n `[${att.type === \"image\" ? \"Photo\" : att.type === \"audio\" ? \"Audio\" : \"File\"}: ${att.fileName}]`;\n const text = rawText.startsWith(\"/\") ? rawText.slice(1) : rawText;\n\n // Assistant topic\n if (threadId === this.assistantTopicId) {\n if (this.assistantSession) {\n await this.assistantSession.enqueuePrompt(text, [att]);\n }\n return;\n }\n\n // Session topic\n const sid = this.resolveSessionId(threadId);\n if (sid) await this.draftManager.finalize(sid, this.assistantSession?.id);\n this.core\n .handleMessage({\n channelId: \"telegram\",\n threadId: String(threadId),\n userId: String(userId),\n text,\n attachments: [att],\n })\n .catch((err) => log.error({ err }, \"handleMessage error\"));\n }\n\n async cleanupSkillCommands(sessionId: string): Promise<void> {\n await this.skillManager.cleanup(sessionId);\n }\n\n async archiveSessionTopic(sessionId: string): Promise<void> {\n const core = this.core as OpenACPCore;\n const session = core.sessionManager.getSession(sessionId);\n if (!session) return;\n\n const chatId = this.telegramConfig.chatId;\n const oldTopicId = Number(session.threadId);\n // Strip existing 🔄 prefix to avoid stacking on repeated archives\n\n // Set archiving flag — sendMessage will skip while this is true.\n // Flag stays true until core finishes cancelSession (prevents race window).\n session.archiving = true;\n\n // Finalize any pending draft\n await this.draftManager.finalize(session.id, this.assistantSession?.id);\n\n // Cleanup all trackers\n this.draftManager.cleanup(session.id);\n this.toolTracker.cleanup(session.id);\n await this.skillManager.cleanup(session.id);\n const tracker = this.sessionTrackers.get(session.id);\n if (tracker) {\n tracker.destroy();\n this.sessionTrackers.delete(session.id);\n }\n\n // Delete topic (removes all messages)\n await deleteSessionTopic(this.bot, chatId, oldTopicId);\n }\n}\n","import type { Bot } from 'grammy'\n\n// Ensure notification and assistant topics exist, create if needed\n// Returns updated topic IDs\nexport async function ensureTopics(\n bot: Bot,\n chatId: number,\n config: { notificationTopicId: number | null; assistantTopicId: number | null },\n saveConfig: (updates: { notificationTopicId?: number; assistantTopicId?: number }) => Promise<void>,\n): Promise<{ notificationTopicId: number; assistantTopicId: number }> {\n let notificationTopicId = config.notificationTopicId\n let assistantTopicId = config.assistantTopicId\n\n if (notificationTopicId === null) {\n const topic = await bot.api.createForumTopic(chatId, '📋 Notifications')\n notificationTopicId = topic.message_thread_id\n await saveConfig({ notificationTopicId })\n }\n\n if (assistantTopicId === null) {\n const topic = await bot.api.createForumTopic(chatId, '🤖 Assistant')\n assistantTopicId = topic.message_thread_id\n await saveConfig({ assistantTopicId })\n }\n\n return { notificationTopicId, assistantTopicId }\n}\n\n// Create a new forum topic for a session\nexport async function createSessionTopic(\n bot: Bot,\n chatId: number,\n name: string,\n): Promise<number> {\n const topic = await bot.api.createForumTopic(chatId, name)\n return topic.message_thread_id\n}\n\n// Rename an existing forum topic\nexport async function renameSessionTopic(\n bot: Bot,\n chatId: number,\n threadId: number,\n name: string,\n): Promise<void> {\n try {\n await bot.api.editForumTopic(chatId, threadId, { name })\n } catch {\n // Ignore rename failures (topic may be closed/deleted)\n }\n}\n\n// Delete a forum topic and all its messages\nexport async function deleteSessionTopic(\n bot: Bot,\n chatId: number,\n threadId: number,\n): Promise<void> {\n await bot.api.deleteForumTopic(chatId, threadId);\n}\n\n// Build a Telegram deep link to a specific message in a forum topic\nexport function buildDeepLink(chatId: number, threadId: number, messageId?: number): string {\n // chatId for supergroups starts with -100, need to strip it for the link\n const cleanId = String(chatId).replace('-100', '')\n // For forum groups: c/{chatId}/{threadId}/{messageId} links to a specific message\n // Without messageId: c/{chatId}/{threadId} links to the topic itself\n if (messageId && messageId !== threadId) {\n return `https://t.me/c/${cleanId}/${threadId}/${messageId}`\n }\n return `https://t.me/c/${cleanId}/${threadId}`\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport type { Session } from \"../../../core/session.js\";\nimport { escapeHtml } from \"../formatting.js\";\nimport { createSessionTopic, renameSessionTopic, buildDeepLink } from \"../topics.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\nimport { buildSessionControlKeyboard } from \"./admin.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\nconst log = createChildLogger({ module: \"telegram-cmd-new-session\" });\n\ninterface PendingNewSession {\n agentName?: string;\n workspace?: string;\n step: \"agent\" | \"workspace\" | \"workspace_input\" | \"confirm\";\n messageId: number;\n threadId?: number;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst pendingNewSessions = new Map<number, PendingNewSession>();\n\nconst PENDING_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\nfunction cleanupPending(userId: number): void {\n const pending = pendingNewSessions.get(userId);\n if (pending) {\n clearTimeout(pending.timer);\n pendingNewSessions.delete(userId);\n }\n}\n\nfunction botFromCtx(ctx: Context): Bot {\n // createSessionTopic only uses bot.api.createForumTopic\n return { api: ctx.api } as unknown as Bot;\n}\n\nexport async function handleNew(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n assistant?: CommandsAssistantContext,\n): Promise<void> {\n const rawMatch = (ctx as Context & { match: unknown }).match;\n const matchStr = typeof rawMatch === \"string\" ? rawMatch : \"\";\n const args = matchStr.split(\" \").filter(Boolean);\n const agentName = args[0];\n const workspace = args[1];\n\n // Full args → create directly\n if (agentName && workspace) {\n await createSessionDirect(ctx, core, chatId, agentName, workspace);\n return;\n }\n\n // In assistant topic → forward to assistant for conversational handling\n const currentThreadId = ctx.message?.message_thread_id;\n if (assistant && currentThreadId === assistant.topicId) {\n const assistantSession = assistant.getSession();\n if (assistantSession) {\n const prompt = agentName\n ? `User wants to create a new session with agent \"${agentName}\" but didn't specify a workspace. Ask them which project directory to use as workspace.`\n : `User wants to create a new session. Guide them through choosing an agent and workspace (project directory).`;\n await assistantSession.enqueuePrompt(prompt);\n return;\n }\n }\n\n // Outside assistant topic → interactive agent picker flow\n await showAgentPicker(ctx, core, chatId, agentName);\n}\n\nasync function startWorkspaceStep(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n userId: number,\n agentName: string,\n): Promise<void> {\n const config = core.configManager.get();\n const baseDir = config.workspace.baseDir;\n\n const keyboard = new InlineKeyboard()\n .text(`📁 Use ${baseDir}`, \"m:new:ws:default\")\n .row()\n .text(\"✏️ Enter project path\", \"m:new:ws:custom\");\n\n const text =\n `📁 <b>Where should ${escapeHtml(agentName)} work?</b>\\n\\n` +\n `Enter the path to your project folder — the agent will read, write, and run code there.\\n\\n` +\n `Or use the default directory below:`;\n\n let msg;\n try {\n const pending = pendingNewSessions.get(userId);\n if (pending?.messageId) {\n await ctx.api.editMessageText(chatId, pending.messageId, text, {\n parse_mode: \"HTML\",\n reply_markup: keyboard,\n });\n msg = { message_id: pending.messageId };\n } else {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n } catch {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n\n cleanupPending(userId);\n pendingNewSessions.set(userId, {\n agentName,\n step: \"workspace\",\n messageId: msg.message_id,\n threadId: ctx.message?.message_thread_id ?? (ctx.callbackQuery?.message as { message_thread_id?: number } | undefined)?.message_thread_id,\n timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\nasync function startConfirmStep(\n ctx: Context,\n chatId: number,\n userId: number,\n agentName: string,\n workspace: string,\n): Promise<void> {\n const keyboard = new InlineKeyboard()\n .text(\"✅ Create\", \"m:new:confirm\")\n .text(\"❌ Cancel\", \"m:new:cancel\");\n\n const text =\n `✅ <b>Ready to create session?</b>\\n\\n` +\n `<b>Agent:</b> ${escapeHtml(agentName)}\\n` +\n `<b>Project:</b> <code>${escapeHtml(workspace)}</code>`;\n\n let msg;\n try {\n const pending = pendingNewSessions.get(userId);\n if (pending?.messageId) {\n await ctx.api.editMessageText(chatId, pending.messageId, text, {\n parse_mode: \"HTML\",\n reply_markup: keyboard,\n });\n msg = { message_id: pending.messageId };\n } else {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n } catch {\n msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n }\n\n cleanupPending(userId);\n pendingNewSessions.set(userId, {\n agentName,\n workspace,\n step: \"confirm\",\n messageId: msg.message_id,\n threadId: ctx.message?.message_thread_id ?? (ctx.callbackQuery?.message as { message_thread_id?: number } | undefined)?.message_thread_id,\n timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\nexport async function createSessionDirect(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n agentName: string,\n workspace: string,\n): Promise<number | null> {\n log.info({ userId: ctx.from?.id, agentName, workspace }, \"New session command (direct)\");\n\n let threadId: number | undefined;\n try {\n const topicName = `🔄 New Session`;\n threadId = await createSessionTopic(botFromCtx(ctx), chatId, topicName);\n\n await ctx.api.sendMessage(chatId, `⏳ Setting up session, please wait...`, {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n\n const session = await core.handleNewSession(\"telegram\", agentName, workspace);\n session.threadId = String(threadId);\n\n await core.sessionManager.patchRecord(session.id, { platform: { topicId: threadId } });\n\n const finalName = `🔄 ${session.agentName} — New Session`;\n try {\n await ctx.api.editForumTopic(chatId, threadId, { name: finalName });\n } catch { /* ignore rename failures */ }\n\n await ctx.api.sendMessage(\n chatId,\n `✅ <b>Session started</b>\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>\\n\\n` +\n `This is your coding session — chat here to work with the agent.`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n reply_markup: buildSessionControlKeyboard(session.id, false, false),\n },\n );\n\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n return threadId ?? null;\n } catch (err) {\n log.error({ err }, \"Session creation failed\");\n if (threadId) {\n try { await ctx.api.deleteForumTopic(chatId, threadId); } catch { /* ignore */ }\n }\n const message = err instanceof Error ? err.message : (typeof err === 'object' ? JSON.stringify(err) : String(err));\n await ctx.reply(`❌ ${escapeHtml(message)}`, { parse_mode: \"HTML\" });\n return null;\n }\n}\n\nexport async function handleNewChat(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) {\n await ctx.reply(\n \"Use /newchat inside a session topic to inherit its config.\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n // Resolve agent config from existing session/record BEFORE spawning\n const currentSession = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n let agentName: string | undefined;\n let workspace: string | undefined;\n\n if (currentSession) {\n agentName = currentSession.agentName;\n workspace = currentSession.workingDirectory;\n } else {\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await ctx.reply(\"No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n agentName = record.agentName;\n workspace = record.workingDir;\n }\n\n let newThreadId: number | undefined;\n try {\n // Create topic FIRST so threadId is ready before session events fire\n const topicName = `🔄 ${agentName} — New Chat`;\n newThreadId = await createSessionTopic(\n botFromCtx(ctx),\n chatId,\n topicName,\n );\n\n // Notify in the original topic immediately with a deep link to the new one\n const topicLink = buildDeepLink(chatId, newThreadId);\n await ctx.reply(\n `✅ New chat created → <a href=\"${topicLink}\">Open topic</a>`,\n { parse_mode: \"HTML\" },\n );\n\n await ctx.api.sendMessage(chatId, `⏳ Setting up session, please wait...`, {\n message_thread_id: newThreadId,\n parse_mode: \"HTML\",\n });\n\n const session = await core.handleNewSession(\n \"telegram\",\n agentName,\n workspace,\n );\n session.threadId = String(newThreadId);\n\n // Persist platform mapping for new chat\n await core.sessionManager.patchRecord(session.id, { platform: {\n topicId: newThreadId,\n } });\n\n await ctx.api.sendMessage(\n chatId,\n `✅ New chat (same agent &amp; workspace)\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>`,\n {\n message_thread_id: newThreadId,\n parse_mode: \"HTML\",\n reply_markup: buildSessionControlKeyboard(session.id, false, false),\n },\n );\n\n // Warm up model cache in background while user types\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n } catch (err) {\n // Clean up orphaned topic if session creation failed\n if (newThreadId) {\n try {\n await ctx.api.deleteForumTopic(chatId, newThreadId);\n } catch {\n /* ignore cleanup failures */\n }\n }\n const message = err instanceof Error ? err.message : String(err);\n await ctx.reply(`❌ ${escapeHtml(message)}`, { parse_mode: \"HTML\" });\n }\n}\n\nexport async function executeNewSession(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n agentName?: string,\n workspace?: string,\n): Promise<{ session: Session; threadId: number; firstMsgId: number }> {\n // Create topic with generic name first (same as original handleNew)\n const threadId = await createSessionTopic(bot, chatId, \"🔄 New Session\");\n\n const setupMsg = await bot.api.sendMessage(chatId, \"⏳ Setting up session, please wait...\", {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n const firstMsgId = setupMsg.message_id;\n\n try {\n // core.handleNewSession() already wires events internally — do NOT call wireSessionEvents again\n const session = await core.handleNewSession(\n \"telegram\",\n agentName,\n workspace,\n );\n session.threadId = String(threadId);\n\n await core.sessionManager.patchRecord(session.id, { platform: {\n topicId: threadId,\n } });\n\n // Rename topic with agent name after session is created\n const finalName = `🔄 ${session.agentName} — New Session`;\n await renameSessionTopic(bot, chatId, threadId, finalName);\n\n // Warm up model cache in background while user types\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n\n return { session, threadId, firstMsgId };\n } catch (err) {\n // Clean up orphaned topic on failure\n try {\n await bot.api.deleteForumTopic(chatId, threadId);\n } catch {\n /* best effort */\n }\n throw err;\n }\n}\n\n/**\n * Check if a text message is a workspace path input for the interactive new session flow.\n * Returns true if the message was handled (caller should not process further).\n */\nexport async function handlePendingWorkspaceInput(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n assistantTopicId?: number,\n): Promise<boolean> {\n const userId = ctx.from?.id;\n if (!userId) return false;\n const pending = pendingNewSessions.get(userId);\n if (!pending || !ctx.message?.text) return false;\n // Accept text input at both \"workspace\" step (user types directly instead of pressing buttons)\n // and \"workspace_input\" step (user pressed \"Custom path\" button)\n if (pending.step !== \"workspace_input\" && pending.step !== \"workspace\") return false;\n\n // Only intercept in assistant topic (or no-thread/general) — never in session topics\n const threadId = ctx.message.message_thread_id;\n if (threadId && threadId !== assistantTopicId) return false;\n\n let workspace = ctx.message.text.trim();\n if (!workspace || !pending.agentName) {\n await ctx.reply(\"⚠️ Please enter a valid directory path.\", { parse_mode: \"HTML\" });\n return true;\n }\n\n // Relative path (no / or ~ prefix) → resolve against baseDir\n if (!workspace.startsWith(\"/\") && !workspace.startsWith(\"~\")) {\n const baseDir = core.configManager.get().workspace.baseDir;\n workspace = `${baseDir.replace(/\\/$/, \"\")}/${workspace}`;\n }\n\n await startConfirmStep(ctx, chatId, userId, pending.agentName, workspace);\n return true;\n}\n\n/**\n * Start the interactive new session flow (agent → workspace → confirm).\n * Used by action-detect when workspace is not provided.\n */\nexport async function startInteractiveNewSession(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n agentName?: string,\n): Promise<void> {\n await showAgentPicker(ctx, core, chatId, agentName);\n}\n\n/**\n * Shared agent picker logic used by both handleNew and startInteractiveNewSession.\n * Shows agent selection keyboard if multiple agents installed, otherwise skips to workspace step.\n */\nasync function showAgentPicker(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n agentName?: string,\n): Promise<void> {\n const userId = ctx.from?.id;\n if (!userId) return;\n\n const installedEntries = core.agentCatalog.getInstalledEntries();\n const agentKeys = Object.keys(installedEntries);\n const config = core.configManager.get();\n\n // If agent provided or only 1 agent → skip to workspace step\n if (agentName || agentKeys.length === 1) {\n const selectedAgent = agentName || config.defaultAgent;\n await startWorkspaceStep(ctx, core, chatId, userId, selectedAgent);\n return;\n }\n\n // Multiple agents → show agent selection\n const keyboard = new InlineKeyboard();\n for (const key of agentKeys) {\n const agent = installedEntries[key]!;\n const label = key === config.defaultAgent\n ? `${agent.name} (default)`\n : agent.name;\n keyboard.text(label, `m:new:agent:${key}`).row();\n }\n\n const msg = await ctx.reply(\n `🤖 <b>Choose an agent:</b>`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n\n cleanupPending(userId);\n const threadId = ctx.message?.message_thread_id\n ?? (ctx.callbackQuery?.message as { message_thread_id?: number } | undefined)?.message_thread_id;\n pendingNewSessions.set(userId, {\n step: \"agent\",\n messageId: msg.message_id,\n threadId,\n timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\nexport function setupNewSessionCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n): void {\n bot.callbackQuery(/^m:new:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired or network — ignore */ }\n\n if (data.startsWith(\"m:new:agent:\")) {\n const agentName = data.replace(\"m:new:agent:\", \"\");\n const userId = ctx.from?.id;\n if (userId) await startWorkspaceStep(ctx, core, chatId, userId, agentName);\n return;\n }\n if (data === \"m:new:ws:default\") {\n const userId = ctx.from?.id;\n if (!userId) return;\n const pending = pendingNewSessions.get(userId);\n if (!pending?.agentName) return;\n const workspace = core.configManager.get().workspace.baseDir;\n await startConfirmStep(ctx, chatId, userId, pending.agentName, workspace);\n return;\n }\n if (data === \"m:new:ws:custom\") {\n const userId = ctx.from?.id;\n if (!userId) return;\n const pending = pendingNewSessions.get(userId);\n if (!pending?.agentName) return;\n try {\n await ctx.api.editMessageText(\n chatId,\n pending.messageId,\n `✏️ <b>Enter your project path:</b>\\n\\n` +\n `Full path like <code>~/code/my-project</code>\\n` +\n `Or just the folder name like <code>my-project</code> (will use ${core.configManager.get().workspace.baseDir}/)`,\n { parse_mode: \"HTML\" },\n );\n } catch {\n await ctx.reply(\n `✏️ <b>Enter your project path:</b>`,\n { parse_mode: \"HTML\" },\n );\n }\n clearTimeout(pending.timer);\n pending.step = \"workspace_input\";\n pending.timer = setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS);\n return;\n }\n if (data === \"m:new:confirm\") {\n const userId = ctx.from?.id;\n if (!userId) return;\n const pending = pendingNewSessions.get(userId);\n if (!pending?.agentName || !pending?.workspace) return;\n cleanupPending(userId);\n const confirmMsgId = pending.messageId;\n try {\n await ctx.api.editMessageText(chatId, confirmMsgId, `⏳ Creating session...`, { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n const resultThreadId = await createSessionDirect(ctx, core, chatId, pending.agentName, pending.workspace);\n try {\n if (resultThreadId) {\n const link = buildDeepLink(chatId, resultThreadId);\n await ctx.api.editMessageText(chatId, confirmMsgId, `✅ Session created → <a href=\"${link}\">Open topic</a>`, { parse_mode: \"HTML\" });\n } else {\n await ctx.api.editMessageText(chatId, confirmMsgId, `❌ Session creation failed.`, { parse_mode: \"HTML\" });\n }\n } catch { /* ignore */ }\n return;\n }\n if (data === \"m:new:cancel\") {\n const userId = ctx.from?.id;\n if (userId) cleanupPending(userId);\n try {\n await ctx.editMessageText(\"❌ Session creation cancelled.\", { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n return;\n }\n });\n}\n","import type { UsageSummary } from \"../../core/types.js\";\nimport type {\n ToolCallMeta,\n ToolUpdateMeta,\n ViewerLinks,\n} from \"../shared/format-types.js\";\nimport { STATUS_ICONS, KIND_ICONS } from \"../shared/format-types.js\";\nimport {\n progressBar,\n formatTokens,\n truncateContent,\n stripCodeFences,\n splitMessage as sharedSplitMessage,\n} from \"../shared/format-utils.js\";\nimport {\n extractContentText,\n formatToolSummary,\n formatToolTitle,\n resolveToolIcon,\n} from \"../shared/message-formatter.js\";\nimport type { DisplayVerbosity } from \"../shared/format-types.js\";\n\nexport function escapeHtml(text: string | undefined | null): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nexport function markdownToTelegramHtml(md: string): string {\n // Step 1: Extract code blocks and inline code into placeholders\n const codeBlocks: string[] = [];\n const inlineCodes: string[] = [];\n\n // Extract fenced code blocks (```lang\\n...\\n```)\n let text = md.replace(\n /```(\\w*)\\n?([\\s\\S]*?)```/g,\n (_match, lang: string, code: string) => {\n const index = codeBlocks.length;\n const escapedCode = escapeHtml(code);\n const langAttr = lang ? ` class=\"language-${escapeHtml(lang)}\"` : \"\";\n codeBlocks.push(`<pre><code${langAttr}>${escapedCode}</code></pre>`);\n return `\\x00CODE_BLOCK_${index}\\x00`;\n },\n );\n\n // Extract inline code (`...`)\n text = text.replace(/`([^`]+)`/g, (_match, code: string) => {\n const index = inlineCodes.length;\n inlineCodes.push(`<code>${escapeHtml(code)}</code>`);\n return `\\x00INLINE_CODE_${index}\\x00`;\n });\n\n // Step 2: Escape HTML in remaining text\n text = escapeHtml(text);\n\n // Step 3: Apply markdown transformations\n // Bold: **text** → <b>text</b>\n text = text.replace(/\\*\\*(.+?)\\*\\*/g, \"<b>$1</b>\");\n\n // Italic: *text* → <i>text</i> (but not the ** used for bold)\n text = text.replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, \"<i>$1</i>\");\n\n // Links: [text](url) → <a href=\"url\">text</a>\n // Note: after escapeHtml, parentheses are not affected, but we need to handle\n // the escaped brackets properly. Since [ ] and ( ) are not escaped, this works directly.\n text = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\">$1</a>');\n\n // Step 4: Restore fenced code blocks\n text = text.replace(/\\x00CODE_BLOCK_(\\d+)\\x00/g, (_match, idx: string) => {\n return codeBlocks[parseInt(idx, 10)];\n });\n\n // Step 5: Restore inline code\n text = text.replace(/\\x00INLINE_CODE_(\\d+)\\x00/g, (_match, idx: string) => {\n return inlineCodes[parseInt(idx, 10)];\n });\n\n return text;\n}\n\nexport function formatToolCall(\n tool: ToolCallMeta,\n verbosity: DisplayVerbosity = \"medium\",\n): string {\n const si = resolveToolIcon(tool);\n const name = tool.name || \"Tool\";\n const label =\n verbosity === \"low\"\n ? formatToolTitle(name, tool.rawInput, tool.displayTitle)\n : formatToolSummary(name, tool.rawInput, tool.displaySummary);\n let text = `${si} <b>${escapeHtml(label)}</b>`;\n // viewer links always shown regardless of verbosity\n text += formatViewerLinks(tool.viewerLinks, tool.viewerFilePath);\n // high only: rawInput + content\n if (verbosity === \"high\") {\n text += formatHighDetails(tool.rawInput, tool.content, 3800);\n }\n return text;\n}\n\nexport function formatToolUpdate(\n update: ToolUpdateMeta,\n verbosity: DisplayVerbosity = \"medium\",\n): string {\n const si = resolveToolIcon(update);\n const name = update.name || \"Tool\";\n const label =\n verbosity === \"low\"\n ? formatToolTitle(name, update.rawInput, update.displayTitle)\n : formatToolSummary(name, update.rawInput, update.displaySummary);\n let text = `${si} <b>${escapeHtml(label)}</b>`;\n text += formatViewerLinks(update.viewerLinks, update.viewerFilePath);\n if (verbosity === \"high\") {\n text += formatHighDetails(update.rawInput, update.content, 3800);\n }\n return text;\n}\n\nfunction formatHighDetails(\n rawInput: unknown,\n content: unknown,\n maxLen: number,\n): string {\n let text = \"\";\n if (rawInput) {\n const inputStr =\n typeof rawInput === \"string\"\n ? rawInput\n : JSON.stringify(rawInput, null, 2);\n if (inputStr && inputStr !== \"{}\") {\n text += `\\n<b>Input:</b>\\n<pre>${escapeHtml(truncateContent(inputStr, maxLen))}</pre>`;\n }\n }\n const details = stripCodeFences(extractContentText(content));\n if (details) {\n text += `\\n<b>Output:</b>\\n<pre>${escapeHtml(truncateContent(details, maxLen))}</pre>`;\n }\n return text;\n}\n\nfunction formatViewerLinks(links?: ViewerLinks, filePath?: string): string {\n if (!links) return \"\";\n const fileName = filePath ? filePath.split(\"/\").pop() || filePath : \"\";\n let text = \"\\n\";\n if (links.file)\n text += `\\n📄 <a href=\"${escapeHtml(links.file)}\">View ${escapeHtml(fileName || \"file\")}</a>`;\n if (links.diff)\n text += `\\n📝 <a href=\"${escapeHtml(links.diff)}\">View diff${fileName ? ` — ${escapeHtml(fileName)}` : \"\"}</a>`;\n return text;\n}\n\nexport function formatPlan(\n plan: { entries: Array<{ content: string; status: string }> },\n verbosity: DisplayVerbosity = \"medium\",\n): string {\n const { entries } = plan;\n // medium: summary count only\n if (verbosity === \"medium\") {\n const done = entries.filter((e) => e.status === \"completed\").length;\n return `📋 <b>Plan:</b> ${done}/${entries.length} steps completed`;\n }\n // high: full entries\n const statusIcon: Record<string, string> = {\n pending: \"⬜\",\n in_progress: \"🔄\",\n completed: \"✅\",\n };\n const lines = entries.map(\n (e, i) =>\n `${statusIcon[e.status] || \"⬜\"} ${i + 1}. ${escapeHtml(e.content)}`,\n );\n return `<b>Plan:</b>\\n${lines.join(\"\\n\")}`;\n}\n\nexport function formatUsage(\n usage: { tokensUsed?: number; contextSize?: number; cost?: number },\n verbosity: DisplayVerbosity = \"medium\",\n): string {\n const { tokensUsed, contextSize, cost } = usage;\n if (tokensUsed == null) return \"📊 Usage data unavailable\";\n\n // medium: compact one-line\n if (verbosity === \"medium\") {\n const costStr = cost != null ? ` · $${cost.toFixed(2)}` : \"\";\n return `📊 ${formatTokens(tokensUsed)} tokens${costStr}`;\n }\n\n // high: full progress bar + cost\n if (contextSize == null) return `📊 ${formatTokens(tokensUsed)} tokens`;\n const ratio = tokensUsed / contextSize;\n const pct = Math.round(ratio * 100);\n const bar = progressBar(ratio);\n const emoji = pct >= 85 ? \"⚠️\" : \"📊\";\n let text = `${emoji} ${formatTokens(tokensUsed)} / ${formatTokens(contextSize)} tokens\\n${bar} ${pct}%`;\n if (cost != null) text += `\\n💰 $${cost.toFixed(2)}`;\n return text;\n}\n\nconst PERIOD_LABEL: Record<string, string> = {\n today: \"Today\",\n week: \"This Week\",\n month: \"This Month\",\n all: \"All Time\",\n};\n\nexport function formatUsageReport(\n summaries: UsageSummary[],\n budgetStatus: {\n status: string;\n used: number;\n budget: number;\n percent: number;\n },\n): string {\n const hasData = summaries.some((s) => s.recordCount > 0);\n if (!hasData) {\n return \"📊 <b>Usage Report</b>\\n\\nNo usage data yet.\";\n }\n\n const formatCost = (n: number) => `$${n.toFixed(2)}`;\n const lines: string[] = [\"📊 <b>Usage Report</b>\"];\n\n for (const summary of summaries) {\n lines.push(\"\");\n lines.push(\n `── <b>${PERIOD_LABEL[summary.period] ?? summary.period}</b> ──`,\n );\n lines.push(\n `💰 ${formatCost(summary.totalCost)} · 🔤 ${formatTokens(summary.totalTokens)} tokens · 📋 ${summary.sessionCount} sessions`,\n );\n\n // Show budget bar only on the month section\n if (summary.period === \"month\" && budgetStatus.budget > 0) {\n const bar = progressBar(budgetStatus.used / budgetStatus.budget);\n lines.push(\n `Budget: ${formatCost(budgetStatus.used)} / ${formatCost(budgetStatus.budget)} (${budgetStatus.percent}%)`,\n );\n lines.push(`${bar} ${budgetStatus.percent}%`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nexport function formatSummary(summary: string, sessionName?: string): string {\n const header = sessionName\n ? `📋 <b>Summary — ${escapeHtml(sessionName)}</b>`\n : \"📋 <b>Session Summary</b>\";\n return `${header}\\n\\n${escapeHtml(summary)}`;\n}\n\nexport function splitMessage(text: string, maxLength = 3800): string[] {\n return sharedSplitMessage(text, maxLength);\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport { escapeHtml } from \"../formatting.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\nconst log = createChildLogger({ module: \"telegram-cmd-admin\" });\n\nexport function buildDangerousModeKeyboard(\n sessionId: string,\n enabled: boolean,\n): InlineKeyboard {\n return new InlineKeyboard().text(\n enabled ? \"🔐 Disable Dangerous Mode\" : \"☠️ Enable Dangerous Mode\",\n `d:${sessionId}`,\n );\n}\n\nexport function setupDangerousModeCallbacks(bot: Bot, core: OpenACPCore): void {\n bot.callbackQuery(/^d:/, async (ctx) => {\n const sessionId = ctx.callbackQuery.data.slice(2);\n const session = core.sessionManager.getSession(sessionId);\n\n // Session live in memory — toggle directly\n if (session) {\n session.dangerousMode = !session.dangerousMode;\n log.info(\n { sessionId, dangerousMode: session.dangerousMode },\n \"Dangerous mode toggled via button\",\n );\n core.sessionManager\n .patchRecord(sessionId, { dangerousMode: session.dangerousMode })\n .catch(() => {});\n\n const toastText = session.dangerousMode\n ? \"☠️ Dangerous mode enabled — permissions auto-approved\"\n : \"🔐 Dangerous mode disabled — permissions shown normally\";\n try {\n await ctx.answerCallbackQuery({ text: toastText });\n } catch {\n /* expired */\n }\n\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: buildSessionControlKeyboard(\n sessionId,\n session.dangerousMode,\n session.voiceMode === \"on\",\n ),\n });\n } catch {\n /* ignore */\n }\n return;\n }\n\n // Session not in memory (e.g. after restart) — toggle directly in store\n const record = core.sessionManager.getSessionRecord(sessionId);\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n try {\n await ctx.answerCallbackQuery({\n text: \"⚠️ Session not found or already ended.\",\n });\n } catch {\n /* expired */\n }\n return;\n }\n\n const newDangerousMode = !(record.dangerousMode ?? false);\n core.sessionManager\n .patchRecord(sessionId, { dangerousMode: newDangerousMode })\n .catch(() => {});\n log.info(\n { sessionId, dangerousMode: newDangerousMode },\n \"Dangerous mode toggled via button (store-only, session not in memory)\",\n );\n\n const toastText = newDangerousMode\n ? \"☠️ Dangerous mode enabled — permissions auto-approved\"\n : \"🔐 Dangerous mode disabled — permissions shown normally\";\n try {\n await ctx.answerCallbackQuery({ text: toastText });\n } catch {\n /* expired */\n }\n\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: buildSessionControlKeyboard(\n sessionId,\n newDangerousMode,\n false,\n ),\n });\n } catch {\n /* ignore */\n }\n });\n}\n\nexport async function handleEnableDangerous(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) {\n await ctx.reply(\"⚠️ This command only works inside a session topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n const session = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n if (session) {\n if (session.dangerousMode) {\n await ctx.reply(\"☠️ Dangerous mode is already enabled.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n session.dangerousMode = true;\n core.sessionManager\n .patchRecord(session.id, { dangerousMode: true })\n .catch(() => {});\n } else {\n // Session not in memory (e.g. after restart) — update store directly\n const record = core.sessionManager.getRecordByThread(\n \"telegram\",\n String(threadId),\n );\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await ctx.reply(\"⚠️ No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n if (record.dangerousMode) {\n await ctx.reply(\"☠️ Dangerous mode is already enabled.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n core.sessionManager\n .patchRecord(record.sessionId, { dangerousMode: true })\n .catch(() => {});\n }\n await ctx.reply(\n `⚠️ <b>Dangerous mode enabled</b>\\n\\nAll permission requests will be auto-approved. Claude can run arbitrary commands without asking.\\n\\nUse /disable_dangerous to restore normal behaviour.`,\n { parse_mode: \"HTML\" },\n );\n}\n\nexport async function handleDisableDangerous(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) {\n await ctx.reply(\"⚠️ This command only works inside a session topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n const session = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n if (session) {\n if (!session.dangerousMode) {\n await ctx.reply(\"🔐 Dangerous mode is already disabled.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n session.dangerousMode = false;\n core.sessionManager\n .patchRecord(session.id, { dangerousMode: false })\n .catch(() => {});\n } else {\n // Session not in memory (e.g. after restart) — update store directly\n const record = core.sessionManager.getRecordByThread(\n \"telegram\",\n String(threadId),\n );\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await ctx.reply(\"⚠️ No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n if (!record.dangerousMode) {\n await ctx.reply(\"🔐 Dangerous mode is already disabled.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n core.sessionManager\n .patchRecord(record.sessionId, { dangerousMode: false })\n .catch(() => {});\n }\n await ctx.reply(\n \"🔐 <b>Dangerous mode disabled</b>\\n\\nPermission requests will be shown normally.\",\n { parse_mode: \"HTML\" },\n );\n}\n\nexport function buildTTSKeyboard(\n sessionId: string,\n enabled: boolean,\n): InlineKeyboard {\n return new InlineKeyboard().text(\n enabled ? \"🔊 Text to Speech\" : \"🔇 Text to Speech\",\n `v:${sessionId}`,\n );\n}\n\nexport function buildSessionControlKeyboard(\n sessionId: string,\n dangerousMode: boolean,\n voiceMode: boolean,\n): InlineKeyboard {\n return new InlineKeyboard()\n .text(\n dangerousMode ? \"🔐 Disable Dangerous Mode\" : \"☠️ Enable Dangerous Mode\",\n `d:${sessionId}`,\n )\n .row()\n .text(\n voiceMode ? \"🔊 Text to Speech\" : \"🔇 Text to Speech\",\n `v:${sessionId}`,\n );\n}\n\nexport function setupTTSCallbacks(bot: Bot, core: OpenACPCore): void {\n bot.callbackQuery(/^v:/, async (ctx) => {\n const sessionId = ctx.callbackQuery.data.slice(2);\n const session = core.sessionManager.getSession(sessionId);\n\n if (!session) {\n try {\n await ctx.answerCallbackQuery({\n text: \"⚠️ Session not found or not active.\",\n });\n } catch {}\n return;\n }\n\n const newMode = session.voiceMode === \"on\" ? \"off\" : \"on\";\n session.setVoiceMode(newMode);\n\n const toastText =\n newMode === \"on\"\n ? \"🔊 Text to Speech enabled\"\n : \"🔇 Text to Speech disabled\";\n try {\n await ctx.answerCallbackQuery({ text: toastText });\n } catch {}\n\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: buildSessionControlKeyboard(\n sessionId,\n session.dangerousMode,\n newMode === \"on\",\n ),\n });\n } catch {\n /* ignore */\n }\n });\n}\n\nexport async function handleTTS(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) {\n await ctx.reply(\"⚠️ This command only works inside a session topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n const session = await core.getOrResumeSession(\"telegram\", String(threadId));\n if (!session) {\n await ctx.reply(\"⚠️ No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n return;\n }\n\n const args = ctx.message?.text?.split(/\\s+/).slice(1) ?? [];\n const arg = args[0]?.toLowerCase();\n\n if (arg === \"on\") {\n session.setVoiceMode(\"on\");\n await ctx.reply(\"🔊 Text to Speech enabled for this session.\", {\n parse_mode: \"HTML\",\n });\n } else if (arg === \"off\") {\n session.setVoiceMode(\"off\");\n await ctx.reply(\"🔇 Text to Speech disabled.\", { parse_mode: \"HTML\" });\n } else {\n session.setVoiceMode(\"next\");\n await ctx.reply(\"🔊 Text to Speech enabled for the next message.\", {\n parse_mode: \"HTML\",\n });\n }\n}\n\n// ─── Verbosity ─────────────────────────────────────────────────────────────\n\nconst VERBOSITY_LABELS: Record<string, string> = {\n low: \"🔇 Low\",\n medium: \"📊 Medium\",\n high: \"📖 High\",\n};\n\nexport async function handleVerbosity(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n const args = ctx.message?.text?.split(/\\s+/).slice(1) ?? [];\n const arg = args[0]?.toLowerCase();\n\n if (arg === \"low\" || arg === \"medium\" || arg === \"high\") {\n await core.configManager.save(\n { channels: { telegram: { displayVerbosity: arg } } },\n \"channels.telegram.displayVerbosity\",\n );\n await ctx.reply(\n `${VERBOSITY_LABELS[arg]} Display verbosity set to <b>${arg}</b>.`,\n { parse_mode: \"HTML\" },\n );\n } else {\n const current =\n (\n core.configManager.get().channels?.telegram as\n | Record<string, unknown>\n | undefined\n )?.displayVerbosity ?? \"medium\";\n await ctx.reply(\n `📊 Current verbosity: <b>${current}</b>\\n\\nUsage: <code>/verbosity low|medium|high</code>\\n\\n• <b>low</b> — minimal output, title only\\n• <b>medium</b> — balanced (default)\\n• <b>high</b> — full detail with content`,\n { parse_mode: \"HTML\" },\n );\n }\n}\n\nexport function setupVerbosityCallbacks(bot: Bot, core: OpenACPCore): void {\n bot.callbackQuery(/^vb:/, async (ctx) => {\n const level = ctx.callbackQuery.data.slice(3);\n if (level !== \"low\" && level !== \"medium\" && level !== \"high\") return;\n\n await core.configManager.save(\n { channels: { telegram: { displayVerbosity: level } } },\n \"channels.telegram.displayVerbosity\",\n );\n\n try {\n await ctx.answerCallbackQuery({\n text: `${VERBOSITY_LABELS[level]} Verbosity: ${level}`,\n });\n } catch {}\n });\n}\n\nexport async function handleUpdate(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n if (!core.requestRestart) {\n await ctx.reply(\n \"⚠️ Update is not available (no restart handler registered).\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n const { getCurrentVersion, getLatestVersion, compareVersions, runUpdate } =\n await import(\"../../../cli/version.js\");\n const current = getCurrentVersion();\n const statusMsg = await ctx.reply(\n `🔍 Checking for updates... (current: v${escapeHtml(current)})`,\n { parse_mode: \"HTML\" },\n );\n\n const latest = await getLatestVersion();\n if (!latest) {\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n \"❌ Could not check for updates.\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n if (compareVersions(current, latest) >= 0) {\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n `✅ Already up to date (v${escapeHtml(current)}).`,\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n `⬇️ Updating v${escapeHtml(current)} → v${escapeHtml(latest)}...`,\n { parse_mode: \"HTML\" },\n );\n\n const ok = await runUpdate();\n if (!ok) {\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n \"❌ Update failed. Try manually: <code>npm install -g @openacp/cli@latest</code>\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n `✅ Updated to v${escapeHtml(latest)}. Restarting...`,\n { parse_mode: \"HTML\" },\n );\n\n await new Promise((r) => setTimeout(r, 500));\n await core.requestRestart();\n}\n\nexport async function handleRestart(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n if (!core.requestRestart) {\n await ctx.reply(\n \"⚠️ Restart is not available (no restart handler registered).\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n await ctx.reply(\n \"🔄 <b>Restarting OpenACP...</b>\\nRebuilding and restarting. Be back shortly.\",\n { parse_mode: \"HTML\" },\n );\n // Give Telegram a moment to deliver the message before shutting down\n await new Promise((r) => setTimeout(r, 500));\n await core.requestRestart();\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport type { Session } from \"../../../core/session.js\";\nimport { escapeHtml, formatUsageReport, formatSummary } from \"../formatting.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\nconst log = createChildLogger({ module: \"telegram-cmd-session\" });\n\nexport async function handleCancel(\n ctx: Context,\n core: OpenACPCore,\n assistant?: CommandsAssistantContext,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) return;\n\n // In assistant topic: forward to assistant for confirmation\n if (assistant && threadId === assistant.topicId) {\n const assistantSession = assistant.getSession();\n if (assistantSession) {\n await assistantSession.enqueuePrompt(\n \"User wants to cancel a session. Confirm which session to cancel.\",\n );\n return;\n }\n }\n\n const session = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n if (session) {\n log.info({ sessionId: session.id }, \"Abort prompt command\");\n await session.abortPrompt();\n await ctx.reply(\"⛔ Prompt aborted. Session is still active — send a new message to continue.\", { parse_mode: \"HTML\" });\n return;\n }\n\n // Fallback: session not in memory — nothing to abort, but session can\n // still be resumed when the user sends a new message.\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (record && record.status !== \"error\") {\n log.info({ sessionId: record.sessionId, status: record.status }, \"Cancel command — no active prompt to abort\");\n await ctx.reply(\"ℹ️ No active prompt to cancel. Send a new message to resume the session.\", { parse_mode: \"HTML\" });\n }\n}\n\nexport async function handleStatus(ctx: Context, core: OpenACPCore): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (threadId) {\n const session = core.sessionManager.getSessionByThread(\n \"telegram\",\n String(threadId),\n );\n if (session) {\n await ctx.reply(\n `<b>Session:</b> ${escapeHtml(session.name || session.id)}\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Status:</b> ${escapeHtml(session.status)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>\\n` +\n `<b>Queue:</b> ${session.queueDepth} pending`,\n { parse_mode: \"HTML\" },\n );\n } else {\n // Fallback: show stored session info when not loaded in memory (e.g. after restart)\n const record = core.sessionManager.getRecordByThread(\"telegram\", String(threadId));\n if (record) {\n await ctx.reply(\n `<b>Session:</b> ${escapeHtml(record.name || record.sessionId)}\\n` +\n `<b>Agent:</b> ${escapeHtml(record.agentName)}\\n` +\n `<b>Status:</b> ${escapeHtml(record.status)} (not loaded)\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(record.workingDir)}</code>`,\n { parse_mode: \"HTML\" },\n );\n } else {\n await ctx.reply(\"No active session in this topic.\", {\n parse_mode: \"HTML\",\n });\n }\n }\n } else {\n const sessions = core.sessionManager.listSessions(\"telegram\");\n const active = sessions.filter(\n (s) => s.status === \"active\" || s.status === \"initializing\",\n );\n await ctx.reply(\n `<b>OpenACP Status</b>\\n` +\n `Active sessions: ${active.length}\\n` +\n `Total sessions: ${sessions.length}`,\n { parse_mode: \"HTML\" },\n );\n }\n}\n\nexport async function handleTopics(ctx: Context, core: OpenACPCore): Promise<void> {\n try {\n const allRecords = core.sessionManager.listRecords();\n\n // Only show sessions that have a Telegram topic (skip headless/CLI-only)\n const records = allRecords.filter((r) => {\n const platform = r.platform as { topicId?: number };\n return !!platform?.topicId;\n });\n\n const headlessCount = allRecords.length - records.length;\n\n if (records.length === 0) {\n const extra = headlessCount > 0 ? ` (${headlessCount} headless hidden)` : \"\";\n await ctx.reply(`No sessions with topics found.${extra}`, { parse_mode: \"HTML\" });\n return;\n }\n\n const statusEmoji: Record<string, string> = {\n active: \"🟢\",\n initializing: \"🟡\",\n finished: \"✅\",\n error: \"❌\",\n cancelled: \"⛔\",\n };\n\n // Sort: active/initializing first, then by lastActiveAt desc\n const statusOrder: Record<string, number> = { active: 0, initializing: 1, error: 2, finished: 3, cancelled: 4 };\n records.sort((a, b) => (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5));\n\n const MAX_DISPLAY = 30;\n const displayed = records.slice(0, MAX_DISPLAY);\n\n const lines = displayed.map((r) => {\n const emoji = statusEmoji[r.status] || \"⚪\";\n const name = r.name?.trim();\n const label = name ? escapeHtml(name) : `<i>${escapeHtml(r.agentName)} session</i>`;\n return `${emoji} ${label} <code>[${r.status}]</code>`;\n });\n\n const header = `<b>Sessions: ${records.length}</b>` +\n (headlessCount > 0 ? ` (${headlessCount} headless hidden)` : \"\");\n const truncated = records.length > MAX_DISPLAY ? `\\n\\n<i>...and ${records.length - MAX_DISPLAY} more</i>` : \"\";\n\n // Count by status for cleanup buttons (include headless sessions)\n const finishedCount = allRecords.filter((r) => r.status === \"finished\").length;\n const errorCount = allRecords.filter((r) => r.status === \"error\" || r.status === \"cancelled\").length;\n\n const keyboard = new InlineKeyboard();\n if (finishedCount > 0) {\n keyboard.text(`Cleanup finished (${finishedCount})`, \"m:cleanup:finished\").row();\n }\n if (errorCount > 0) {\n keyboard.text(`Cleanup errors (${errorCount})`, \"m:cleanup:errors\").row();\n }\n if (finishedCount + errorCount > 0) {\n keyboard.text(`Cleanup all non-active (${finishedCount + errorCount})`, \"m:cleanup:all\").row();\n }\n keyboard.text(`⚠️ Cleanup ALL (${allRecords.length})`, \"m:cleanup:everything\").row();\n keyboard.text(\"Refresh\", \"m:topics\");\n\n await ctx.reply(\n `${header}\\n\\n${lines.join(\"\\n\")}${truncated}`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch (err) {\n log.error({ err }, \"handleTopics error\");\n await ctx.reply(\"❌ Failed to list sessions.\", { parse_mode: \"HTML\" }).catch(() => {});\n }\n}\n\nexport async function handleCleanup(ctx: Context, core: OpenACPCore, chatId: number, statuses: string[]): Promise<void> {\n const allRecords = core.sessionManager.listRecords();\n const cleanable = allRecords.filter((r) => statuses.includes(r.status));\n\n if (cleanable.length === 0) {\n await ctx.reply(\"Nothing to clean up.\", { parse_mode: \"HTML\" });\n return;\n }\n\n let deleted = 0;\n let failed = 0;\n\n for (const record of cleanable) {\n try {\n const topicId = (record.platform as { topicId?: number })?.topicId;\n if (topicId) {\n try {\n await ctx.api.deleteForumTopic(chatId, topicId);\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId, topicId }, \"Failed to delete forum topic during cleanup\");\n }\n }\n await core.sessionManager.removeRecord(record.sessionId);\n deleted++;\n } catch (err) {\n log.error({ err, sessionId: record.sessionId }, \"Failed to cleanup session\");\n failed++;\n }\n }\n\n await ctx.reply(\n `🗑 Cleaned up <b>${deleted}</b> sessions${failed > 0 ? ` (${failed} failed)` : \"\"}.`,\n { parse_mode: \"HTML\" },\n );\n}\n\nexport async function handleCleanupEverything(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n): Promise<void> {\n const allRecords = core.sessionManager.listRecords();\n const cleanable = allRecords.filter((r) => {\n const platform = r.platform as { topicId?: number };\n if (systemTopicIds && platform?.topicId && (platform.topicId === systemTopicIds.notificationTopicId || platform.topicId === systemTopicIds.assistantTopicId)) return false;\n return true;\n });\n\n if (cleanable.length === 0) {\n await ctx.reply(\"Nothing to clean up.\", { parse_mode: \"HTML\" });\n return;\n }\n\n // Group by status for breakdown\n const statusCounts = new Map<string, number>();\n for (const r of cleanable) {\n statusCounts.set(r.status, (statusCounts.get(r.status) ?? 0) + 1);\n }\n\n const statusEmoji: Record<string, string> = {\n active: \"🟢\", initializing: \"🟡\", finished: \"✅\", error: \"❌\", cancelled: \"⛔\",\n };\n\n const breakdown = Array.from(statusCounts.entries())\n .map(([status, count]) => `${statusEmoji[status] ?? \"⚪\"} ${status}: ${count}`)\n .join(\"\\n\");\n\n const activeCount = (statusCounts.get(\"active\") ?? 0) + (statusCounts.get(\"initializing\") ?? 0);\n const activeWarning = activeCount > 0\n ? `\\n\\n⚠️ <b>${activeCount} active session(s) will be cancelled and their agents stopped!</b>`\n : \"\";\n\n const keyboard = new InlineKeyboard()\n .text(\"Yes, delete all\", \"m:cleanup:everything:confirm\")\n .text(\"Cancel\", \"m:topics\");\n\n await ctx.reply(\n `<b>Delete ${cleanable.length} topics?</b>\\n\\n` +\n `This will:\\n` +\n `• Delete all session topics from this group\\n` +\n `• Cancel any running agent sessions\\n` +\n `• Remove all session records\\n\\n` +\n `<b>Breakdown:</b>\\n${breakdown}${activeWarning}\\n\\n` +\n `<i>Notifications and Assistant topics will NOT be deleted.</i>`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n}\n\nexport async function handleCleanupEverythingConfirmed(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n): Promise<void> {\n const allRecords = core.sessionManager.listRecords();\n const cleanable = allRecords.filter((r) => {\n const platform = r.platform as { topicId?: number };\n if (systemTopicIds && platform?.topicId && (platform.topicId === systemTopicIds.notificationTopicId || platform.topicId === systemTopicIds.assistantTopicId)) return false;\n return true;\n });\n\n if (cleanable.length === 0) {\n await ctx.reply(\"Nothing to clean up.\", { parse_mode: \"HTML\" });\n return;\n }\n\n let deleted = 0;\n let failed = 0;\n\n for (const record of cleanable) {\n try {\n // Cancel active sessions first\n if (record.status === \"active\" || record.status === \"initializing\") {\n try {\n await core.sessionManager.cancelSession(record.sessionId);\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId }, \"Failed to cancel session during cleanup\");\n }\n }\n\n const topicId = (record.platform as { topicId?: number })?.topicId;\n if (topicId) {\n try {\n await ctx.api.deleteForumTopic(chatId, topicId);\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId, topicId }, \"Failed to delete forum topic during cleanup\");\n }\n }\n await core.sessionManager.removeRecord(record.sessionId);\n deleted++;\n } catch (err) {\n log.error({ err, sessionId: record.sessionId }, \"Failed to cleanup session\");\n failed++;\n }\n }\n\n await ctx.reply(\n `🗑 Cleaned up <b>${deleted}</b> sessions${failed > 0 ? ` (${failed} failed)` : \"\"}.`,\n { parse_mode: \"HTML\" },\n );\n}\n\nexport async function executeCancelSession(\n core: OpenACPCore,\n excludeSessionId?: string,\n): Promise<Session | null> {\n const sessions = core.sessionManager\n .listSessions(\"telegram\")\n .filter((s) => s.status === \"active\" && s.id !== excludeSessionId)\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n\n const session = sessions[0];\n if (!session) return null;\n\n await session.abortPrompt();\n return session;\n}\n\nexport function setupSessionCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n): void {\n bot.callbackQuery(/^m:cleanup/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired */ }\n\n switch (data) {\n case \"m:cleanup:finished\":\n await handleCleanup(ctx, core, chatId, [\"finished\"]);\n break;\n case \"m:cleanup:errors\":\n await handleCleanup(ctx, core, chatId, [\"error\", \"cancelled\"]);\n break;\n case \"m:cleanup:all\":\n await handleCleanup(ctx, core, chatId, [\"finished\", \"error\", \"cancelled\"]);\n break;\n case \"m:cleanup:everything\":\n await handleCleanupEverything(ctx, core, chatId, systemTopicIds);\n break;\n case \"m:cleanup:everything:confirm\":\n await handleCleanupEverythingConfirmed(ctx, core, chatId, systemTopicIds);\n break;\n }\n });\n}\n\nexport async function handleUsage(ctx: Context, core: OpenACPCore): Promise<void> {\n if (!core.usageStore) {\n await ctx.reply(\"📊 Usage tracking is disabled.\", { parse_mode: \"HTML\" });\n return;\n }\n\n const rawMatch = (ctx as Context & { match: unknown }).match;\n const period = typeof rawMatch === \"string\" ? rawMatch.trim().toLowerCase() : \"\";\n\n let summaries: ReturnType<typeof core.usageStore.query>[];\n\n if (period === \"today\" || period === \"week\" || period === \"month\") {\n summaries = [core.usageStore.query(period)];\n } else {\n summaries = [\n core.usageStore.query(\"month\"),\n core.usageStore.query(\"week\"),\n core.usageStore.query(\"today\"),\n ];\n }\n\n const budgetStatus = core.usageBudget\n ? core.usageBudget.getStatus()\n : { status: \"ok\" as const, used: 0, budget: 0, percent: 0 };\n\n const text = formatUsageReport(summaries, budgetStatus);\n await ctx.reply(text, { parse_mode: \"HTML\" });\n}\n\nexport async function handleArchive(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) return;\n\n // Check in-memory session first, then fall back to stored record\n const session = core.sessionManager.getSessionByThread(\"telegram\", String(threadId));\n const record = !session ? core.sessionManager.getRecordByThread(\"telegram\", String(threadId)) : undefined;\n // Use sessionId if available, otherwise use threadId as identifier for orphan topics\n const identifier = session?.id ?? record?.sessionId ?? `topic:${threadId}`;\n\n await ctx.reply(\n \"⚠️ <b>Archive this session?</b>\\n\\n\" +\n \"This will:\\n\" +\n \"• Delete this topic and all messages\\n\" +\n \"• Stop the agent session (if running)\\n\" +\n \"• Remove the session record\\n\\n\" +\n \"<i>This action cannot be undone.</i>\",\n {\n parse_mode: \"HTML\",\n reply_markup: new InlineKeyboard()\n .text(\"🗑 Yes, archive\", `ar:yes:${identifier}`)\n .text(\"❌ Cancel\", `ar:no:${identifier}`),\n },\n );\n}\n\nexport async function handleArchiveConfirm(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n): Promise<void> {\n const data = ctx.callbackQuery?.data;\n if (!data) return;\n\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired */ }\n\n // Format: ar:<action>:<identifier> where identifier is sessionId or topic:<threadId>\n const [, action, ...rest] = data.split(\":\");\n const identifier = rest.join(\":\");\n\n if (action === \"no\") {\n await ctx.editMessageText(\"Archive cancelled.\", { parse_mode: \"HTML\" });\n return;\n }\n\n // action === \"yes\"\n await ctx.editMessageText(\"🔄 Archiving...\", { parse_mode: \"HTML\" });\n\n // Handle orphan topics (no session/record) — delete topic directly\n if (identifier.startsWith(\"topic:\")) {\n const topicId = Number(identifier.slice(\"topic:\".length));\n try {\n await ctx.api.deleteForumTopic(chatId, topicId);\n core.notificationManager.notifyAll({\n sessionId: \"system\",\n sessionName: `Orphan topic #${topicId}`,\n type: \"completed\",\n summary: `Orphan topic #${topicId} archived and deleted.`,\n });\n } catch (err) {\n core.notificationManager.notifyAll({\n sessionId: \"system\",\n sessionName: `Orphan topic #${topicId}`,\n type: \"error\",\n summary: `Failed to delete orphan topic #${topicId}: ${(err as Error).message}`,\n });\n }\n return;\n }\n\n const result = await core.archiveSession(identifier);\n if (result.ok) {\n core.notificationManager.notifyAll({\n sessionId: identifier,\n type: \"completed\",\n summary: `Session archived and deleted.`,\n });\n } else {\n try {\n await ctx.editMessageText(`❌ Failed to archive: <code>${escapeHtml(result.error)}</code>`, { parse_mode: \"HTML\" });\n } catch {\n core.notificationManager.notifyAll({\n sessionId: identifier,\n type: \"error\",\n summary: `Failed to archive session \"${identifier}\": ${result.error}`,\n });\n }\n }\n}\n\nexport async function handleSummary(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n const threadId = ctx.message?.message_thread_id;\n if (!threadId) return;\n\n const session = core.sessionManager.getSessionByThread(\"telegram\", String(threadId));\n const record = !session ? core.sessionManager.getRecordByThread(\"telegram\", String(threadId)) : undefined;\n const sessionId = session?.id ?? record?.sessionId;\n\n if (!sessionId) {\n await ctx.reply(\n \"ℹ️ <b>/summary</b> works in session topics — it asks the agent to summarize the session.\\n\\nGo to a session topic and type /summary there.\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n await ctx.replyWithChatAction(\"typing\");\n const result = await core.summarizeSession(sessionId);\n\n if (result.ok) {\n await ctx.reply(formatSummary(result.summary, session?.name ?? record?.name), { parse_mode: \"HTML\" });\n } else {\n await ctx.reply(`⚠️ ${escapeHtml(result.error)}`, { parse_mode: \"HTML\" });\n }\n}\n\nexport async function handleSummaryCallback(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n): Promise<void> {\n const data = ctx.callbackQuery?.data;\n if (!data) return;\n\n const sessionId = data.replace(\"sm:summary:\", \"\");\n\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired */ }\n\n // Find thread ID from active session or stored record\n const session = core.sessionManager.getSession(sessionId);\n const record = !session ? core.sessionManager.getSessionRecord(sessionId) : undefined;\n const threadId = session ? Number(session.threadId) : ((record?.platform as any)?.topicId ?? 0);\n if (!threadId) return;\n\n await ctx.api.sendMessage(chatId, \"📋 Generating summary...\", {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n\n const result = await core.summarizeSession(sessionId);\n const sessionName = session?.name ?? record?.name;\n if (result.ok) {\n await ctx.api.sendMessage(chatId, formatSummary(result.summary, sessionName), {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n } else {\n await ctx.api.sendMessage(chatId, `⚠️ ${escapeHtml(result.error)}`, {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n }\n}\n","import type { Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/core.js\";\nimport type { InstallProgress } from \"../../../core/types.js\";\nimport { escapeHtml } from \"../formatting.js\";\n\nconst AGENTS_PER_PAGE = 6;\n\nexport async function handleAgents(ctx: Context, core: OpenACPCore, page = 0): Promise<void> {\n const catalog = core.agentCatalog;\n const items = catalog.getAvailable();\n\n const installed = items.filter((i) => i.installed);\n const available = items.filter((i) => !i.installed);\n\n let text = \"<b>🤖 Agents</b>\\n\\n\";\n\n // Installed agents section\n if (installed.length > 0) {\n text += \"<b>Installed:</b>\\n\";\n for (const item of installed) {\n text += `✅ <b>${escapeHtml(item.name)}</b>`;\n if (item.description) {\n text += ` — <i>${escapeHtml(truncate(item.description, 50))}</i>`;\n }\n text += \"\\n\";\n }\n text += \"\\n\";\n }\n\n // Available agents section (paginated)\n if (available.length > 0) {\n const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE);\n const safePage = Math.max(0, Math.min(page, totalPages - 1));\n const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE);\n\n text += `<b>Available to install:</b>`;\n if (totalPages > 1) {\n text += ` (${safePage + 1}/${totalPages})`;\n }\n text += \"\\n\";\n\n for (const item of pageItems) {\n if (item.available) {\n text += `⬇️ <b>${escapeHtml(item.name)}</b>`;\n } else {\n const deps = item.missingDeps?.join(\", \") ?? \"requirements not met\";\n text += `⚠️ <b>${escapeHtml(item.name)}</b> <i>(needs: ${escapeHtml(deps)})</i>`;\n }\n if (item.description) {\n text += `\\n <i>${escapeHtml(truncate(item.description, 60))}</i>`;\n }\n text += \"\\n\";\n }\n\n // Install buttons for current page\n const keyboard = new InlineKeyboard();\n const installable = pageItems.filter((i) => i.available);\n for (let i = 0; i < installable.length; i += 2) {\n const row = installable.slice(i, i + 2);\n for (const item of row) {\n keyboard.text(`⬇️ ${item.name}`, `ag:install:${item.key}`);\n }\n keyboard.row();\n }\n\n // Pagination buttons\n if (totalPages > 1) {\n if (safePage > 0) {\n keyboard.text(\"◀️ Prev\", `ag:page:${safePage - 1}`);\n }\n if (safePage < totalPages - 1) {\n keyboard.text(\"Next ▶️\", `ag:page:${safePage + 1}`);\n }\n keyboard.row();\n }\n\n // Tip for CLI install\n if (available.some((i) => !i.available)) {\n text += \"\\n💡 <i>Agents marked ⚠️ need additional setup. Use</i> <code>openacp agents info &lt;name&gt;</code> <i>for details.</i>\\n\";\n }\n\n await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n } else {\n text += \"<i>All agents are already installed!</i>\";\n await ctx.reply(text, { parse_mode: \"HTML\" });\n }\n}\n\nexport async function handleInstall(ctx: Context, core: OpenACPCore): Promise<void> {\n const text = (ctx.message?.text ?? \"\").trim();\n const parts = text.split(/\\s+/);\n const nameOrId = parts[1];\n\n if (!nameOrId) {\n await ctx.reply(\n \"📦 <b>Install an agent</b>\\n\\n\" +\n \"Usage: <code>/install &lt;agent-name&gt;</code>\\n\" +\n \"Example: <code>/install gemini</code>\\n\\n\" +\n \"Use /agents to browse available agents.\",\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n await installAgentWithProgress(ctx, core, nameOrId);\n}\n\nexport async function handleAgentCallback(ctx: Context, core: OpenACPCore): Promise<void> {\n const data = ctx.callbackQuery?.data ?? \"\";\n await ctx.answerCallbackQuery();\n\n if (data.startsWith(\"ag:install:\")) {\n const nameOrId = data.replace(\"ag:install:\", \"\");\n await installAgentWithProgress(ctx, core, nameOrId);\n return;\n }\n\n if (data.startsWith(\"ag:page:\")) {\n const page = parseInt(data.replace(\"ag:page:\", \"\"), 10);\n // Edit the existing message with the new page\n try {\n const catalog = core.agentCatalog;\n const items = catalog.getAvailable();\n const installed = items.filter((i) => i.installed);\n const available = items.filter((i) => !i.installed);\n\n let text = \"<b>🤖 Agents</b>\\n\\n\";\n\n if (installed.length > 0) {\n text += \"<b>Installed:</b>\\n\";\n for (const item of installed) {\n text += `✅ <b>${escapeHtml(item.name)}</b>`;\n if (item.description) {\n text += ` — <i>${escapeHtml(truncate(item.description, 50))}</i>`;\n }\n text += \"\\n\";\n }\n text += \"\\n\";\n }\n\n const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE);\n const safePage = Math.max(0, Math.min(page, totalPages - 1));\n const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE);\n\n text += `<b>Available to install:</b>`;\n if (totalPages > 1) {\n text += ` (${safePage + 1}/${totalPages})`;\n }\n text += \"\\n\";\n\n for (const item of pageItems) {\n if (item.available) {\n text += `⬇️ <b>${escapeHtml(item.name)}</b>`;\n } else {\n const deps = item.missingDeps?.join(\", \") ?? \"requirements not met\";\n text += `⚠️ <b>${escapeHtml(item.name)}</b> <i>(needs: ${escapeHtml(deps)})</i>`;\n }\n if (item.description) {\n text += `\\n <i>${escapeHtml(truncate(item.description, 60))}</i>`;\n }\n text += \"\\n\";\n }\n\n const keyboard = new InlineKeyboard();\n const installable = pageItems.filter((i) => i.available);\n for (let i = 0; i < installable.length; i += 2) {\n const row = installable.slice(i, i + 2);\n for (const item of row) {\n keyboard.text(`⬇️ ${item.name}`, `ag:install:${item.key}`);\n }\n keyboard.row();\n }\n\n if (totalPages > 1) {\n if (safePage > 0) {\n keyboard.text(\"◀️ Prev\", `ag:page:${safePage - 1}`);\n }\n if (safePage < totalPages - 1) {\n keyboard.text(\"Next ▶️\", `ag:page:${safePage + 1}`);\n }\n keyboard.row();\n }\n\n await ctx.editMessageText(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n } catch { /* ignore edit failures */ }\n }\n}\n\nasync function installAgentWithProgress(ctx: Context, core: OpenACPCore, nameOrId: string): Promise<void> {\n const catalog = core.agentCatalog;\n const msg = await ctx.reply(`⏳ Installing <b>${escapeHtml(nameOrId)}</b>...`, { parse_mode: \"HTML\" });\n\n let lastEdit = 0;\n const EDIT_THROTTLE_MS = 1500;\n\n const progress: InstallProgress = {\n onStart(_id, _name) { /* initial message already sent */ },\n async onStep(step) {\n const now = Date.now();\n if (now - lastEdit > EDIT_THROTTLE_MS) {\n lastEdit = now;\n try {\n await ctx.api.editMessageText(msg.chat.id, msg.message_id, `⏳ <b>${escapeHtml(nameOrId)}</b>: ${escapeHtml(step)}`, { parse_mode: \"HTML\" });\n } catch { /* rate limit or unchanged */ }\n }\n },\n async onDownloadProgress(percent) {\n const now = Date.now();\n if (now - lastEdit > EDIT_THROTTLE_MS) {\n lastEdit = now;\n try {\n const bar = buildProgressBar(percent);\n await ctx.api.editMessageText(msg.chat.id, msg.message_id, `⏳ <b>${escapeHtml(nameOrId)}</b>\\nDownloading... ${bar} ${percent}%`, { parse_mode: \"HTML\" });\n } catch { /* rate limit */ }\n }\n },\n async onSuccess(name) {\n try {\n const keyboard = new InlineKeyboard().text(`🚀 Start session with ${name}`, `na:${nameOrId}`);\n await ctx.api.editMessageText(msg.chat.id, msg.message_id, `✅ <b>${escapeHtml(name)}</b> installed!`, { parse_mode: \"HTML\", reply_markup: keyboard });\n } catch { /* ignore */ }\n },\n async onError(error) {\n try {\n await ctx.api.editMessageText(msg.chat.id, msg.message_id, `❌ ${escapeHtml(error)}`, { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n },\n };\n\n const result = await catalog.install(nameOrId, progress);\n\n // Auto-integrate handoff if agent supports it\n if (result.ok) {\n const { getAgentCapabilities } = await import(\"../../../core/agent-dependencies.js\");\n const caps = getAgentCapabilities(result.agentKey);\n if (caps.integration) {\n const { installIntegration } = await import(\"../../../cli/integrate.js\");\n const intResult = await installIntegration(result.agentKey, caps.integration);\n if (intResult.success) {\n try {\n await ctx.reply(`🔗 Handoff integration installed for <b>${escapeHtml(result.agentKey)}</b>`, { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n }\n }\n }\n\n // Show setup steps as a follow-up message with copyable commands\n if (result.ok && result.setupSteps?.length) {\n let setupText = `📋 <b>Setup for ${escapeHtml(result.agentKey)}:</b>\\n\\n`;\n for (const step of result.setupSteps) {\n setupText += `→ ${formatSetupStep(step)}\\n`;\n }\n setupText += `\\n💡 <i>Tap any command to copy it</i>`;\n try {\n await ctx.reply(setupText, { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n }\n}\n\n/**\n * Format a setup step for Telegram, wrapping commands in <code> for tap-to-copy.\n * Patterns handled:\n * \"Install Claude CLI: npm install -g @anthropic-ai/claude-code\"\n * \"Login: claude login (opens browser)\"\n * \"Or set API key: export OPENAI_API_KEY=<your-key>\"\n * \"Free tier: 60 requests/min\" (no command — plain text)\n */\nfunction formatSetupStep(step: string): string {\n const colonIdx = step.indexOf(\": \");\n if (colonIdx === -1) return escapeHtml(step);\n\n const label = step.slice(0, colonIdx);\n const rest = step.slice(colonIdx + 2);\n\n // Check if the part after \":\" looks like a command (starts with known command prefixes)\n const cmdPrefixes = [\n \"npm \", \"npx \", \"pip \", \"uvx \", \"export \", \"claude \", \"codex \",\n \"openacp \", \"goose \", \"gemini \", \"cursor \", \"gh \",\n ];\n const looksLikeCommand = cmdPrefixes.some((p) => rest.startsWith(p));\n\n if (looksLikeCommand) {\n // Split command from parenthetical explanation: \"claude login (opens browser)\"\n const parenIdx = rest.indexOf(\" (\");\n if (parenIdx !== -1) {\n const cmd = rest.slice(0, parenIdx);\n const explanation = rest.slice(parenIdx);\n return `${escapeHtml(label)}: <code>${escapeHtml(cmd)}</code> ${escapeHtml(explanation)}`;\n }\n return `${escapeHtml(label)}: <code>${escapeHtml(rest)}</code>`;\n }\n\n return escapeHtml(step);\n}\n\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return text.slice(0, maxLen - 1) + \"…\";\n}\n\nfunction buildProgressBar(percent: number): string {\n const filled = Math.round(percent / 10);\n const empty = 10 - filled;\n return \"█\".repeat(filled) + \"░\".repeat(empty);\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport { escapeHtml } from \"../formatting.js\";\n\nexport async function handleIntegrate(ctx: Context, _core: OpenACPCore): Promise<void> {\n const { listIntegrations } = await import(\"../../../cli/integrate.js\");\n const agents = listIntegrations();\n\n const keyboard = new InlineKeyboard();\n for (const agent of agents) {\n keyboard.text(`🤖 ${agent}`, `i:agent:${agent}`).row();\n }\n\n await ctx.reply(\n `<b>🔗 Integrations</b>\\n\\nSelect an agent to manage its integrations.`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n}\n\nfunction buildAgentItemsKeyboard(agentName: string, items: import(\"../../../cli/integrate.js\").IntegrationItem[]): InlineKeyboard {\n const keyboard = new InlineKeyboard();\n for (const item of items) {\n const installed = item.isInstalled();\n keyboard.text(\n installed ? `✅ ${item.name} — Uninstall` : `📦 ${item.name} — Install`,\n installed ? `i:uninstall:${agentName}:${item.id}` : `i:install:${agentName}:${item.id}`,\n ).row();\n }\n keyboard.text(\"← Back\", \"i:back\").row();\n return keyboard;\n}\n\nexport function setupIntegrateCallbacks(\n bot: Bot,\n core: OpenACPCore,\n): void {\n bot.callbackQuery(/^i:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch {\n /* expired */\n }\n\n // Back to agent list\n if (data === \"i:back\") {\n const { listIntegrations } = await import(\"../../../cli/integrate.js\");\n const agents = listIntegrations();\n const keyboard = new InlineKeyboard();\n for (const agent of agents) {\n keyboard.text(`🤖 ${agent}`, `i:agent:${agent}`).row();\n }\n try {\n await ctx.editMessageText(\n `<b>🔗 Integrations</b>\\n\\nSelect an agent to manage its integrations.`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch { /* message unchanged */ }\n return;\n }\n\n // Show agent items\n const agentMatch = data.match(/^i:agent:(.+)$/);\n if (agentMatch) {\n const agentName = agentMatch[1];\n const { getIntegration } = await import(\"../../../cli/integrate.js\");\n const integration = getIntegration(agentName);\n if (!integration) {\n await ctx.reply(`❌ No integration available for '${escapeHtml(agentName)}'.`, { parse_mode: \"HTML\" });\n return;\n }\n const keyboard = buildAgentItemsKeyboard(agentName, integration.items);\n try {\n await ctx.editMessageText(\n `<b>🔗 ${escapeHtml(agentName)} Integrations</b>\\n\\n${integration.items.map((i) => `• <b>${escapeHtml(i.name)}</b> — ${escapeHtml(i.description)}`).join(\"\\n\")}`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch {\n await ctx.reply(\n `<b>🔗 ${escapeHtml(agentName)} Integrations</b>`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n }\n return;\n }\n\n // Install / uninstall item\n const actionMatch = data.match(/^i:(install|uninstall):([^:]+):(.+)$/);\n if (!actionMatch) return;\n\n const action = actionMatch[1] as \"install\" | \"uninstall\";\n const agentName = actionMatch[2];\n const itemId = actionMatch[3];\n\n const { getIntegration } = await import(\"../../../cli/integrate.js\");\n const integration = getIntegration(agentName);\n if (!integration) return;\n\n const item = integration.items.find((i) => i.id === itemId);\n if (!item) return;\n\n const result = action === \"install\"\n ? await item.install()\n : await item.uninstall();\n\n // Save state to config\n const installed = action === \"install\" && result.success;\n await core.configManager.save({\n integrations: {\n [agentName]: {\n installed,\n installedAt: installed ? new Date().toISOString() : undefined,\n },\n },\n });\n\n const statusEmoji = result.success ? \"✅\" : \"❌\";\n const actionLabel = action === \"install\" ? \"installed\" : \"uninstalled\";\n const logsText = result.logs.map((l) => `<code>${escapeHtml(l)}</code>`).join(\"\\n\");\n const resultText = `${statusEmoji} <b>${escapeHtml(item.name)}</b> ${actionLabel}.\\n\\n${logsText}`;\n\n const keyboard = buildAgentItemsKeyboard(agentName, integration.items);\n try {\n await ctx.editMessageText(\n `<b>🔗 ${escapeHtml(agentName)} Integrations</b>\\n\\n${resultText}`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n } catch {\n await ctx.reply(resultText, { parse_mode: \"HTML\" });\n }\n });\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport type { ContextQuery } from \"../../../core/context/context-provider.js\";\nimport { DEFAULT_MAX_TOKENS } from \"../../../core/context/context-provider.js\";\nimport { CheckpointReader } from \"../../../core/context/entire/checkpoint-reader.js\";\nimport { escapeHtml } from \"../formatting.js\";\nimport { createSessionTopic, buildDeepLink } from \"../topics.js\";\nimport { buildSessionControlKeyboard } from \"./admin.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\n\nconst log = createChildLogger({ module: \"telegram-cmd-resume\" });\n\nconst PENDING_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\nfunction botFromCtx(ctx: Context): Bot {\n return { api: ctx.api } as unknown as Bot;\n}\n\n// --- Pending state for interactive workspace picker ---\n\ninterface PendingResume {\n query: Omit<ContextQuery, \"repoPath\">;\n step: \"workspace\" | \"workspace_input\";\n messageId: number;\n threadId?: number;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst pendingResumes = new Map<number, PendingResume>();\n\nfunction cleanupPending(userId: number): void {\n const pending = pendingResumes.get(userId);\n if (pending) {\n clearTimeout(pending.timer);\n pendingResumes.delete(userId);\n }\n}\n\n// --- Arg parsing ---\n\nexport function parseResumeArgs(matchStr: string): { query: Omit<ContextQuery, \"repoPath\"> } | null {\n const args = matchStr.split(\" \").filter(Boolean);\n if (args.length === 0) return { query: { type: \"latest\", value: \"5\" } };\n\n const first = args[0];\n\n // Subcommands\n if (first === \"pr\") return args[1] ? { query: { type: \"pr\", value: args[1] } } : null;\n if (first === \"branch\") return args[1] ? { query: { type: \"branch\", value: args[1] } } : null;\n if (first === \"commit\") return args[1] ? { query: { type: \"commit\", value: args[1] } } : null;\n\n // Auto-detect ID format\n if (CheckpointReader.isCheckpointId(first)) return { query: { type: \"checkpoint\", value: first } };\n if (CheckpointReader.isSessionId(first)) return { query: { type: \"session\", value: first } };\n\n // GitHub PR URL: github.com/org/repo/pull/19\n if (first.includes(\"/pull/\")) {\n const prMatch = first.match(/\\/pull\\/(\\d+)/);\n return prMatch ? { query: { type: \"pr\", value: prMatch[1] } } : null;\n }\n\n // GitHub commit URL: github.com/org/repo/commit/e0dd2fa4...\n const ghCommitMatch = first.match(/github\\.com\\/[^/]+\\/[^/]+\\/commit\\/([0-9a-f]+)/);\n if (ghCommitMatch) return { query: { type: \"commit\", value: ghCommitMatch[1] } };\n\n // GitHub branch URL: github.com/org/repo/tree/branch-name\n const ghBranchMatch = first.match(/github\\.com\\/[^/]+\\/[^/]+\\/tree\\/(.+?)(?:\\?|#|$)/);\n if (ghBranchMatch) return { query: { type: \"branch\", value: ghBranchMatch[1] } };\n\n // GitHub compare URL: github.com/org/repo/compare/base...head\n const ghCompareMatch = first.match(/github\\.com\\/[^/]+\\/[^/]+\\/compare\\/(?:[^.]+\\.{2,3})(.+?)(?:\\?|#|$)/);\n if (ghCompareMatch) return { query: { type: \"branch\", value: ghCompareMatch[1] } };\n\n // GitHub bare repo URL: github.com/org/repo (no subpath) → latest\n if (first.match(/github\\.com\\/[^/]+\\/[^/]+\\/?$/) && !first.includes(\"/tree/\") && !first.includes(\"/pull/\") && !first.includes(\"/commit/\") && !first.includes(\"/compare/\")) {\n return { query: { type: \"latest\", value: \"5\" } };\n }\n\n // Entire.io checkpoint URL: entire.io/gh/{owner}/{repo}/checkpoints/{branch}/{checkpoint_id}\n const entireCheckpointMatch = first.match(/entire\\.io\\/gh\\/[^/]+\\/[^/]+\\/checkpoints\\/[^/]+\\/([0-9a-f]{12})/);\n if (entireCheckpointMatch) return { query: { type: \"checkpoint\", value: entireCheckpointMatch[1] } };\n\n // Entire.io commit URL: entire.io/gh/{owner}/{repo}/commit/{commit_hash}\n const entireCommitMatch = first.match(/entire\\.io\\/gh\\/[^/]+\\/[^/]+\\/commit\\/([0-9a-f]+)/);\n if (entireCommitMatch) return { query: { type: \"commit\", value: entireCommitMatch[1] } };\n\n // Unknown — default to latest\n return { query: { type: \"latest\", value: \"5\" } };\n}\n\nfunction looksLikePath(text: string): boolean {\n return text.startsWith(\"/\") || text.startsWith(\"~\") || text.startsWith(\".\");\n}\n\n// --- List subdirectories in workspace baseDir ---\n\nfunction listWorkspaceDirs(baseDir: string, maxItems = 10): string[] {\n const resolved = baseDir.replace(/^~/, os.homedir());\n try {\n if (!fs.existsSync(resolved)) return [];\n return fs.readdirSync(resolved, { withFileTypes: true })\n .filter(d => d.isDirectory() && !d.name.startsWith(\".\"))\n .map(d => d.name)\n .sort()\n .slice(0, maxItems);\n } catch {\n return [];\n }\n}\n\n// --- Workspace picker step ---\n\nasync function showWorkspacePicker(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n userId: number,\n query: Omit<ContextQuery, \"repoPath\">,\n): Promise<void> {\n const config = core.configManager.get();\n const baseDir = config.workspace.baseDir;\n const resolvedBase = baseDir.replace(/^~/, os.homedir());\n const subdirs = listWorkspaceDirs(baseDir);\n\n const keyboard = new InlineKeyboard();\n\n // List subdirectories as buttons\n for (const dir of subdirs) {\n const fullPath = path.join(resolvedBase, dir);\n keyboard.text(`📁 ${dir}`, `m:resume:ws:${dir}`).row();\n }\n\n // Always offer base dir and custom input\n keyboard.text(`📁 Use ${baseDir}`, \"m:resume:ws:default\").row();\n keyboard.text(\"✏️ Enter project path\", \"m:resume:ws:custom\");\n\n const queryLabel = query.type === \"latest\" ? \"latest sessions\" : `${query.type}: ${query.value}`;\n const text =\n `📁 <b>Select project directory for resume</b>\\n\\n` +\n `Query: <code>${escapeHtml(queryLabel)}</code>\\n\\n` +\n `Choose the repo that has Entire checkpoints enabled:`;\n\n const msg = await ctx.reply(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n\n cleanupPending(userId);\n pendingResumes.set(userId, {\n query,\n step: \"workspace\",\n messageId: msg.message_id,\n threadId: ctx.message?.message_thread_id,\n timer: setTimeout(() => pendingResumes.delete(userId), PENDING_TIMEOUT_MS),\n });\n}\n\n// --- Execute resume with resolved workspace ---\n\nasync function executeResume(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n query: Omit<ContextQuery, \"repoPath\">,\n repoPath: string,\n): Promise<void> {\n // Check provider availability\n const provider = await core.contextManager.getProvider(repoPath);\n if (!provider) {\n await ctx.reply(\n `⚠️ <b>Entire not enabled in <code>${escapeHtml(repoPath)}</code></b>\\n\\n` +\n `To enable conversation history tracking:\\n` +\n `<code>cd ${escapeHtml(repoPath)} && npx entire enable</code>\\n\\n` +\n `Learn more: https://docs.entire.io/getting-started`,\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n // Scan sessions\n const fullQuery: ContextQuery = { ...query, repoPath };\n\n await ctx.reply(`🔍 Scanning ${query.type === \"latest\" ? \"latest sessions\" : `${query.type}: ${escapeHtml(query.value)}`}...`, { parse_mode: \"HTML\" });\n\n const listResult = await core.contextManager.listSessions(fullQuery);\n if (!listResult || listResult.sessions.length === 0) {\n await ctx.reply(\n `🔍 <b>No sessions found</b>\\n\\n` +\n `Query: <code>${escapeHtml(query.type)}: ${escapeHtml(query.value)}</code>\\n` +\n `Repo: <code>${escapeHtml(repoPath)}</code>`,\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n const config = core.configManager.get();\n const agentName = config.defaultAgent;\n\n let threadId: number | undefined;\n try {\n // Create topic FIRST (before session events fire — prevent race condition)\n const queryLabel = query.type === \"latest\" ? \"latest\" : `${query.type}: ${query.value.slice(0, 20)}`;\n const topicName = `📜 Resume — ${queryLabel}`;\n threadId = await createSessionTopic(botFromCtx(ctx), chatId, topicName);\n\n await ctx.api.sendMessage(chatId, `⏳ Loading context and starting session...`, {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n });\n\n const { session, contextResult } = await core.createSessionWithContext({\n channelId: \"telegram\",\n agentName,\n workingDirectory: repoPath,\n contextQuery: fullQuery,\n contextOptions: { maxTokens: DEFAULT_MAX_TOKENS },\n });\n\n session.threadId = String(threadId);\n await core.sessionManager.patchRecord(session.id, { platform: { topicId: threadId } });\n\n // Build summary info\n const sessionCount = contextResult?.sessionCount ?? listResult.sessions.length;\n const mode = contextResult?.mode ?? \"full\";\n const tokens = contextResult?.tokenEstimate ?? listResult.estimatedTokens;\n\n const topicLink = buildDeepLink(chatId, threadId);\n const replyTarget = ctx.message?.message_thread_id;\n\n if (replyTarget !== threadId) {\n await ctx.reply(\n `✅ Session resumed → <a href=\"${topicLink}\">Open topic</a>`,\n { parse_mode: \"HTML\" },\n );\n }\n\n await ctx.api.sendMessage(\n chatId,\n `✅ <b>Session resumed with context</b>\\n` +\n `<b>Agent:</b> ${escapeHtml(session.agentName)}\\n` +\n `<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>\\n` +\n `<b>Sessions loaded:</b> ${sessionCount}\\n` +\n `<b>Mode:</b> ${escapeHtml(mode)}\\n` +\n `<b>~Tokens:</b> ${tokens.toLocaleString()}\\n\\n` +\n `Context is ready — chat here to continue working with the agent.`,\n {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n reply_markup: buildSessionControlKeyboard(session.id, false, false),\n },\n );\n\n session.warmup().catch((err) => log.error({ err }, \"Warm-up error\"));\n } catch (err) {\n log.error({ err }, \"Resume session creation failed\");\n if (threadId) {\n try {\n await ctx.api.deleteForumTopic(chatId, threadId);\n } catch { /* ignore cleanup failures */ }\n }\n const message = err instanceof Error ? err.message : (typeof err === \"object\" ? JSON.stringify(err) : String(err));\n await ctx.reply(`❌ ${escapeHtml(message)}`, { parse_mode: \"HTML\" });\n }\n}\n\n// --- Main handler ---\n\nexport async function handleResume(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n assistant?: CommandsAssistantContext,\n): Promise<void> {\n const rawMatch = (ctx as Context & { match: unknown }).match;\n const matchStr = typeof rawMatch === \"string\" ? rawMatch : \"\";\n\n const parsed = parseResumeArgs(matchStr);\n if (!parsed) {\n await ctx.reply(\n `❌ <b>Invalid arguments.</b>\\n\\n` +\n `Usage examples:\\n` +\n `• <code>/resume</code> — latest 5 sessions\\n` +\n `• <code>/resume pr 19</code>\\n` +\n `• <code>/resume branch main</code>\\n` +\n `• <code>/resume commit e0dd2fa4</code>\\n` +\n `• <code>/resume f634acf05138</code> — checkpoint ID\\n` +\n `• <code>/resume https://entire.io/gh/.../checkpoints/.../2e884e2c402a</code>\\n` +\n `• <code>/resume https://entire.io/gh/.../commit/e0dd2fa4...</code>`,\n { parse_mode: \"HTML\" },\n );\n return;\n }\n\n const { query } = parsed;\n const userId = ctx.from?.id;\n if (!userId) return;\n\n // Always show workspace picker — user must choose working directory\n await showWorkspacePicker(ctx, core, chatId, userId, query);\n}\n\n// --- Text input handler for custom workspace path ---\n\nexport async function handlePendingResumeInput(\n ctx: Context,\n core: OpenACPCore,\n chatId: number,\n assistantTopicId?: number,\n): Promise<boolean> {\n const userId = ctx.from?.id;\n if (!userId) return false;\n const pending = pendingResumes.get(userId);\n if (!pending || !ctx.message?.text) return false;\n if (pending.step !== \"workspace_input\" && pending.step !== \"workspace\") return false;\n\n // Only intercept in assistant topic or general chat\n const threadId = ctx.message.message_thread_id;\n if (threadId && threadId !== assistantTopicId) return false;\n\n // At \"workspace\" step (picker shown), only intercept if text looks like a path\n if (pending.step === \"workspace\" && !looksLikePath(ctx.message.text.trim())) return false;\n\n let workspace = ctx.message.text.trim();\n if (!workspace) {\n await ctx.reply(\"⚠️ Please enter a valid directory path.\", { parse_mode: \"HTML\" });\n return true;\n }\n\n // Resolve relative paths against baseDir\n if (!workspace.startsWith(\"/\") && !workspace.startsWith(\"~\")) {\n const baseDir = core.configManager.get().workspace.baseDir;\n workspace = `${baseDir.replace(/\\/$/, \"\")}/${workspace}`;\n }\n const resolved = core.configManager.resolveWorkspace(workspace);\n\n cleanupPending(userId);\n await executeResume(ctx, core, chatId, pending.query, resolved);\n return true;\n}\n\n// --- Callback handlers for workspace picker buttons ---\n\nexport function setupResumeCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n): void {\n bot.callbackQuery(/^m:resume:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n const userId = ctx.from?.id;\n if (!userId) return;\n\n try {\n await ctx.answerCallbackQuery();\n } catch { /* expired or network — ignore */ }\n\n const pending = pendingResumes.get(userId);\n if (!pending) return;\n\n if (data === \"m:resume:ws:default\") {\n // Use baseDir directly\n const baseDir = core.configManager.get().workspace.baseDir;\n const resolved = core.configManager.resolveWorkspace(baseDir);\n cleanupPending(userId);\n try {\n await ctx.api.editMessageText(chatId, pending.messageId, `⏳ Using <code>${escapeHtml(resolved)}</code>...`, { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n await executeResume(ctx, core, chatId, pending.query, resolved);\n return;\n }\n\n if (data === \"m:resume:ws:custom\") {\n // Switch to text input mode\n try {\n await ctx.api.editMessageText(\n chatId,\n pending.messageId,\n `✏️ <b>Enter project path:</b>\\n\\n` +\n `Full path like <code>~/code/my-project</code>\\n` +\n `Or just the folder name (will use workspace baseDir)`,\n { parse_mode: \"HTML\" },\n );\n } catch {\n await ctx.reply(`✏️ <b>Enter project path:</b>`, { parse_mode: \"HTML\" });\n }\n clearTimeout(pending.timer);\n pending.step = \"workspace_input\";\n pending.timer = setTimeout(() => pendingResumes.delete(userId), PENDING_TIMEOUT_MS);\n return;\n }\n\n if (data.startsWith(\"m:resume:ws:\")) {\n // Subdirectory selected\n const dirName = data.replace(\"m:resume:ws:\", \"\");\n const baseDir = core.configManager.get().workspace.baseDir;\n const resolved = core.configManager.resolveWorkspace(path.join(baseDir.replace(/^~/, os.homedir()), dirName));\n cleanupPending(userId);\n try {\n await ctx.api.editMessageText(chatId, pending.messageId, `⏳ Using <code>${escapeHtml(resolved)}</code>...`, { parse_mode: \"HTML\" });\n } catch { /* ignore */ }\n await executeResume(ctx, core, chatId, pending.query, resolved);\n return;\n }\n });\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport { getSafeFields, resolveOptions, getConfigValue, isHotReloadable, type ConfigFieldDef } from \"../../../core/config-registry.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\n\nconst log = createChildLogger({ module: \"telegram-settings\" });\n\nfunction buildSettingsKeyboard(core: OpenACPCore): InlineKeyboard {\n const config = core.configManager.get();\n const fields = getSafeFields();\n const kb = new InlineKeyboard();\n\n for (const field of fields) {\n const value = getConfigValue(config, field.path);\n const label = formatFieldLabel(field, value);\n\n if (field.type === 'toggle') {\n kb.text(`${label}`, `s:toggle:${field.path}`).row();\n } else if (field.type === 'select') {\n kb.text(`${label}`, `s:select:${field.path}`).row();\n } else {\n kb.text(`${label}`, `s:input:${field.path}`).row();\n }\n }\n\n kb.text(\"◀️ Back to Menu\", \"s:back\");\n return kb;\n}\n\nfunction formatFieldLabel(field: ConfigFieldDef, value: unknown): string {\n const icons: Record<string, string> = {\n agent: '🤖', logging: '📝', tunnel: '🔗',\n security: '🔒', workspace: '📁', storage: '💾', speech: '🎤',\n };\n const icon = icons[field.group] ?? '⚙️';\n\n if (field.type === 'toggle') {\n return `${icon} ${field.displayName}: ${value ? 'ON' : 'OFF'}`;\n }\n const displayValue = value === null || value === undefined ? 'Not set' : String(value);\n return `${icon} ${field.displayName}: ${displayValue}`;\n}\n\nexport async function handleSettings(ctx: Context, core: OpenACPCore): Promise<void> {\n const kb = buildSettingsKeyboard(core);\n await ctx.reply(`<b>⚙️ Settings</b>\\nTap to change:`, {\n parse_mode: \"HTML\",\n reply_markup: kb,\n });\n}\n\nexport function setupSettingsCallbacks(\n bot: Bot,\n core: OpenACPCore,\n getAssistantSession: () => { topicId: number; enqueuePrompt: (p: string) => Promise<void> } | undefined,\n): void {\n bot.callbackQuery(/^s:toggle:/, async (ctx) => {\n const fieldPath = ctx.callbackQuery.data.replace('s:toggle:', '');\n const config = core.configManager.get();\n const currentValue = getConfigValue(config, fieldPath);\n const newValue = !currentValue;\n\n try {\n const updates = buildNestedUpdate(fieldPath, newValue);\n await core.configManager.save(updates, fieldPath);\n\n const toast = isHotReloadable(fieldPath)\n ? `✅ ${fieldPath} = ${newValue}`\n : `✅ ${fieldPath} = ${newValue} (restart needed)`;\n try { await ctx.answerCallbackQuery({ text: toast }); } catch { /* expired */ }\n\n try {\n await ctx.editMessageReplyMarkup({ reply_markup: buildSettingsKeyboard(core) });\n } catch { /* ignore */ }\n } catch (err) {\n log.error({ err, fieldPath }, 'Failed to toggle config');\n try { await ctx.answerCallbackQuery({ text: '❌ Failed to update' }); } catch { /* expired */ }\n }\n });\n\n bot.callbackQuery(/^s:select:/, async (ctx) => {\n const fieldPath = ctx.callbackQuery.data.replace('s:select:', '');\n const config = core.configManager.get();\n const fieldDef = getSafeFields().find(f => f.path === fieldPath);\n if (!fieldDef) return;\n\n const options = resolveOptions(fieldDef, config) ?? [];\n const currentValue = getConfigValue(config, fieldPath);\n const kb = new InlineKeyboard();\n\n for (const opt of options) {\n const marker = opt === String(currentValue) ? ' ✓' : '';\n kb.text(`${opt}${marker}`, `s:pick:${fieldPath}:${opt}`).row();\n }\n kb.text(\"◀️ Back\", \"s:back:refresh\");\n\n try { await ctx.answerCallbackQuery(); } catch { /* expired */ }\n\n try {\n await ctx.editMessageText(`<b>⚙️ ${fieldDef.displayName}</b>\\nSelect a value:`, {\n parse_mode: \"HTML\",\n reply_markup: kb,\n });\n } catch { /* ignore */ }\n });\n\n bot.callbackQuery(/^s:pick:/, async (ctx) => {\n const parts = ctx.callbackQuery.data.replace('s:pick:', '').split(':');\n const fieldPath = parts.slice(0, -1).join(':');\n const newValue = parts[parts.length - 1];\n\n try {\n // For speech.stt.provider: check if the selected provider has an API key configured\n if (fieldPath === 'speech.stt.provider') {\n const config = core.configManager.get();\n const providerConfig = config.speech?.stt?.providers?.[newValue];\n if (!providerConfig?.apiKey) {\n // No API key — delegate to assistant to collect it\n const assistant = getAssistantSession();\n if (assistant) {\n try { await ctx.answerCallbackQuery({ text: `🔑 API key needed — check Assistant topic` }); } catch { /* expired */ }\n const prompt = `User wants to enable ${newValue} as Speech-to-Text provider, but no API key is configured yet. Guide them to get a ${newValue} API key and set it up. After they provide the key, run both commands: \\`openacp config set speech.stt.providers.${newValue}.apiKey <key>\\` and \\`openacp config set speech.stt.provider ${newValue}\\``;\n await assistant.enqueuePrompt(prompt);\n return;\n }\n // No assistant — just warn\n try { await ctx.answerCallbackQuery({ text: `⚠️ Set API key first: openacp config set speech.stt.providers.${newValue}.apiKey <key>` }); } catch { /* expired */ }\n return;\n }\n }\n\n const updates = buildNestedUpdate(fieldPath, newValue);\n await core.configManager.save(updates, fieldPath);\n\n try { await ctx.answerCallbackQuery({ text: `✅ ${fieldPath} = ${newValue}` }); } catch { /* expired */ }\n try {\n await ctx.editMessageText(`<b>⚙️ Settings</b>\\nTap to change:`, {\n parse_mode: \"HTML\",\n reply_markup: buildSettingsKeyboard(core),\n });\n } catch { /* ignore */ }\n } catch (err) {\n log.error({ err, fieldPath }, 'Failed to set config');\n try { await ctx.answerCallbackQuery({ text: '❌ Failed to update' }); } catch { /* expired */ }\n }\n });\n\n bot.callbackQuery(/^s:input:/, async (ctx) => {\n const fieldPath = ctx.callbackQuery.data.replace('s:input:', '');\n const config = core.configManager.get();\n const fieldDef = getSafeFields().find(f => f.path === fieldPath);\n if (!fieldDef) return;\n\n const currentValue = getConfigValue(config, fieldPath);\n const assistant = getAssistantSession();\n\n if (!assistant) {\n try { await ctx.answerCallbackQuery({ text: '⚠️ Start the assistant first (/assistant)' }); } catch { /* expired */ }\n return;\n }\n\n try { await ctx.answerCallbackQuery({ text: `Delegating to assistant...` }); } catch { /* expired */ }\n\n const prompt = `User wants to change ${fieldDef.displayName} (config path: ${fieldPath}). Current value: ${JSON.stringify(currentValue)}. Ask them for the new value and apply it using: openacp config set ${fieldPath} <value>`;\n await assistant.enqueuePrompt(prompt);\n });\n\n bot.callbackQuery(\"s:back\", async (ctx) => {\n try { await ctx.answerCallbackQuery(); } catch { /* expired */ }\n const { buildMenuKeyboard } = await import('./menu.js');\n try {\n await ctx.editMessageText(`<b>OpenACP Menu</b>\\nChoose an action:`, {\n parse_mode: \"HTML\",\n reply_markup: buildMenuKeyboard(),\n });\n } catch { /* ignore */ }\n });\n\n bot.callbackQuery(\"s:back:refresh\", async (ctx) => {\n try { await ctx.answerCallbackQuery(); } catch { /* expired */ }\n try {\n await ctx.editMessageText(`<b>⚙️ Settings</b>\\nTap to change:`, {\n parse_mode: \"HTML\",\n reply_markup: buildSettingsKeyboard(core),\n });\n } catch { /* ignore */ }\n });\n}\n\nfunction buildNestedUpdate(dotPath: string, value: unknown): Record<string, unknown> {\n const parts = dotPath.split('.');\n const result: Record<string, unknown> = {};\n let target = result;\n for (let i = 0; i < parts.length - 1; i++) {\n target[parts[i]] = {};\n target = target[parts[i]] as Record<string, unknown>;\n }\n target[parts[parts.length - 1]] = value;\n return result;\n}\n","import type { Bot, Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport { DoctorEngine } from \"../../../core/doctor/index.js\";\nimport type { DoctorReport, PendingFix } from \"../../../core/doctor/types.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\n\nconst log = createChildLogger({ module: \"telegram-cmd-doctor\" });\n\nconst pendingFixesStore = new Map<string, PendingFix[]>();\n\nfunction renderReport(report: DoctorReport): { text: string; keyboard: InlineKeyboard | undefined } {\n const icons = { pass: \"✅\", warn: \"⚠️\", fail: \"❌\" };\n const lines: string[] = [\"🩺 <b>OpenACP Doctor</b>\\n\"];\n\n for (const category of report.categories) {\n lines.push(`<b>${category.name}</b>`);\n for (const result of category.results) {\n lines.push(` ${icons[result.status]} ${escapeHtml(result.message)}`);\n }\n lines.push(\"\");\n }\n\n const { passed, warnings, failed, fixed } = report.summary;\n const fixedStr = fixed > 0 ? `, ${fixed} fixed` : \"\";\n lines.push(`<b>Result:</b> ${passed} passed, ${warnings} warnings, ${failed} failed${fixedStr}`);\n\n let keyboard: InlineKeyboard | undefined;\n if (report.pendingFixes.length > 0) {\n keyboard = new InlineKeyboard();\n for (let i = 0; i < report.pendingFixes.length; i++) {\n const label = `🔧 Fix: ${report.pendingFixes[i].message.slice(0, 30)}`;\n keyboard.text(label, `m:doctor:fix:${i}`).row();\n }\n }\n\n return { text: lines.join(\"\\n\"), keyboard };\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\nexport async function handleDoctor(ctx: Context): Promise<void> {\n const statusMsg = await ctx.reply(\"🩺 Running diagnostics...\", { parse_mode: \"HTML\" });\n\n try {\n const engine = new DoctorEngine();\n const report = await engine.runAll();\n const { text, keyboard } = renderReport(report);\n\n const storeKey = `${ctx.chat!.id}:${statusMsg.message_id}`;\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes);\n }\n\n await ctx.api.editMessageText(ctx.chat!.id, statusMsg.message_id, text, {\n parse_mode: \"HTML\",\n reply_markup: keyboard,\n });\n } catch (err) {\n log.error({ err }, \"Doctor command failed\");\n await ctx.api.editMessageText(\n ctx.chat!.id,\n statusMsg.message_id,\n `❌ Doctor failed: ${err instanceof Error ? err.message : String(err)}`,\n { parse_mode: \"HTML\" },\n );\n }\n}\n\nexport function setupDoctorCallbacks(bot: Bot): void {\n bot.callbackQuery(/^m:doctor:fix:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n const index = parseInt(data.replace(\"m:doctor:fix:\", \"\"), 10);\n const chatId = ctx.callbackQuery.message?.chat.id;\n const messageId = ctx.callbackQuery.message?.message_id;\n\n try {\n await ctx.answerCallbackQuery({ text: \"Applying fix...\" });\n } catch { /* expired */ }\n\n if (chatId === undefined || messageId === undefined) return;\n\n const storeKey = `${chatId}:${messageId}`;\n const fixes = pendingFixesStore.get(storeKey);\n if (!fixes || index < 0 || index >= fixes.length) {\n try { await ctx.answerCallbackQuery({ text: \"Fix no longer available\" }); } catch { /* */ }\n return;\n }\n\n const pending = fixes[index];\n try {\n const result = await pending.fix();\n if (result.success) {\n const engine = new DoctorEngine();\n const report = await engine.runAll();\n const { text, keyboard } = renderReport(report);\n\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes);\n } else {\n pendingFixesStore.delete(storeKey);\n }\n\n await ctx.editMessageText(text, { parse_mode: \"HTML\", reply_markup: keyboard });\n } else {\n try { await ctx.answerCallbackQuery({ text: `Fix failed: ${result.message}` }); } catch { /* */ }\n }\n } catch (err) {\n log.error({ err, index }, \"Doctor fix callback failed\");\n }\n });\n\n bot.callbackQuery(\"m:doctor\", async (ctx) => {\n try { await ctx.answerCallbackQuery(); } catch { /* */ }\n await handleDoctor(ctx);\n });\n}\n","import type { Context } from \"grammy\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport { escapeHtml } from \"../formatting.js\";\nimport { createChildLogger } from \"../../../core/log.js\";\n\nconst log = createChildLogger({ module: \"telegram-cmd-tunnel\" });\n\nexport async function handleTunnel(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n if (!core.tunnelService) {\n await ctx.reply(\"❌ Tunnel service is not enabled.\", { parse_mode: \"HTML\" });\n return;\n }\n\n const match = (ctx as Context & { match?: string }).match?.trim() ?? \"\";\n\n // /tunnel stop <port>\n if (match.startsWith(\"stop \")) {\n const portStr = match.slice(5).trim();\n const port = parseInt(portStr, 10);\n if (isNaN(port)) {\n await ctx.reply(\"❌ Invalid port number.\", { parse_mode: \"HTML\" });\n return;\n }\n\n try {\n await core.tunnelService.stopTunnel(port);\n await ctx.reply(`🔌 Tunnel stopped: port ${port}`, { parse_mode: \"HTML\" });\n } catch (err) {\n await ctx.reply(`❌ ${escapeHtml((err as Error).message)}`, { parse_mode: \"HTML\" });\n }\n return;\n }\n\n // /tunnel <port> [label]\n if (match) {\n const parts = match.split(/\\s+/);\n const port = parseInt(parts[0], 10);\n if (isNaN(port)) {\n await ctx.reply(\"❌ Invalid port number. Usage: <code>/tunnel 3000 [label]</code>\", { parse_mode: \"HTML\" });\n return;\n }\n const label = parts.slice(1).join(\" \") || undefined;\n\n // Find session for this thread\n const threadId = ctx.message?.message_thread_id;\n let sessionId: string | undefined;\n if (threadId) {\n const session = core.sessionManager.getSessionByThread(\"telegram\", String(threadId));\n if (session) sessionId = session.id;\n }\n\n try {\n await ctx.reply(`⏳ Starting tunnel for port ${port}...`, { parse_mode: \"HTML\" });\n const entry = await core.tunnelService.addTunnel(port, { label, sessionId });\n await ctx.reply(\n `🔗 <b>Tunnel active</b>\\n\\nPort ${port}${label ? ` (${escapeHtml(label)})` : \"\"}\\n→ <a href=\"${escapeHtml(entry.publicUrl || \"\")}\">${escapeHtml(entry.publicUrl || \"\")}</a>`,\n { parse_mode: \"HTML\" },\n );\n } catch (err) {\n await ctx.reply(`❌ ${escapeHtml((err as Error).message)}`, { parse_mode: \"HTML\" });\n }\n return;\n }\n\n // No args — show help\n await ctx.reply(\n `<b>Tunnel commands:</b>\\n\\n` +\n `<code>/tunnel &lt;port&gt; [label]</code> — Create tunnel\\n` +\n `<code>/tunnel stop &lt;port&gt;</code> — Stop tunnel\\n` +\n `<code>/tunnels</code> — List active tunnels`,\n { parse_mode: \"HTML\" },\n );\n}\n\nexport async function handleTunnels(\n ctx: Context,\n core: OpenACPCore,\n): Promise<void> {\n if (!core.tunnelService) {\n await ctx.reply(\"❌ Tunnel service is not enabled.\", { parse_mode: \"HTML\" });\n return;\n }\n\n // In session topic: show only that session's tunnels. In assistant/other: show all.\n const threadId = ctx.message?.message_thread_id;\n let entries = core.tunnelService.listTunnels();\n let sessionScoped = false;\n\n if (threadId) {\n const session = core.sessionManager.getSessionByThread(\"telegram\", String(threadId));\n if (session) {\n entries = entries.filter(e => e.sessionId === session.id);\n sessionScoped = true;\n }\n }\n\n if (entries.length === 0) {\n const hint = sessionScoped\n ? \"No tunnels for this session.\\n\\nUse <code>/tunnel &lt;port&gt;</code> to create one.\"\n : \"No active tunnels.\\n\\nUse <code>/tunnel &lt;port&gt;</code> to create one.\";\n await ctx.reply(hint, { parse_mode: \"HTML\" });\n return;\n }\n\n const lines = entries.map((e) => {\n const status = e.status === \"active\" ? \"✅\" : e.status === \"starting\" ? \"⏳\" : \"❌\";\n const label = e.label ? ` (${escapeHtml(e.label)})` : \"\";\n const url = e.publicUrl ? `\\n → <a href=\"${escapeHtml(e.publicUrl)}\">${escapeHtml(e.publicUrl)}</a>` : \"\";\n return `${status} Port <b>${e.port}</b>${label}${url}`;\n });\n\n const keyboard = new InlineKeyboard();\n for (const e of entries) {\n keyboard.text(`🔌 Stop ${e.port}${e.label ? ` (${e.label})` : \"\"}`, `tn:stop:${e.port}`).row();\n }\n if (entries.length > 1) {\n keyboard.text(\"🔌 Stop all\", \"tn:stop-all\").row();\n }\n\n await ctx.reply(\n `<b>Active tunnels:</b>\\n\\n${lines.join(\"\\n\\n\")}`,\n { parse_mode: \"HTML\", reply_markup: keyboard },\n );\n}\n\nexport function setupTunnelCallbacks(\n bot: import(\"grammy\").Bot,\n core: OpenACPCore,\n): void {\n bot.callbackQuery(/^tn:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n if (!core.tunnelService) {\n await ctx.answerCallbackQuery({ text: \"Tunnel not enabled\" });\n return;\n }\n\n try {\n if (data === \"tn:stop-all\") {\n const entries = core.tunnelService.listTunnels();\n for (const e of entries) {\n try { await core.tunnelService.stopTunnel(e.port); } catch { /* ignore system */ }\n }\n await ctx.answerCallbackQuery({ text: \"All tunnels stopped\" });\n await ctx.editMessageText(\"🔌 All tunnels stopped.\", { parse_mode: \"HTML\" });\n } else if (data.startsWith(\"tn:stop:\")) {\n const port = parseInt(data.replace(\"tn:stop:\", \"\"), 10);\n await core.tunnelService.stopTunnel(port);\n await ctx.answerCallbackQuery({ text: `Port ${port} stopped` });\n // Refresh list with keyboard\n const remaining = core.tunnelService.listTunnels();\n if (remaining.length === 0) {\n await ctx.editMessageText(\"🔌 All tunnels stopped.\", { parse_mode: \"HTML\" });\n } else {\n const kb = new InlineKeyboard();\n for (const e of remaining) {\n kb.text(`🔌 Stop ${e.port}${e.label ? ` (${e.label})` : \"\"}`, `tn:stop:${e.port}`).row();\n }\n if (remaining.length > 1) {\n kb.text(\"🔌 Stop all\", \"tn:stop-all\").row();\n }\n await ctx.editMessageText(\n `<b>Active tunnels:</b>\\n\\n` +\n remaining.map(e => {\n const status = e.status === \"active\" ? \"✅\" : \"⏳\";\n const label = e.label ? ` (${escapeHtml(e.label)})` : \"\";\n const url = e.publicUrl ? `\\n → <a href=\"${escapeHtml(e.publicUrl)}\">${escapeHtml(e.publicUrl)}</a>` : \"\";\n return `${status} Port <b>${e.port}</b>${label}${url}`;\n }).join(\"\\n\\n\"),\n { parse_mode: \"HTML\", reply_markup: kb },\n );\n }\n }\n } catch (err) {\n await ctx.answerCallbackQuery({ text: (err as Error).message });\n }\n });\n}\n","import type { Bot, Context } from \"grammy\";\nimport type { OpenACPCore } from \"../../../core/index.js\";\nimport type { CommandsAssistantContext } from \"../types.js\";\n\n// Domain modules\nimport { handleNew, handleNewChat, setupNewSessionCallbacks, createSessionDirect } from './new-session.js'\nimport { handleCancel, handleStatus, handleTopics, handleUsage, handleArchive, handleArchiveConfirm, handleSummary, handleSummaryCallback, setupSessionCallbacks } from './session.js'\nimport { handleEnableDangerous, handleDisableDangerous, handleUpdate, handleRestart, handleTTS, handleVerbosity } from './admin.js'\nimport { handleMenu, handleHelp, handleClear, buildMenuKeyboard } from './menu.js'\nimport { handleAgents, handleInstall, handleAgentCallback } from \"./agents.js\";\nimport { handleIntegrate } from \"./integrate.js\";\nimport {\n handleResume,\n setupResumeCallbacks,\n handlePendingResumeInput,\n} from \"./resume.js\";\nimport { handleSettings, setupSettingsCallbacks } from \"./settings.js\";\nimport { handleDoctor, setupDoctorCallbacks } from \"./doctor.js\";\nimport { handleTunnel, handleTunnels, setupTunnelCallbacks } from \"./tunnel.js\";\n\nexport function setupCommands(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n assistant?: CommandsAssistantContext,\n): void {\n bot.command(\"new\", (ctx) => handleNew(ctx, core, chatId, assistant));\n bot.command(\"newchat\", (ctx) => handleNewChat(ctx, core, chatId));\n bot.command(\"cancel\", (ctx) => handleCancel(ctx, core, assistant));\n bot.command(\"status\", (ctx) => handleStatus(ctx, core));\n bot.command(\"sessions\", (ctx) => handleTopics(ctx, core));\n bot.command(\"agents\", (ctx) => handleAgents(ctx, core));\n bot.command(\"install\", (ctx) => handleInstall(ctx, core));\n bot.command(\"help\", (ctx) => handleHelp(ctx));\n bot.command(\"menu\", (ctx) => handleMenu(ctx));\n bot.command(\"enable_dangerous\", (ctx) => handleEnableDangerous(ctx, core));\n bot.command(\"disable_dangerous\", (ctx) => handleDisableDangerous(ctx, core));\n bot.command(\"restart\", (ctx) => handleRestart(ctx, core));\n bot.command(\"update\", (ctx) => handleUpdate(ctx, core));\n bot.command(\"integrate\", (ctx) => handleIntegrate(ctx, core));\n bot.command(\"clear\", (ctx) => handleClear(ctx, assistant));\n bot.command(\"doctor\", (ctx) => handleDoctor(ctx));\n bot.command(\"usage\", (ctx) => handleUsage(ctx, core));\n bot.command(\"tunnel\", (ctx) => handleTunnel(ctx, core));\n bot.command(\"tunnels\", (ctx) => handleTunnels(ctx, core));\n bot.command(\"archive\", (ctx) => handleArchive(ctx, core));\n bot.command(\"summary\", (ctx) => handleSummary(ctx, core));\n bot.command(\"text_to_speech\", (ctx) => handleTTS(ctx, core));\n bot.command(\"verbosity\", (ctx) => handleVerbosity(ctx, core));\n bot.command(\"resume\", (ctx) => handleResume(ctx, core, chatId, assistant));\n}\n\nexport function setupAllCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n systemTopicIds?: { notificationTopicId: number; assistantTopicId: number },\n getAssistantSession?: () =>\n | { topicId: number; enqueuePrompt: (p: string) => Promise<void> }\n | undefined,\n): void {\n // Register specific prefix handlers FIRST (grammY middleware order matters)\n setupNewSessionCallbacks(bot, core, chatId);\n setupResumeCallbacks(bot, core, chatId);\n setupSessionCallbacks(bot, core, chatId, systemTopicIds);\n\n // Settings handlers — must be before broad m: handler\n setupSettingsCallbacks(bot, core, getAssistantSession ?? (() => undefined));\n\n // Doctor handlers — must be before broad m: handler\n setupDoctorCallbacks(bot);\n\n // Tunnel callbacks — must be before broad m: handler\n setupTunnelCallbacks(bot, core);\n\n // Agent callbacks (install + pagination) — must be before broad m: handler\n bot.callbackQuery(/^ag:/, (ctx) => handleAgentCallback(ctx, core));\n\n // New session with specific agent callback — must be before broad m: handler\n bot.callbackQuery(/^na:/, async (ctx) => {\n const agentKey = ctx.callbackQuery.data!.replace(\"na:\", \"\");\n await ctx.answerCallbackQuery();\n await createSessionDirect(\n ctx,\n core,\n chatId,\n agentKey,\n core.configManager.get().workspace.baseDir,\n );\n });\n\n // Archive confirmation callbacks\n bot.callbackQuery(/^ar:/, (ctx) => handleArchiveConfirm(ctx, core, chatId));\n\n // Summary button callbacks\n bot.callbackQuery(/^sm:/, (ctx) => handleSummaryCallback(ctx, core, chatId));\n\n // Broad m: handler for remaining menu dispatch — LAST\n bot.callbackQuery(/^m:/, async (ctx) => {\n const data = ctx.callbackQuery.data;\n try {\n await ctx.answerCallbackQuery();\n } catch {\n /* expired or network — ignore */\n }\n\n switch (data) {\n case \"m:new\":\n await handleNew(ctx, core, chatId);\n break;\n case \"m:status\":\n await handleStatus(ctx, core);\n break;\n case \"m:agents\":\n await handleAgents(ctx, core);\n break;\n case \"m:help\":\n await handleHelp(ctx);\n break;\n case \"m:restart\":\n await handleRestart(ctx, core);\n break;\n case \"m:update\":\n await handleUpdate(ctx, core);\n break;\n case \"m:integrate\":\n await handleIntegrate(ctx, core);\n break;\n case \"m:topics\":\n await handleTopics(ctx, core);\n break;\n case \"m:settings\":\n await handleSettings(ctx, core);\n break;\n }\n });\n}\n\n// Backward compat alias\nexport { setupAllCallbacks as setupMenuCallbacks };\n\n// Re-exports for external consumers (adapter.ts, action-detect.ts)\nexport { buildMenuKeyboard } from \"./menu.js\";\nexport { buildSkillMessages } from \"./menu.js\";\nexport {\n handlePendingWorkspaceInput,\n executeNewSession,\n startInteractiveNewSession,\n} from \"./new-session.js\";\nexport { executeCancelSession } from \"./session.js\";\nexport {\n setupDangerousModeCallbacks,\n buildDangerousModeKeyboard,\n} from \"./admin.js\";\nexport {\n setupTTSCallbacks,\n setupVerbosityCallbacks,\n buildTTSKeyboard,\n buildSessionControlKeyboard,\n handleTTS,\n handleVerbosity,\n} from \"./admin.js\";\nexport { setupIntegrateCallbacks } from \"./integrate.js\";\nexport { setupSettingsCallbacks } from \"./settings.js\";\nexport { setupDoctorCallbacks } from \"./doctor.js\";\nexport { handlePendingResumeInput, setupResumeCallbacks } from \"./resume.js\";\n\nexport const STATIC_COMMANDS = [\n { command: \"new\", description: \"Create new session\" },\n { command: \"newchat\", description: \"New chat, same agent & workspace\" },\n { command: \"cancel\", description: \"Cancel current session\" },\n { command: \"status\", description: \"Show status\" },\n { command: \"sessions\", description: \"List all sessions\" },\n { command: \"agents\", description: \"List available agents\" },\n { command: \"install\", description: \"Install a new agent\" },\n { command: \"help\", description: \"Help\" },\n { command: \"menu\", description: \"Show menu\" },\n {\n command: \"enable_dangerous\",\n description: \"Auto-approve all permission requests (session only)\",\n },\n {\n command: \"disable_dangerous\",\n description: \"Restore normal permission prompts (session only)\",\n },\n { command: \"integrate\", description: \"Manage agent integrations\" },\n { command: \"handoff\", description: \"Continue this session in your terminal\" },\n { command: \"clear\", description: \"Clear assistant history\" },\n { command: \"restart\", description: \"Restart OpenACP\" },\n { command: \"update\", description: \"Update to latest version and restart\" },\n { command: \"doctor\", description: \"Run system diagnostics\" },\n { command: \"usage\", description: \"View token usage and cost report\" },\n { command: \"tunnel\", description: \"Create/stop tunnel for a local port\" },\n { command: \"tunnels\", description: \"List active tunnels\" },\n { command: 'archive', description: 'Archive session topic (recreate with clean history)' },\n { command: 'summary', description: 'Get AI summary of current session' },\n { command: 'text_to_speech', description: 'Toggle Text to Speech (/text_to_speech on, /text_to_speech off)' },\n { command: 'verbosity', description: 'Set display verbosity (/verbosity low|medium|high)' },\n { command: 'resume', description: 'Resume with conversation history from Entire checkpoints' },\n];\n","import type { Bot } from 'grammy'\nimport { InlineKeyboard } from 'grammy'\nimport { nanoid } from 'nanoid'\nimport type { PermissionRequest, NotificationMessage, Session } from '../../core/index.js'\nimport { escapeHtml } from './formatting.js'\nimport { buildDeepLink } from './topics.js'\nimport { createChildLogger } from '../../core/log.js'\nconst log = createChildLogger({ module: 'telegram-permissions' })\n\n// Stored pending permission callbacks: callbackKey → { sessionId, requestId, options }\ninterface PendingPermission {\n sessionId: string\n requestId: string\n options: { id: string; isAllow: boolean }[]\n}\n\nexport class PermissionHandler {\n private pending: Map<string, PendingPermission> = new Map()\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private getSession: (sessionId: string) => Session | undefined,\n private sendNotification: (notification: NotificationMessage) => Promise<void>,\n ) {}\n\n async sendPermissionRequest(session: Session, request: PermissionRequest): Promise<void> {\n const threadId = Number(session.threadId)\n\n // Short callback key (Telegram 64-byte limit on callback_data)\n const callbackKey = nanoid(8)\n this.pending.set(callbackKey, {\n sessionId: session.id,\n requestId: request.id,\n options: request.options.map(o => ({ id: o.id, isAllow: o.isAllow })),\n })\n\n // Build inline keyboard\n const keyboard = new InlineKeyboard()\n for (const option of request.options) {\n const emoji = option.isAllow ? '✅' : '❌'\n keyboard.text(`${emoji} ${option.label}`, `p:${callbackKey}:${option.id}`)\n }\n\n // Send in session topic WITH notification\n const msg = await this.bot.api.sendMessage(this.chatId,\n `🔐 <b>Permission request:</b>\\n\\n${escapeHtml(request.description)}`,\n {\n message_thread_id: threadId,\n parse_mode: 'HTML',\n reply_markup: keyboard,\n disable_notification: false,\n }\n )\n\n // Deep link for notification — include threadId so link navigates into the topic\n const deepLink = buildDeepLink(this.chatId, threadId, msg.message_id)\n\n // Notify in notification topic (fire-and-forget to avoid sendQueue deadlock:\n // this method runs INSIDE a sendQueue item, so awaiting another enqueue() deadlocks)\n void this.sendNotification({\n sessionId: session.id,\n sessionName: session.name,\n type: 'permission',\n summary: request.description,\n deepLink,\n })\n }\n\n setupCallbackHandler(): void {\n this.bot.on('callback_query:data', async (ctx) => {\n const data = ctx.callbackQuery.data\n if (!data.startsWith('p:')) return\n\n const parts = data.split(':')\n if (parts.length < 3) return\n const [, callbackKey, optionId] = parts\n\n const pending = this.pending.get(callbackKey)\n if (!pending) {\n try { await ctx.answerCallbackQuery({ text: '❌ Expired' }) } catch { /* old query */ }\n return\n }\n\n const session = this.getSession(pending.sessionId)\n const isAllow = pending.options.find(o => o.id === optionId)?.isAllow ?? false\n log.info({ requestId: pending.requestId, optionId, isAllow }, 'Permission responded')\n if (session?.permissionGate.requestId === pending.requestId) {\n session.permissionGate.resolve(optionId)\n }\n this.pending.delete(callbackKey)\n\n try { await ctx.answerCallbackQuery({ text: '✅ Responded' }) } catch { /* old query */ }\n\n // Remove buttons\n try {\n await ctx.editMessageReplyMarkup({ reply_markup: undefined })\n } catch { /* ignore */ }\n })\n }\n}\n","import type { OpenACPCore, ChannelAdapter, Config, Session } from \"../../core/index.js\";\nimport { createChildLogger } from \"../../core/log.js\";\nimport { PRODUCT_GUIDE } from \"../../product-guide.js\";\nconst log = createChildLogger({ module: \"telegram-assistant\" });\n\nexport type SpawnAssistantResult = {\n session: Session;\n /** Resolves when the background system prompt completes (or fails). */\n ready: Promise<void>;\n};\n\nexport async function spawnAssistant(\n core: OpenACPCore,\n adapter: ChannelAdapter,\n assistantTopicId: number,\n): Promise<SpawnAssistantResult> {\n const config = core.configManager.get();\n\n // Create session with default agent via unified pipeline\n log.info({ agent: config.defaultAgent }, \"Creating assistant session...\");\n const session = await core.createSession({\n channelId: \"telegram\",\n agentName: config.defaultAgent,\n workingDirectory: core.configManager.resolveWorkspace(),\n initialName: \"Assistant\", // Prevent auto-naming from triggering after system prompt\n });\n session.threadId = String(assistantTopicId);\n log.info({ sessionId: session.id }, \"Assistant agent spawned\");\n\n // Build dynamic context for system prompt\n const allRecords = core.sessionManager.listRecords();\n const activeCount = allRecords.filter(r => r.status === 'active' || r.status === 'initializing').length;\n const statusCounts = new Map<string, number>();\n for (const r of allRecords) {\n statusCounts.set(r.status, (statusCounts.get(r.status) ?? 0) + 1);\n }\n const topicSummary = Array.from(statusCounts.entries()).map(([status, count]) => ({ status, count }));\n\n // Get agent info from catalog\n const installedAgents = Object.keys(core.agentCatalog.getInstalledEntries());\n const availableItems = core.agentCatalog.getAvailable();\n const availableAgentCount = availableItems.filter(i => !i.installed).length;\n\n const ctx: AssistantContext = {\n config,\n activeSessionCount: activeCount,\n totalSessionCount: allRecords.length,\n topicSummary,\n installedAgents,\n availableAgentCount,\n };\n\n // Fire system prompt in background — don't block startup.\n const systemPrompt = buildAssistantSystemPrompt(ctx);\n const ready = session.enqueuePrompt(systemPrompt)\n .then(() => { log.info({ sessionId: session.id }, \"Assistant system prompt completed\"); })\n .catch((err) => { log.warn({ err }, \"Assistant system prompt failed\"); });\n\n return { session, ready };\n}\n\nexport interface AssistantContext {\n config: Config\n activeSessionCount: number\n totalSessionCount: number\n topicSummary: { status: string; count: number }[]\n installedAgents?: string[]\n availableAgentCount?: number\n}\n\nexport interface WelcomeContext {\n activeCount: number;\n errorCount: number;\n totalCount: number;\n agents: string[];\n defaultAgent: string;\n}\n\nexport function buildWelcomeMessage(ctx: WelcomeContext): string {\n const { activeCount, errorCount, totalCount, agents, defaultAgent } = ctx;\n\n const agentList = agents\n .map((a) => `${a}${a === defaultAgent ? \" (default)\" : \"\"}`)\n .join(\", \");\n\n // Variant 1: No sessions\n if (totalCount === 0) {\n return `👋 <b>OpenACP is ready!</b>\\n\\nNo sessions yet. Tap 🆕 New Session to start, or ask me anything!`;\n }\n\n // Variant 2: Has errors\n if (errorCount > 0) {\n return (\n `👋 <b>OpenACP is ready!</b>\\n\\n` +\n `📊 ${activeCount} active, ${errorCount} errors / ${totalCount} total\\n` +\n `⚠️ ${errorCount} session${errorCount > 1 ? \"s have\" : \" has\"} errors — ask me to check if you'd like.\\n\\n` +\n `Agents: ${agentList}`\n );\n }\n\n // Variant 3/4: Has active or fallback\n return (\n `👋 <b>OpenACP is ready!</b>\\n\\n` +\n `📊 ${activeCount} active / ${totalCount} total\\n` +\n `Agents: ${agentList}`\n );\n}\n\nexport function buildAssistantSystemPrompt(ctx: AssistantContext): string {\n const { config, activeSessionCount, totalSessionCount, topicSummary, installedAgents, availableAgentCount } = ctx;\n const agentNames = installedAgents?.length ? installedAgents.join(\", \") : Object.keys(config.agents).join(\", \");\n const topicBreakdown =\n topicSummary.map((s) => `${s.status}: ${s.count}`).join(\", \") || \"none\";\n\n return `You are the OpenACP Assistant — a helpful guide for managing AI coding sessions.\n\n## Current State\n- Active sessions: ${activeSessionCount} / ${totalSessionCount} total\n- Topics by status: ${topicBreakdown}\n- Installed agents: ${agentNames}\n- Available in ACP Registry: ${availableAgentCount ?? \"28+\"} more agents (use /agents to browse)\n- Default agent: ${config.defaultAgent}\n- Workspace base directory: ${config.workspace.baseDir}\n- STT: ${config.speech?.stt?.provider ? `${config.speech.stt.provider} ✅` : \"Not configured\"}\n\n## Action Playbook\n\n### Create Session\n- The workspace is the project directory where the agent will work (read, write, execute code). It is NOT the base directory — it should be a specific project folder like \\`~/code/my-project\\` or \\`${config.workspace.baseDir}/my-app\\`.\n- Ask which agent to use (if multiple are installed). Show installed: ${agentNames}\n- Ask which project directory to use as workspace. Suggest \\`${config.workspace.baseDir}\\` as the base, but explain the user can provide any path.\n- Confirm before creating: show agent name + full workspace path.\n- Create via: \\`openacp api new <agent> <workspace>\\`\n\n### Browse & Install Agents\n- Guide users to /agents command to see all available agents (installed + from ACP Registry)\n- The /agents list is paginated with install buttons — users can tap to install directly\n- For CLI users: \\`openacp agents install <name>\\`\n- Some agents need login/setup after install — guide users to \\`openacp agents info <name>\\` for setup steps\n- To run agent CLI for login: \\`openacp agents run <name> -- <args>\\`\n- Common setup examples:\n - Gemini: \\`openacp agents run gemini -- auth login\\`\n - GitHub Copilot: \\`openacp agents run copilot -- auth login\\`\n - Codex: needs OPENAI_API_KEY environment variable\n\n### Check Status / List Sessions\n- Run \\`openacp api status\\` for active sessions overview\n- Run \\`openacp api topics\\` for full list with statuses\n- Format the output nicely for the user\n\n### Cancel Session\n- Run \\`openacp api status\\` to see what's active\n- If 1 active session → ask user to confirm → \\`openacp api cancel <id>\\`\n- If multiple → list them, ask user which one to cancel\n\n### Troubleshoot (Session Stuck, Errors)\n- Run \\`openacp api health\\` + \\`openacp api status\\` to diagnose\n- Small issue (stuck session) → suggest cancel + create new\n- Big issue (system-level) → suggest restart, ask for confirmation first\n\n### Cleanup Old Sessions\n- Run \\`openacp api topics --status finished,error\\` to see what can be cleaned\n- Report the count, ask user to confirm\n- Execute: \\`openacp api cleanup --status <statuses>\\`\n\n### Configuration\n- View: \\`openacp config\\` (or \\`openacp api config\\` — deprecated)\n- Update: \\`openacp config set <key> <value>\\`\n- When user asks about \"settings\" or \"config\", use \\`openacp config set\\` directly\n- When receiving a delegated request from the Settings menu, ask user for the new value, then apply with \\`openacp config set <path> <value>\\`\n\n### Voice / Speech-to-Text\n- OpenACP can transcribe voice messages to text using STT providers (Groq Whisper, OpenAI Whisper)\n- Current STT provider: ${config.speech?.stt?.provider ?? \"Not configured\"}\n- To enable: user needs an API key from the STT provider\n - Groq (recommended, free tier ~8h/day): Get key at console.groq.com → API Keys\n - Set via: \\`openacp config set speech.stt.provider groq\\` then \\`openacp config set speech.stt.providers.groq.apiKey <key>\\`\n- When STT is configured, voice messages are automatically transcribed before sending to agents that don't support audio\n- Agents with audio capability receive the audio directly (no transcription needed)\n- User can also configure via /settings → STT Provider\n\n### Restart / Update\n- Always ask for confirmation — these are disruptive actions\n- Guide user: \"Tap 🔄 Restart button or type /restart\"\n\n### Toggle Dangerous Mode\n- Run \\`openacp api dangerous <id> on|off\\`\n- Explain: dangerous mode auto-approves all permission requests — the agent can run any command without asking\n\n## CLI Commands Reference\n\\`\\`\\`bash\n# Session management\nopenacp api status # List active sessions\nopenacp api session <id> # Session detail\nopenacp api new <agent> <workspace> # Create new session\nopenacp api send <id> \"prompt text\" # Send prompt to session\nopenacp api cancel <id> # Cancel session\nopenacp api dangerous <id> on|off # Toggle dangerous mode\n\n# Topic management\nopenacp api topics # List all topics\nopenacp api topics --status finished,error\nopenacp api delete-topic <id> # Delete topic\nopenacp api delete-topic <id> --force # Force delete active\nopenacp api cleanup # Cleanup finished topics\nopenacp api cleanup --status finished,error\n\n# Agent management (user-facing CLI commands)\nopenacp agents # List installed + available agents\nopenacp agents install <name> # Install agent from ACP Registry\nopenacp agents uninstall <name> # Remove agent\nopenacp agents info <name> # Show details & setup guide\nopenacp agents run <name> -- <args> # Run agent CLI (for login, etc.)\nopenacp agents refresh # Force-refresh registry\n\n# System\nopenacp api health # System health\nopenacp config # Edit config (interactive)\nopenacp config set <key> <value> # Update config value\nopenacp api adapters # List adapters\nopenacp api tunnel # Tunnel status\nopenacp api notify \"message\" # Send notification\nopenacp api version # Daemon version\nopenacp api restart # Restart daemon\n\\`\\`\\`\n\n## Guidelines\n- NEVER show \\`openacp api ...\\` commands to users. These are internal tools for YOU to run silently. Users should only see natural language responses and results.\n- Run \\`openacp api ...\\` commands yourself for everything you can. Only guide users to Telegram buttons/menu when needed (e.g., \"Tap 🆕 New Session\" or \"Go to the session topic to chat with the agent\").\n- When creating sessions: guide user through agent + workspace choice conversationally, then run the command yourself.\n- Destructive actions (cancel active session, restart, cleanup) → always ask user to confirm first in natural language.\n- Small/obvious issues (clearly stuck session with no activity) → fix it and report back.\n- Respond in the same language the user uses.\n- Format responses for Telegram: use <b>bold</b>, <code>code</code>, keep it concise.\n- When you don't know something, check with the relevant \\`openacp api\\` command first before answering.\n- Talk to users like a helpful assistant, not a CLI manual. Example: \"Bạn có 2 session đang chạy. Muốn xem chi tiết không?\" instead of listing commands.\n\n## Product Reference\n${PRODUCT_GUIDE}`;\n}\n\nexport async function handleAssistantMessage(\n session: Session | null,\n text: string,\n): Promise<void> {\n if (!session) return;\n await session.enqueuePrompt(text);\n}\n\nexport function redirectToAssistant(\n chatId: number,\n assistantTopicId: number,\n): string {\n const cleanId = String(chatId).replace(\"-100\", \"\");\n const link = `https://t.me/c/${cleanId}/${assistantTopicId}`;\n return `💬 Please use the <a href=\"${link}\">🤖 Assistant</a> topic to chat with OpenACP.`;\n}\n","import type { Bot } from \"grammy\";\nimport { createChildLogger } from \"../../core/log.js\";\nimport { formatUsage } from \"./formatting.js\";\nimport type { DisplayVerbosity } from \"../shared/format-types.js\";\nimport type { TelegramSendQueue } from \"./send-queue.js\";\nimport type { PlanEntry } from \"../../core/types.js\";\n\nconst log = createChildLogger({ module: \"telegram:activity\" });\n\n// ─── ThinkingIndicator ────────────────────────────────────────────────────────\n\nconst THINKING_REFRESH_MS = 15_000;\nconst THINKING_MAX_MS = 3 * 60 * 1000;\n\nexport class ThinkingIndicator {\n private msgId?: number;\n private sending = false;\n private dismissed = false;\n private refreshTimer?: ReturnType<typeof setInterval>;\n private showTime = 0;\n\n constructor(\n private api: Bot[\"api\"],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n async show(): Promise<void> {\n if (this.msgId || this.sending || this.dismissed) return;\n this.sending = true;\n this.showTime = Date.now();\n try {\n const result = await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, \"💭 <i>Thinking...</i>\", {\n message_thread_id: this.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n }),\n );\n if (result && !this.dismissed) {\n this.msgId = result.message_id;\n this.startRefreshTimer();\n }\n } catch (err) {\n log.warn({ err }, \"ThinkingIndicator.show() failed\");\n } finally {\n this.sending = false;\n }\n }\n\n /** Clear state — stops refresh timer, no Telegram API call */\n dismiss(): void {\n this.dismissed = true;\n this.msgId = undefined;\n this.stopRefreshTimer();\n }\n\n /** Reset for a new prompt cycle */\n reset(): void {\n this.dismissed = false;\n }\n\n private startRefreshTimer(): void {\n this.stopRefreshTimer();\n this.refreshTimer = setInterval(() => {\n if (\n this.dismissed ||\n !this.msgId ||\n Date.now() - this.showTime >= THINKING_MAX_MS\n ) {\n this.stopRefreshTimer();\n return;\n }\n const elapsed = Math.round((Date.now() - this.showTime) / 1000);\n this.sendQueue\n .enqueue(() => {\n // Re-check after waiting in queue — dismiss may have been called\n if (this.dismissed) return Promise.resolve(undefined);\n return this.api.sendMessage(\n this.chatId,\n `💭 <i>Still thinking... (${elapsed}s)</i>`,\n {\n message_thread_id: this.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n },\n );\n })\n .then((result) => {\n if (result && !this.dismissed) {\n this.msgId = result.message_id;\n }\n })\n .catch(() => {});\n }, THINKING_REFRESH_MS);\n }\n\n private stopRefreshTimer(): void {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n this.refreshTimer = undefined;\n }\n }\n}\n\n// ─── UsageMessage ─────────────────────────────────────────────────────────────\n\nexport class UsageMessage {\n private msgId?: number;\n\n constructor(\n private api: Bot[\"api\"],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n async send(\n usage: { tokensUsed?: number; contextSize?: number; cost?: number },\n verbosity: DisplayVerbosity = \"medium\",\n ): Promise<void> {\n const text = formatUsage(usage, verbosity);\n try {\n if (this.msgId) {\n await this.sendQueue.enqueue(() =>\n this.api.editMessageText(this.chatId, this.msgId!, text, {\n parse_mode: \"HTML\",\n }),\n );\n } else {\n const result = await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, text, {\n message_thread_id: this.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n }),\n );\n if (result) this.msgId = result.message_id;\n }\n } catch (err) {\n log.warn({ err }, \"UsageMessage.send() failed\");\n }\n }\n\n getMsgId(): number | undefined {\n return this.msgId;\n }\n\n async delete(): Promise<void> {\n if (!this.msgId) return;\n const id = this.msgId;\n this.msgId = undefined;\n try {\n await this.sendQueue.enqueue(() =>\n this.api.deleteMessage(this.chatId, id),\n );\n } catch (err) {\n log.warn({ err }, \"UsageMessage.delete() failed\");\n }\n }\n}\n\n// ─── PlanCard ─────────────────────────────────────────────────────────────────\n\nfunction formatPlanCard(\n entries: PlanEntry[],\n verbosity: DisplayVerbosity = \"medium\",\n): string {\n if (verbosity === \"medium\") {\n const done = entries.filter((e) => e.status === \"completed\").length;\n return `📋 <b>Plan:</b> ${done}/${entries.length} steps completed`;\n }\n const statusIcon: Record<string, string> = {\n completed: \"✅\",\n in_progress: \"🔄\",\n pending: \"⬜\",\n failed: \"❌\",\n };\n const total = entries.length;\n const done = entries.filter((e) => e.status === \"completed\").length;\n const ratio = total > 0 ? done / total : 0;\n const filled = Math.round(ratio * 10);\n const bar = \"▓\".repeat(filled) + \"░\".repeat(10 - filled);\n const pct = Math.round(ratio * 100);\n const header = `📋 <b>Plan</b>\\n${bar} ${pct}% · ${done}/${total}`;\n const lines = entries.map((e, i) => {\n const icon = statusIcon[e.status] ?? \"⬜\";\n return `${icon} ${i + 1}. ${e.content}`;\n });\n return [header, ...lines].join(\"\\n\");\n}\n\nexport class PlanCard {\n private msgId?: number;\n private flushPromise: Promise<void> = Promise.resolve();\n private latestEntries?: PlanEntry[];\n private lastSentText?: string;\n private flushTimer?: ReturnType<typeof setTimeout>;\n private verbosity: DisplayVerbosity = \"medium\";\n\n constructor(\n private api: Bot[\"api\"],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n setVerbosity(v: DisplayVerbosity): void {\n this.verbosity = v;\n }\n\n update(entries: PlanEntry[]): void {\n this.latestEntries = entries;\n if (this.flushTimer) clearTimeout(this.flushTimer);\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined;\n this.flushPromise = this.flushPromise\n .then(() => this._flush())\n .catch(() => {});\n }, 3500);\n }\n\n async finalize(): Promise<void> {\n if (!this.latestEntries) return;\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n await this.flushPromise;\n this.flushPromise = this.flushPromise\n .then(() => this._flush())\n .catch(() => {});\n await this.flushPromise;\n }\n\n destroy(): void {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n }\n\n private async _flush(): Promise<void> {\n if (!this.latestEntries) return;\n const text = formatPlanCard(this.latestEntries, this.verbosity);\n if (this.msgId && text === this.lastSentText) return;\n this.lastSentText = text;\n try {\n if (this.msgId) {\n await this.sendQueue.enqueue(() =>\n this.api.editMessageText(this.chatId, this.msgId!, text, {\n parse_mode: \"HTML\",\n }),\n );\n } else {\n const result = await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, text, {\n message_thread_id: this.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n }),\n );\n if (result) this.msgId = result.message_id;\n }\n } catch (err) {\n log.warn({ err }, \"PlanCard flush failed\");\n }\n }\n}\n\n// ─── ActivityTracker ──────────────────────────────────────────────────────────\n\nexport class ActivityTracker {\n private isFirstEvent = true;\n private hasPlanCard = false;\n private thinking: ThinkingIndicator;\n private planCard: PlanCard;\n private usage: UsageMessage;\n\n constructor(\n private api: Bot[\"api\"],\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n ) {\n this.thinking = new ThinkingIndicator(api, chatId, threadId, sendQueue);\n this.planCard = new PlanCard(api, chatId, threadId, sendQueue);\n this.usage = new UsageMessage(api, chatId, threadId, sendQueue);\n }\n\n async onNewPrompt(): Promise<void> {\n this.isFirstEvent = true;\n this.hasPlanCard = false;\n this.thinking.dismiss();\n this.thinking.reset();\n }\n\n async onThought(): Promise<void> {\n await this._firstEventGuard();\n await this.thinking.show();\n }\n\n async onPlan(\n entries: PlanEntry[],\n verbosity?: DisplayVerbosity,\n ): Promise<void> {\n await this._firstEventGuard();\n this.thinking.dismiss();\n this.hasPlanCard = true;\n if (verbosity) this.planCard.setVerbosity(verbosity);\n this.planCard.update(entries);\n }\n\n async onToolCall(): Promise<void> {\n await this._firstEventGuard();\n this.thinking.dismiss();\n this.thinking.reset();\n }\n\n async onTextStart(): Promise<void> {\n await this._firstEventGuard();\n this.thinking.dismiss();\n }\n\n async sendUsage(\n data: { tokensUsed?: number; contextSize?: number; cost?: number },\n verbosity: DisplayVerbosity = \"medium\",\n ): Promise<void> {\n await this.usage.send(data, verbosity);\n }\n\n getUsageMsgId(): number | undefined {\n return this.usage.getMsgId();\n }\n\n async onComplete(): Promise<void> {\n if (this.hasPlanCard) {\n await this.planCard.finalize();\n } else {\n try {\n await this.sendQueue.enqueue(() =>\n this.api.sendMessage(this.chatId, \"✅ <b>Done</b>\", {\n message_thread_id: this.threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n }),\n );\n } catch (err) {\n log.warn({ err }, \"ActivityTracker.onComplete() Done send failed\");\n }\n }\n }\n\n destroy(): void {\n this.thinking.dismiss();\n this.planCard.destroy();\n }\n\n private async _firstEventGuard(): Promise<void> {\n if (!this.isFirstEvent) return;\n this.isFirstEvent = false;\n await this.usage.delete();\n }\n}\n","export type QueueItemType = 'text' | 'other'\n\ninterface QueueItem<T = unknown> {\n fn: () => Promise<T>\n type: QueueItemType\n key?: string\n resolve: (value: T | undefined) => void\n reject: (err: unknown) => void\n}\n\nexport class TelegramSendQueue {\n private items: QueueItem[] = []\n private processing = false\n private lastExec = 0\n private minInterval: number\n\n constructor(minInterval = 3000) {\n this.minInterval = minInterval\n }\n\n enqueue<T>(\n fn: () => Promise<T>,\n opts?: { type?: QueueItemType; key?: string },\n ): Promise<T | undefined> {\n const type = opts?.type ?? 'other'\n const key = opts?.key\n\n return new Promise<T | undefined>((resolve, reject) => {\n if (type === 'text' && key) {\n const idx = this.items.findIndex(\n (item) => item.type === 'text' && item.key === key,\n )\n if (idx !== -1) {\n this.items[idx].resolve(undefined)\n this.items[idx] = { fn, type, key, resolve, reject } as QueueItem\n this.scheduleProcess()\n return\n }\n }\n\n this.items.push({ fn, type, key, resolve, reject } as QueueItem)\n this.scheduleProcess()\n })\n }\n\n onRateLimited(): void {\n const remaining: QueueItem[] = []\n for (const item of this.items) {\n if (item.type === 'text') {\n item.resolve(undefined)\n } else {\n remaining.push(item)\n }\n }\n this.items = remaining\n }\n\n private scheduleProcess(): void {\n if (this.processing) return\n if (this.items.length === 0) return\n\n const elapsed = Date.now() - this.lastExec\n const delay = Math.max(0, this.minInterval - elapsed)\n\n this.processing = true\n setTimeout(() => void this.processNext(), delay)\n }\n\n private async processNext(): Promise<void> {\n const item = this.items.shift()\n if (!item) {\n this.processing = false\n return\n }\n\n try {\n const result = await item.fn()\n item.resolve(result)\n } catch (err) {\n item.reject(err)\n } finally {\n this.lastExec = Date.now()\n this.processing = false\n this.scheduleProcess()\n }\n }\n}\n","import { nanoid } from \"nanoid\";\nimport { InlineKeyboard } from \"grammy\";\nimport type { Bot } from \"grammy\";\nimport type { OpenACPCore } from \"../../core/core.js\";\nimport { executeNewSession, executeCancelSession, startInteractiveNewSession } from \"./commands/index.js\";\n\nexport interface DetectedAction {\n action: \"new_session\" | \"cancel_session\";\n agent?: string;\n workspace?: string;\n}\n\n// Command patterns: /new [agent] [workspace], /cancel\n// Agent and workspace are ASCII-only tokens (no Unicode letters) to avoid matching non-ASCII words\nconst CMD_NEW_RE =\n /\\/new(?:\\s+([^\\s\\u0080-\\uFFFF]+)(?:\\s+([^\\s\\u0080-\\uFFFF]+))?)?/;\nconst CMD_CANCEL_RE = /\\/cancel\\b/;\n\n// Keyword patterns (compound phrases only to avoid false positives)\nconst KW_NEW_RE = /(?:create|new)\\s+session/i;\nconst KW_CANCEL_RE = /(?:cancel|stop)\\s+session/i;\n\nexport function detectAction(text: string): DetectedAction | null {\n if (!text) return null;\n\n // Priority 1: command pattern\n const cancelCmd = CMD_CANCEL_RE.exec(text);\n if (cancelCmd) return { action: \"cancel_session\" };\n\n const newCmd = CMD_NEW_RE.exec(text);\n if (newCmd) {\n return {\n action: \"new_session\",\n agent: newCmd[1] || undefined,\n workspace: newCmd[2] || undefined,\n };\n }\n\n // Priority 2: keyword matching\n if (KW_CANCEL_RE.test(text)) return { action: \"cancel_session\" };\n if (KW_NEW_RE.test(text))\n return { action: \"new_session\", agent: undefined, workspace: undefined };\n\n return null;\n}\n\n// --- Callback map for action buttons ---\n\nconst ACTION_TTL_MS = 5 * 60 * 1000; // 5 minutes\nconst actionMap: Map<string, { action: DetectedAction; createdAt: number }> =\n new Map();\n\nexport function storeAction(action: DetectedAction): string {\n const id = nanoid(10);\n actionMap.set(id, { action, createdAt: Date.now() });\n // Cleanup expired entries\n for (const [key, entry] of actionMap) {\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(key);\n }\n }\n return id;\n}\n\nexport function getAction(id: string): DetectedAction | undefined {\n const entry = actionMap.get(id);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(id);\n return undefined;\n }\n return entry.action;\n}\n\nexport function removeAction(id: string): void {\n actionMap.delete(id);\n}\n\nexport function buildActionKeyboard(\n actionId: string,\n action: DetectedAction,\n): InlineKeyboard {\n const keyboard = new InlineKeyboard();\n if (action.action === \"new_session\") {\n keyboard.text(\"✅ Create session\", `a:${actionId}`);\n keyboard.text(\"❌ Cancel\", `a:dismiss:${actionId}`);\n } else {\n keyboard.text(\"⛔ Cancel session\", `a:${actionId}`);\n keyboard.text(\"❌ No\", `a:dismiss:${actionId}`);\n }\n return keyboard;\n}\n\nexport function setupActionCallbacks(\n bot: Bot,\n core: OpenACPCore,\n chatId: number,\n getAssistantSessionId: () => string | undefined,\n): void {\n // IMPORTANT: dismiss handler MUST be registered BEFORE generic a: handler\n // because grammY routes to the first matching handler and /^a:/ also matches a:dismiss:\n bot.callbackQuery(/^a:dismiss:/, async (ctx) => {\n const actionId = ctx.callbackQuery.data.replace(\"a:dismiss:\", \"\");\n removeAction(actionId);\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch {\n /* message may be old */\n }\n await ctx.answerCallbackQuery({ text: \"Dismissed\" });\n });\n\n bot.callbackQuery(/^a:(?!dismiss)/, async (ctx) => {\n const actionId = ctx.callbackQuery.data.replace(\"a:\", \"\");\n const action = getAction(actionId);\n if (!action) {\n await ctx.answerCallbackQuery({ text: \"Action expired\" });\n return;\n }\n removeAction(actionId);\n\n try {\n if (action.action === \"new_session\") {\n // If both agent and workspace provided → create directly\n if (action.agent && action.workspace) {\n await ctx.answerCallbackQuery({ text: \"⏳ Creating session...\" });\n const { threadId, firstMsgId } = await executeNewSession(\n bot,\n core,\n chatId,\n action.agent,\n action.workspace,\n );\n const cleanId = String(chatId).replace(\"-100\", \"\");\n const topicLink = firstMsgId\n ? `https://t.me/c/${cleanId}/${threadId}/${firstMsgId}`\n : `https://t.me/c/${cleanId}/${threadId}`;\n const originalText = ctx.callbackQuery.message?.text ?? \"\";\n try {\n await ctx.editMessageText(\n originalText +\n `\\n\\n✅ Session created → <a href=\"${topicLink}\">Go to topic</a>`,\n { parse_mode: \"HTML\" },\n );\n } catch {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n }\n } else {\n // Missing workspace → start interactive flow\n await ctx.answerCallbackQuery();\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch { /* best effort */ }\n await startInteractiveNewSession(ctx, core, chatId, action.agent);\n }\n } else if (action.action === \"cancel_session\") {\n const assistantId = getAssistantSessionId();\n const cancelled = await executeCancelSession(core, assistantId);\n if (cancelled) {\n await ctx.answerCallbackQuery({ text: \"⛔ Session cancelled\" });\n const originalText = ctx.callbackQuery.message?.text ?? \"\";\n try {\n await ctx.editMessageText(\n originalText +\n `\\n\\n⛔ Session \"${cancelled.name ?? cancelled.id}\" cancelled`,\n { parse_mode: \"HTML\" },\n );\n } catch {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n }\n } else {\n await ctx.answerCallbackQuery({\n text: \"No active session\",\n });\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch {\n /* best effort */\n }\n }\n }\n } catch {\n await ctx.answerCallbackQuery({ text: \"❌ Error, try again later\" });\n try {\n await ctx.editMessageReplyMarkup({\n reply_markup: { inline_keyboard: [] },\n });\n } catch {\n /* best effort */\n }\n }\n });\n}\n","import type { Bot } from \"grammy\";\nimport type { TelegramSendQueue } from \"./send-queue.js\";\nimport { formatToolCall, formatToolUpdate } from \"./formatting.js\";\nimport { createChildLogger } from \"../../core/log.js\";\nimport type {\n ToolCallMeta,\n ViewerLinks,\n DisplayVerbosity,\n} from \"../shared/format-types.js\";\n\nconst log = createChildLogger({ module: \"tool-call-tracker\" });\n\ninterface ToolCallState {\n msgId: number;\n name: string;\n kind?: string;\n rawInput?: unknown;\n viewerLinks?: ViewerLinks;\n viewerFilePath?: string;\n ready: Promise<void>;\n}\n\nexport class ToolCallTracker {\n private sessions: Map<string, Map<string, ToolCallState>> = new Map();\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n async trackNewCall(\n sessionId: string,\n threadId: number,\n meta: ToolCallMeta,\n verbosity: DisplayVerbosity = \"medium\",\n ): Promise<void> {\n if (!this.sessions.has(sessionId)) {\n this.sessions.set(sessionId, new Map());\n }\n\n let resolveReady!: () => void;\n const ready = new Promise<void>((r) => {\n resolveReady = r;\n });\n\n this.sessions.get(sessionId)!.set(meta.id, {\n msgId: 0,\n name: meta.name,\n kind: meta.kind,\n rawInput: meta.rawInput,\n viewerLinks: meta.viewerLinks,\n viewerFilePath: meta.viewerFilePath,\n ready,\n });\n\n try {\n const msg = await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(this.chatId, formatToolCall(meta, verbosity), {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n }),\n );\n\n const toolEntry = this.sessions.get(sessionId)!.get(meta.id)!;\n toolEntry.msgId = msg!.message_id;\n } finally {\n resolveReady();\n }\n }\n\n async updateCall(\n sessionId: string,\n meta: ToolCallMeta & { status: string },\n verbosity: DisplayVerbosity = \"medium\",\n ): Promise<void> {\n const toolState = this.sessions.get(sessionId)?.get(meta.id);\n if (!toolState) return;\n\n // Accumulate state from intermediate updates\n if (meta.viewerLinks) {\n toolState.viewerLinks = meta.viewerLinks;\n log.debug(\n { toolId: meta.id, viewerLinks: meta.viewerLinks },\n \"Accumulated viewerLinks\",\n );\n }\n if (meta.viewerFilePath) toolState.viewerFilePath = meta.viewerFilePath;\n if (meta.name) toolState.name = meta.name;\n if (meta.kind) toolState.kind = meta.kind;\n\n // Only edit on terminal status — minimizes API calls to avoid rate limits\n const isTerminal = meta.status === \"completed\" || meta.status === \"failed\";\n if (!isTerminal) return;\n\n await toolState.ready;\n\n log.debug(\n {\n toolId: meta.id,\n status: meta.status,\n hasViewerLinks: !!toolState.viewerLinks,\n viewerLinks: toolState.viewerLinks,\n name: toolState.name,\n msgId: toolState.msgId,\n },\n \"Tool completed, preparing edit\",\n );\n\n const merged = {\n ...meta,\n name: toolState.name,\n kind: toolState.kind,\n rawInput: toolState.rawInput,\n viewerLinks: toolState.viewerLinks,\n viewerFilePath: toolState.viewerFilePath,\n };\n const formattedText = formatToolUpdate(merged, verbosity);\n\n try {\n await this.sendQueue.enqueue(() =>\n this.bot.api.editMessageText(\n this.chatId,\n toolState.msgId,\n formattedText,\n { parse_mode: \"HTML\" },\n ),\n );\n } catch (err) {\n log.warn(\n {\n err,\n msgId: toolState.msgId,\n textLen: formattedText.length,\n hasViewerLinks: !!merged.viewerLinks,\n },\n \"Tool update edit failed\",\n );\n }\n }\n\n cleanup(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n}\n","import type { Bot } from 'grammy'\nimport { markdownToTelegramHtml, splitMessage } from './formatting.js'\nimport type { TelegramSendQueue } from './send-queue.js'\n\nconst FLUSH_INTERVAL = 5000\n\nexport class MessageDraft {\n private buffer: string = ''\n private messageId?: number\n private firstFlushPending = false\n private flushTimer?: ReturnType<typeof setTimeout>\n private flushPromise: Promise<void> = Promise.resolve()\n private lastSentBuffer: string = ''\n private displayTruncated = false\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private threadId: number,\n private sendQueue: TelegramSendQueue,\n private sessionId: string,\n ) {}\n\n append(text: string): void {\n if (!text) return\n this.buffer += text\n this.scheduleFlush()\n }\n\n private scheduleFlush(): void {\n if (this.flushTimer) return\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined\n this.flushPromise = this.flushPromise\n .then(() => this.flush())\n .catch(() => {})\n }, FLUSH_INTERVAL)\n }\n\n private async flush(): Promise<void> {\n if (!this.buffer) return\n if (this.firstFlushPending) return\n\n // CRITICAL: Snapshot the buffer BEFORE any await.\n // append() can be called synchronously while we're awaiting sendQueue,\n // so this.buffer may change. We must track what was ACTUALLY sent.\n const snapshot = this.buffer\n\n let html = markdownToTelegramHtml(snapshot)\n if (!html) return\n let truncated = false\n if (html.length > 4096) {\n // Estimate markdown cut point proportionally, then find a line boundary\n const ratio = 4000 / html.length\n const targetLen = Math.floor(snapshot.length * ratio)\n let cutAt = snapshot.lastIndexOf('\\n', targetLen)\n if (cutAt < targetLen * 0.5) cutAt = targetLen\n html = markdownToTelegramHtml(snapshot.slice(0, cutAt) + '\\n…')\n truncated = true\n if (html.length > 4096) {\n html = html.slice(0, 4090) + '\\n…'\n }\n }\n\n if (!this.messageId) {\n this.firstFlushPending = true\n try {\n const result = await this.sendQueue.enqueue(\n () => this.bot.api.sendMessage(this.chatId, html, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n { type: 'other' },\n )\n if (result) {\n this.messageId = result.message_id\n if (!truncated) {\n this.lastSentBuffer = snapshot\n this.displayTruncated = false\n } else {\n this.displayTruncated = true\n }\n }\n } catch {\n // sendMessage failed — next flush will retry\n } finally {\n this.firstFlushPending = false\n }\n } else {\n try {\n const result = await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, html, {\n parse_mode: 'HTML',\n }),\n { type: 'text', key: this.sessionId },\n )\n // Only mark as sent if the edit was actually executed (not dropped by dedup/rate-limit)\n if (result !== undefined) {\n if (!truncated) {\n this.lastSentBuffer = snapshot\n this.displayTruncated = false\n } else {\n this.displayTruncated = true\n }\n }\n } catch {\n // Don't reset messageId — transient errors (rate limit, network) would cause\n // the next flush to sendMessage the full buffer as a NEW message, creating duplicates.\n // If the message was truly deleted, finalize() handles the fallback.\n }\n }\n }\n\n async finalize(): Promise<number | undefined> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = undefined\n }\n\n await this.flushPromise\n\n if (!this.buffer) return this.messageId\n\n // Skip if buffer was already fully sent by flush() and nothing new was appended.\n // Do NOT skip if flush() truncated the display — finalize must send the full content.\n if (this.messageId && this.buffer === this.lastSentBuffer && !this.displayTruncated) {\n return this.messageId\n }\n\n // Try sending full buffer as a single message (most common case).\n // Only split if HTML exceeds Telegram's 4096 char limit.\n const fullHtml = markdownToTelegramHtml(this.buffer)\n if (fullHtml.length <= 4096) {\n // Single enqueue — no ordering issue possible\n try {\n if (this.messageId) {\n await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, fullHtml, {\n parse_mode: 'HTML',\n }),\n { type: 'other' },\n )\n } else {\n const msg = await this.sendQueue.enqueue(\n () => this.bot.api.sendMessage(this.chatId, fullHtml, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n }),\n { type: 'other' },\n )\n if (msg) this.messageId = msg.message_id\n }\n return this.messageId\n } catch {\n // HTML send failed — fall through to split/fallback below\n }\n }\n\n // HTML > 4096 or single send failed — split markdown, convert each chunk separately.\n // This prevents breaking HTML tags (e.g. <pre><code>) at split boundaries.\n //\n // CRITICAL: Enqueue ALL chunks in a tight synchronous loop (no await between\n // enqueues). This prevents concurrent event handlers (usage, session_end) from\n // slipping their messages between our chunks in the sendQueue.\n const mdChunks = splitMessage(this.buffer)\n const chunkPromises: Promise<void>[] = []\n\n for (let i = 0; i < mdChunks.length; i++) {\n const html = markdownToTelegramHtml(mdChunks[i])\n const isEdit = i === 0 && !!this.messageId\n const chunkMd = mdChunks[i]\n\n const fn = isEdit\n ? () => this.bot.api.editMessageText(this.chatId, this.messageId!, html, { parse_mode: 'HTML' }) as Promise<unknown>\n : () => this.bot.api.sendMessage(this.chatId, html, {\n message_thread_id: this.threadId,\n parse_mode: 'HTML',\n disable_notification: true,\n })\n const promise = this.sendQueue.enqueue(fn, { type: 'other' })\n .then((result) => {\n if (!isEdit && result && typeof result === 'object' && 'message_id' in (result as Record<string, unknown>)) {\n this.messageId = (result as { message_id: number }).message_id\n }\n })\n .catch(() => {\n // HTML failed — enqueue plain text fallback (goes after all chunks, acceptable)\n const fallbackFn = isEdit\n ? () => this.bot.api.editMessageText(this.chatId, this.messageId!, chunkMd.slice(0, 4096)) as Promise<unknown>\n : () => this.bot.api.sendMessage(this.chatId, chunkMd.slice(0, 4096), {\n message_thread_id: this.threadId,\n disable_notification: true,\n })\n return this.sendQueue.enqueue(fallbackFn, { type: 'other' })\n .then((result) => {\n if (!isEdit && result && typeof result === 'object' && 'message_id' in (result as Record<string, unknown>)) {\n this.messageId = (result as { message_id: number }).message_id\n }\n })\n .catch(() => {})\n })\n\n chunkPromises.push(promise)\n }\n\n // All chunks are now in the queue — any items enqueued by concurrent handlers\n // (usage, session_end) will go AFTER our chunks. Safe to await.\n await Promise.all(chunkPromises)\n\n return this.messageId\n }\n\n getMessageId(): number | undefined {\n return this.messageId\n }\n\n async stripPattern(pattern: RegExp): Promise<void> {\n if (!this.messageId || !this.buffer) return\n\n const stripped = this.buffer.replace(pattern, '').trim()\n if (stripped === this.buffer.trim()) return\n\n this.buffer = stripped\n this.lastSentBuffer = stripped\n\n const html = markdownToTelegramHtml(stripped)\n if (!html) return\n\n try {\n await this.sendQueue.enqueue(\n () => this.bot.api.editMessageText(this.chatId, this.messageId!, html, {\n parse_mode: 'HTML',\n }),\n { type: 'other' },\n )\n } catch {\n // Best effort — non-critical edit\n }\n }\n}\n","import type { Bot } from \"grammy\";\nimport { MessageDraft } from \"./streaming.js\";\nimport type { TelegramSendQueue } from \"./send-queue.js\";\nimport {\n detectAction,\n storeAction,\n buildActionKeyboard,\n} from \"./action-detect.js\";\n\nexport class DraftManager {\n private drafts: Map<string, MessageDraft> = new Map();\n private textBuffers: Map<string, string> = new Map();\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private sendQueue: TelegramSendQueue,\n ) {}\n\n getOrCreate(sessionId: string, threadId: number): MessageDraft {\n let draft = this.drafts.get(sessionId);\n if (!draft) {\n draft = new MessageDraft(\n this.bot,\n this.chatId,\n threadId,\n this.sendQueue,\n sessionId,\n );\n this.drafts.set(sessionId, draft);\n }\n return draft;\n }\n\n hasDraft(sessionId: string): boolean {\n return this.drafts.has(sessionId);\n }\n\n getDraft(sessionId: string): MessageDraft | undefined {\n return this.drafts.get(sessionId);\n }\n\n appendText(sessionId: string, text: string): void {\n this.textBuffers.set(\n sessionId,\n (this.textBuffers.get(sessionId) ?? \"\") + text,\n );\n }\n\n /**\n * Finalize the current draft and return the message ID.\n * Optionally detects actions in assistant responses.\n */\n async finalize(\n sessionId: string,\n assistantSessionId?: string,\n ): Promise<void> {\n const draft = this.drafts.get(sessionId);\n if (!draft) return;\n\n // Delete BEFORE awaiting to prevent concurrent finalizeDraft() calls\n // from double-finalizing the same draft\n this.drafts.delete(sessionId);\n const finalMsgId = await draft.finalize();\n\n // Detect actions in assistant responses and attach keyboard\n if (assistantSessionId && sessionId === assistantSessionId) {\n const fullText = this.textBuffers.get(sessionId);\n this.textBuffers.delete(sessionId);\n if (fullText && finalMsgId) {\n const detected = detectAction(fullText);\n if (detected) {\n const actionId = storeAction(detected);\n const keyboard = buildActionKeyboard(actionId, detected);\n try {\n await this.bot.api.editMessageReplyMarkup(\n this.chatId,\n finalMsgId,\n { reply_markup: keyboard },\n );\n } catch {\n // Best effort — keyboard attachment is non-critical\n }\n }\n }\n } else {\n this.textBuffers.delete(sessionId);\n }\n }\n\n cleanup(sessionId: string): void {\n this.drafts.delete(sessionId);\n this.textBuffers.delete(sessionId);\n }\n}\n","import type { Bot } from \"grammy\";\nimport type { TelegramSendQueue } from \"./send-queue.js\";\nimport type { AgentCommand } from \"../../core/types.js\";\nimport type { SessionManager } from \"../../core/session-manager.js\";\nimport type { TelegramPlatformData } from \"../../core/types.js\";\nimport { buildSkillMessages } from \"./commands/index.js\";\nimport { createChildLogger } from \"../../core/log.js\";\n\nconst log = createChildLogger({ module: \"skill-commands\" });\n\nexport class SkillCommandManager {\n private messages: Map<string, number> = new Map(); // sessionId → pinned msgId\n\n constructor(\n private bot: Bot,\n private chatId: number,\n private sendQueue: TelegramSendQueue,\n private sessionManager: SessionManager,\n ) {}\n\n async send(\n sessionId: string,\n threadId: number,\n commands: AgentCommand[],\n ): Promise<void> {\n // Restore skillMsgIds from persisted platform data if not in memory\n if (!this.messages.has(sessionId)) {\n const record = this.sessionManager.getSessionRecord(sessionId);\n const platform = record?.platform as TelegramPlatformData | undefined;\n if (platform?.skillMsgId) {\n this.messages.set(sessionId, platform.skillMsgId);\n }\n }\n\n // Empty commands → remove pinned message\n if (commands.length === 0) {\n await this.cleanup(sessionId);\n return;\n }\n\n const messages = buildSkillMessages(commands);\n const existingMsgId = this.messages.get(sessionId);\n\n if (existingMsgId) {\n try {\n await this.bot.api.editMessageText(\n this.chatId,\n existingMsgId,\n messages[0],\n { parse_mode: \"HTML\" },\n );\n return;\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"\";\n if (msg.includes(\"message is not modified\")) return;\n try {\n await this.bot.api.deleteMessage(this.chatId, existingMsgId);\n } catch { /* already gone */ }\n this.messages.delete(sessionId);\n }\n }\n\n // Send new messages and pin the first one\n try {\n let firstMsgId: number | undefined;\n for (const text of messages) {\n const msg = await this.sendQueue.enqueue(() =>\n this.bot.api.sendMessage(this.chatId, text, {\n message_thread_id: threadId,\n parse_mode: \"HTML\",\n disable_notification: true,\n }),\n );\n if (!firstMsgId) firstMsgId = msg!.message_id;\n }\n\n this.messages.set(sessionId, firstMsgId!);\n\n // Persist skillMsgId so it survives restarts\n const record = this.sessionManager.getSessionRecord(sessionId);\n if (record) {\n await this.sessionManager.patchRecord(sessionId, {\n platform: { ...record.platform, skillMsgId: firstMsgId },\n });\n }\n\n await this.bot.api.pinChatMessage(this.chatId, firstMsgId!, {\n disable_notification: true,\n });\n } catch (err) {\n log.error({ err, sessionId }, \"Failed to send skill commands\");\n }\n }\n\n async cleanup(sessionId: string): Promise<void> {\n const msgId = this.messages.get(sessionId);\n if (!msgId) return;\n\n try {\n await this.bot.api.editMessageText(\n this.chatId,\n msgId,\n \"🛠 <i>Session ended</i>\",\n { parse_mode: \"HTML\" },\n );\n await this.bot.api.unpinChatMessage(this.chatId, msgId);\n } catch { /* message may already be deleted */ }\n\n this.messages.delete(sessionId);\n\n // Clear persisted skillMsgId\n const record = this.sessionManager.getSessionRecord(sessionId);\n if (record) {\n const platform = record.platform;\n if (platform && typeof platform === 'object' && 'topicId' in platform) {\n const { skillMsgId: _removed, ...rest } = platform as unknown as TelegramPlatformData;\n await this.sessionManager.patchRecord(sessionId, { platform: rest });\n }\n }\n }\n}\n"],"mappings":"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","names":["InlineKeyboard","splitMessage","toastText","log","InlineKeyboard","InlineKeyboard","log","InlineKeyboard","InlineKeyboard","InlineKeyboard","InlineKeyboard","InlineKeyboard","keyboard","agentName","getIntegration","integration","InlineKeyboard","log","PENDING_TIMEOUT_MS","botFromCtx","cleanupPending","InlineKeyboard","InlineKeyboard","log","InlineKeyboard","buildMenuKeyboard","InlineKeyboard","log","escapeHtml","InlineKeyboard","InlineKeyboard","log","InlineKeyboard","InlineKeyboard","log","InlineKeyboard","log","log","done","nanoid","InlineKeyboard","nanoid","InlineKeyboard","log","splitMessage","log","log"]}