@openacp/cli 0.2.30 → 0.3.0

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 (31) hide show
  1. package/dist/{chunk-CEAIK37M.js → chunk-7W5SOJPD.js} +2 -2
  2. package/dist/{chunk-WKHCVK5P.js → chunk-C6IFPAWN.js} +581 -102
  3. package/dist/chunk-C6IFPAWN.js.map +1 -0
  4. package/dist/{chunk-7VEHVMVM.js → chunk-CA6FXPLH.js} +9 -8
  5. package/dist/chunk-CA6FXPLH.js.map +1 -0
  6. package/dist/{chunk-2QSUSMBI.js → chunk-LVSQQRCF.js} +2 -2
  7. package/dist/{chunk-ZMNBZAXN.js → chunk-NS2L445T.js} +4 -4
  8. package/dist/chunk-NS2L445T.js.map +1 -0
  9. package/dist/{chunk-GP66XLS6.js → chunk-YXMRR2E3.js} +23 -3
  10. package/dist/chunk-YXMRR2E3.js.map +1 -0
  11. package/dist/cli.js +16 -16
  12. package/dist/{config-3EDZ3IMJ.js → config-2CBRLF3R.js} +2 -2
  13. package/dist/config-editor-UN56HQCW.js +11 -0
  14. package/dist/{daemon-TNQKCKTB.js → daemon-UXC7PB4P.js} +3 -3
  15. package/dist/index.d.ts +5 -0
  16. package/dist/index.js +6 -6
  17. package/dist/{main-CW4GRPSX.js → main-OVEJEUX5.js} +10 -10
  18. package/dist/{setup-JRNMPTIT.js → setup-UKWBLJIT.js} +3 -3
  19. package/package.json +1 -1
  20. package/dist/chunk-7VEHVMVM.js.map +0 -1
  21. package/dist/chunk-GP66XLS6.js.map +0 -1
  22. package/dist/chunk-WKHCVK5P.js.map +0 -1
  23. package/dist/chunk-ZMNBZAXN.js.map +0 -1
  24. package/dist/config-editor-KCD6FFC3.js +0 -11
  25. /package/dist/{chunk-CEAIK37M.js.map → chunk-7W5SOJPD.js.map} +0 -0
  26. /package/dist/{chunk-2QSUSMBI.js.map → chunk-LVSQQRCF.js.map} +0 -0
  27. /package/dist/{config-3EDZ3IMJ.js.map → config-2CBRLF3R.js.map} +0 -0
  28. /package/dist/{config-editor-KCD6FFC3.js.map → config-editor-UN56HQCW.js.map} +0 -0
  29. /package/dist/{daemon-TNQKCKTB.js.map → daemon-UXC7PB4P.js.map} +0 -0
  30. /package/dist/{main-CW4GRPSX.js.map → main-OVEJEUX5.js.map} +0 -0
  31. /package/dist/{setup-JRNMPTIT.js.map → setup-UKWBLJIT.js.map} +0 -0
@@ -523,6 +523,7 @@ var Session = class {
523
523
  adapter;
524
524
  // Set by wireSessionEvents for renaming
525
525
  pendingPermission;
526
+ dangerousMode = false;
526
527
  log;
527
528
  constructor(opts) {
528
529
  this.id = opts.id || nanoid(12);
@@ -593,7 +594,8 @@ var Session = class {
593
594
  async warmup() {
594
595
  this.promptRunning = true;
595
596
  const prevHandler = this.agentInstance.onSessionUpdate;
596
- this.agentInstance.onSessionUpdate = () => {
597
+ this.agentInstance.onSessionUpdate = (event) => {
598
+ if (event.type === "commands_update") prevHandler(event);
597
599
  };
598
600
  try {
599
601
  const start = Date.now();
@@ -666,6 +668,12 @@ var SessionManager = class {
666
668
  }
667
669
  return void 0;
668
670
  }
671
+ getRecordByThread(channelId, threadId) {
672
+ return this.store?.findByPlatform(
673
+ channelId,
674
+ (p) => String(p.topicId) === threadId
675
+ );
676
+ }
669
677
  registerSession(session) {
670
678
  this.sessions.set(session.id, session);
671
679
  }
@@ -707,11 +715,11 @@ var SessionManager = class {
707
715
  const session = this.sessions.get(sessionId);
708
716
  if (session) {
709
717
  await session.cancel();
710
- if (this.store) {
711
- const record = this.store.get(sessionId);
712
- if (record) {
713
- await this.store.save({ ...record, status: "cancelled" });
714
- }
718
+ }
719
+ if (this.store) {
720
+ const record = this.store.get(sessionId);
721
+ if (record && record.status !== "cancelled") {
722
+ await this.store.save({ ...record, status: "cancelled" });
715
723
  }
716
724
  }
717
725
  }
@@ -1044,9 +1052,9 @@ var OpenACPCore = class {
1044
1052
  );
1045
1053
  const adapter = this.adapters.get(message.channelId);
1046
1054
  if (adapter) {
1047
- await adapter.sendMessage("system", {
1055
+ await adapter.sendMessage(message.threadId, {
1048
1056
  type: "error",
1049
- text: `Max concurrent sessions (${config.security.maxConcurrentSessions}) reached. Cancel a session first.`
1057
+ text: `\u26A0\uFE0F Session limit reached (${config.security.maxConcurrentSessions}). Please cancel existing sessions with /cancel before starting new ones.`
1050
1058
  });
1051
1059
  }
1052
1060
  return;
@@ -1086,11 +1094,19 @@ var OpenACPCore = class {
1086
1094
  channelId,
1087
1095
  currentThreadId
1088
1096
  );
1089
- if (!currentSession) return null;
1097
+ if (currentSession) {
1098
+ return this.handleNewSession(
1099
+ channelId,
1100
+ currentSession.agentName,
1101
+ currentSession.workingDirectory
1102
+ );
1103
+ }
1104
+ const record = this.sessionManager.getRecordByThread(channelId, currentThreadId);
1105
+ if (!record || record.status === "cancelled" || record.status === "error") return null;
1090
1106
  return this.handleNewSession(
1091
1107
  channelId,
1092
- currentSession.agentName,
1093
- currentSession.workingDirectory
1108
+ record.agentName,
1109
+ record.workingDir
1094
1110
  );
1095
1111
  }
1096
1112
  // --- Lazy Resume ---
@@ -1609,20 +1625,23 @@ function formatViewerLinks(links, filePath) {
1609
1625
  \u{1F4DD} <a href="${escapeHtml(links.diff)}">View diff${fileName ? ` \u2014 ${escapeHtml(fileName)}` : ""}</a>`;
1610
1626
  return text;
1611
1627
  }
1612
- function formatPlan(plan) {
1613
- const statusIcon = { pending: "\u2B1C", in_progress: "\u{1F504}", completed: "\u2705" };
1614
- const lines = plan.entries.map(
1615
- (e, i) => `${statusIcon[e.status] || "\u2B1C"} ${i + 1}. ${escapeHtml(e.content)}`
1616
- );
1617
- return `<b>Plan:</b>
1618
- ${lines.join("\n")}`;
1628
+ function formatTokens(n) {
1629
+ return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
1630
+ }
1631
+ function progressBar(ratio) {
1632
+ const filled = Math.round(Math.min(ratio, 1) * 10);
1633
+ return "\u2593".repeat(filled) + "\u2591".repeat(10 - filled);
1619
1634
  }
1620
1635
  function formatUsage(usage) {
1621
- const parts = [];
1622
- if (usage.tokensUsed != null) parts.push(`Tokens: ${usage.tokensUsed.toLocaleString()}`);
1623
- if (usage.contextSize != null) parts.push(`Context: ${usage.contextSize.toLocaleString()}`);
1624
- if (usage.cost) parts.push(`Cost: $${usage.cost.amount.toFixed(4)}`);
1625
- return `\u{1F4CA} ${parts.join(" | ")}`;
1636
+ const { tokensUsed, contextSize } = usage;
1637
+ if (tokensUsed == null) return "\u{1F4CA} Usage data unavailable";
1638
+ if (contextSize == null) return `\u{1F4CA} ${formatTokens(tokensUsed)} tokens`;
1639
+ const ratio = tokensUsed / contextSize;
1640
+ const pct = Math.round(ratio * 100);
1641
+ const bar = progressBar(ratio);
1642
+ const emoji = pct >= 85 ? "\u26A0\uFE0F" : "\u{1F4CA}";
1643
+ return `${emoji} ${formatTokens(tokensUsed)} / ${formatTokens(contextSize)} tokens
1644
+ ${bar} ${pct}%`;
1626
1645
  }
1627
1646
  function splitMessage(text, maxLength = 4096) {
1628
1647
  if (text.length <= maxLength) return [text];
@@ -1663,6 +1682,7 @@ var MessageDraft = class {
1663
1682
  flushPromise = Promise.resolve();
1664
1683
  lastSentBuffer = "";
1665
1684
  append(text) {
1685
+ if (!text) return;
1666
1686
  this.buffer += text;
1667
1687
  this.scheduleFlush();
1668
1688
  }
@@ -1709,7 +1729,6 @@ var MessageDraft = class {
1709
1729
  );
1710
1730
  this.lastSentBuffer = this.buffer;
1711
1731
  } catch {
1712
- this.messageId = void 0;
1713
1732
  }
1714
1733
  }
1715
1734
  }
@@ -1813,6 +1832,8 @@ function setupCommands(bot, core, chatId, assistant) {
1813
1832
  bot.command("agents", (ctx) => handleAgents(ctx, core));
1814
1833
  bot.command("help", (ctx) => handleHelp(ctx));
1815
1834
  bot.command("menu", (ctx) => handleMenu(ctx));
1835
+ bot.command("enable_dangerous", (ctx) => handleEnableDangerous(ctx, core));
1836
+ bot.command("disable_dangerous", (ctx) => handleDisableDangerous(ctx, core));
1816
1837
  }
1817
1838
  function buildMenuKeyboard() {
1818
1839
  return new InlineKeyboard().text("\u{1F195} New Session", "m:new").text("\u{1F4AC} New Chat", "m:new_chat").row().text("\u26D4 Cancel", "m:cancel").text("\u{1F4CA} Status", "m:status").row().text("\u{1F916} Agents", "m:agents").text("\u2753 Help", "m:help");
@@ -1898,7 +1919,8 @@ async function handleNew(ctx, core, chatId, assistant) {
1898
1919
  <b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>`,
1899
1920
  {
1900
1921
  message_thread_id: threadId,
1901
- parse_mode: "HTML"
1922
+ parse_mode: "HTML",
1923
+ reply_markup: buildDangerousModeKeyboard(session.id, false)
1902
1924
  }
1903
1925
  );
1904
1926
  session.warmup().catch((err) => log6.error({ err }, "Warm-up error"));
@@ -1952,7 +1974,8 @@ async function handleNewChat(ctx, core, chatId) {
1952
1974
  <b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>`,
1953
1975
  {
1954
1976
  message_thread_id: newThreadId,
1955
- parse_mode: "HTML"
1977
+ parse_mode: "HTML",
1978
+ reply_markup: buildDangerousModeKeyboard(session.id, false)
1956
1979
  }
1957
1980
  );
1958
1981
  session.warmup().catch((err) => log6.error({ err }, "Warm-up error"));
@@ -1981,6 +2004,13 @@ async function handleCancel(ctx, core, assistant) {
1981
2004
  log6.info({ sessionId: session.id }, "Cancel session command");
1982
2005
  await session.cancel();
1983
2006
  await ctx.reply("\u26D4 Session cancelled.", { parse_mode: "HTML" });
2007
+ return;
2008
+ }
2009
+ const record = core.sessionManager.getRecordByThread("telegram", String(threadId));
2010
+ if (record && record.status !== "cancelled" && record.status !== "error") {
2011
+ log6.info({ sessionId: record.sessionId }, "Cancel session command (from store)");
2012
+ await core.sessionManager.cancelSession(record.sessionId);
2013
+ await ctx.reply("\u26D4 Session cancelled.", { parse_mode: "HTML" });
1984
2014
  }
1985
2015
  }
1986
2016
  async function handleStatus(ctx, core) {
@@ -2000,9 +2030,20 @@ async function handleStatus(ctx, core) {
2000
2030
  { parse_mode: "HTML" }
2001
2031
  );
2002
2032
  } else {
2003
- await ctx.reply("No active session in this topic.", {
2004
- parse_mode: "HTML"
2005
- });
2033
+ const record = core.sessionManager.getRecordByThread("telegram", String(threadId));
2034
+ if (record) {
2035
+ await ctx.reply(
2036
+ `<b>Session:</b> ${escapeHtml(record.name || record.sessionId)}
2037
+ <b>Agent:</b> ${escapeHtml(record.agentName)}
2038
+ <b>Status:</b> ${escapeHtml(record.status)} (not loaded)
2039
+ <b>Workspace:</b> <code>${escapeHtml(record.workingDir)}</code>`,
2040
+ { parse_mode: "HTML" }
2041
+ );
2042
+ } else {
2043
+ await ctx.reply("No active session in this topic.", {
2044
+ parse_mode: "HTML"
2045
+ });
2046
+ }
2006
2047
  }
2007
2048
  } else {
2008
2049
  const sessions = core.sessionManager.listSessions("telegram");
@@ -2047,6 +2088,81 @@ Or just chat in the \u{1F916} Assistant topic for help!`,
2047
2088
  { parse_mode: "HTML" }
2048
2089
  );
2049
2090
  }
2091
+ function buildDangerousModeKeyboard(sessionId, enabled) {
2092
+ return new InlineKeyboard().text(
2093
+ enabled ? "\u{1F510} Disable Dangerous Mode" : "\u2620\uFE0F Enable Dangerous Mode",
2094
+ `d:${sessionId}`
2095
+ );
2096
+ }
2097
+ function setupDangerousModeCallbacks(bot, core) {
2098
+ bot.callbackQuery(/^d:/, async (ctx) => {
2099
+ const sessionId = ctx.callbackQuery.data.slice(2);
2100
+ const session = core.sessionManager.getSession(sessionId);
2101
+ if (!session) {
2102
+ try {
2103
+ await ctx.answerCallbackQuery({ text: "\u26A0\uFE0F Session not found or already ended." });
2104
+ } catch {
2105
+ }
2106
+ return;
2107
+ }
2108
+ session.dangerousMode = !session.dangerousMode;
2109
+ log6.info({ sessionId, dangerousMode: session.dangerousMode }, "Dangerous mode toggled via button");
2110
+ const toastText = session.dangerousMode ? "\u2620\uFE0F Dangerous mode enabled \u2014 permissions auto-approved" : "\u{1F510} Dangerous mode disabled \u2014 permissions shown normally";
2111
+ try {
2112
+ await ctx.answerCallbackQuery({ text: toastText });
2113
+ } catch {
2114
+ }
2115
+ try {
2116
+ await ctx.editMessageReplyMarkup({
2117
+ reply_markup: buildDangerousModeKeyboard(sessionId, session.dangerousMode)
2118
+ });
2119
+ } catch {
2120
+ }
2121
+ });
2122
+ }
2123
+ async function handleEnableDangerous(ctx, core) {
2124
+ const threadId = ctx.message?.message_thread_id;
2125
+ if (!threadId) {
2126
+ await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", { parse_mode: "HTML" });
2127
+ return;
2128
+ }
2129
+ const session = core.sessionManager.getSessionByThread("telegram", String(threadId));
2130
+ if (!session) {
2131
+ await ctx.reply("\u26A0\uFE0F No active session in this topic.", { parse_mode: "HTML" });
2132
+ return;
2133
+ }
2134
+ if (session.dangerousMode) {
2135
+ await ctx.reply("\u2620\uFE0F Dangerous mode is already enabled.", { parse_mode: "HTML" });
2136
+ return;
2137
+ }
2138
+ session.dangerousMode = true;
2139
+ await ctx.reply(
2140
+ `\u26A0\uFE0F <b>Dangerous mode enabled</b>
2141
+
2142
+ All permission requests will be auto-approved. Claude can run arbitrary commands without asking.
2143
+
2144
+ Use /disable_dangerous to restore normal behaviour.`,
2145
+ { parse_mode: "HTML" }
2146
+ );
2147
+ }
2148
+ async function handleDisableDangerous(ctx, core) {
2149
+ const threadId = ctx.message?.message_thread_id;
2150
+ if (!threadId) {
2151
+ await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", { parse_mode: "HTML" });
2152
+ return;
2153
+ }
2154
+ const session = core.sessionManager.getSessionByThread("telegram", String(threadId));
2155
+ if (!session) {
2156
+ await ctx.reply("\u26A0\uFE0F No active session in this topic.", { parse_mode: "HTML" });
2157
+ return;
2158
+ }
2159
+ if (!session.dangerousMode) {
2160
+ await ctx.reply("\u{1F510} Dangerous mode is already disabled.", { parse_mode: "HTML" });
2161
+ return;
2162
+ }
2163
+ session.dangerousMode = false;
2164
+ await ctx.reply("\u{1F510} <b>Dangerous mode disabled</b>\n\nPermission requests will be shown normally.", { parse_mode: "HTML" });
2165
+ }
2050
2166
  function botFromCtx(ctx) {
2051
2167
  return { api: ctx.api };
2052
2168
  }
@@ -2128,7 +2244,9 @@ var STATIC_COMMANDS = [
2128
2244
  { command: "status", description: "Show status" },
2129
2245
  { command: "agents", description: "List available agents" },
2130
2246
  { command: "help", description: "Help" },
2131
- { command: "menu", description: "Show menu" }
2247
+ { command: "menu", description: "Show menu" },
2248
+ { command: "enable_dangerous", description: "Auto-approve all permission requests (session only)" },
2249
+ { command: "disable_dangerous", description: "Restore normal permission prompts (session only)" }
2132
2250
  ];
2133
2251
 
2134
2252
  // src/adapters/telegram/permissions.ts
@@ -2213,8 +2331,10 @@ ${escapeHtml(request.description)}`,
2213
2331
  };
2214
2332
 
2215
2333
  // src/adapters/telegram/assistant.ts
2334
+ var log8 = createChildLogger({ module: "telegram-assistant" });
2216
2335
  async function spawnAssistant(core, adapter, assistantTopicId) {
2217
2336
  const config = core.configManager.get();
2337
+ log8.info({ agent: config.defaultAgent }, "Creating assistant session...");
2218
2338
  const session = await core.sessionManager.createSession(
2219
2339
  "telegram",
2220
2340
  config.defaultAgent,
@@ -2222,10 +2342,16 @@ async function spawnAssistant(core, adapter, assistantTopicId) {
2222
2342
  core.agentManager
2223
2343
  );
2224
2344
  session.threadId = String(assistantTopicId);
2225
- const systemPrompt = buildAssistantSystemPrompt(config);
2226
- await session.enqueuePrompt(systemPrompt);
2345
+ session.name = "Assistant";
2346
+ log8.info({ sessionId: session.id }, "Assistant agent spawned");
2227
2347
  core.wireSessionEvents(session, adapter);
2228
- return session;
2348
+ const systemPrompt = buildAssistantSystemPrompt(config);
2349
+ const ready = session.enqueuePrompt(systemPrompt).then(() => {
2350
+ log8.info({ sessionId: session.id }, "Assistant system prompt completed");
2351
+ }).catch((err) => {
2352
+ log8.warn({ err }, "Assistant system prompt failed");
2353
+ });
2354
+ return { session, ready };
2229
2355
  }
2230
2356
  function buildAssistantSystemPrompt(config) {
2231
2357
  const agentNames = Object.keys(config.agents).join(", ");
@@ -2260,6 +2386,279 @@ function redirectToAssistant(chatId, assistantTopicId) {
2260
2386
  return `\u{1F4AC} Please use the <a href="${link}">\u{1F916} Assistant</a> topic to chat with OpenACP.`;
2261
2387
  }
2262
2388
 
2389
+ // src/adapters/telegram/activity.ts
2390
+ var log9 = createChildLogger({ module: "telegram:activity" });
2391
+ var THINKING_REFRESH_MS = 15e3;
2392
+ var THINKING_MAX_MS = 3 * 60 * 1e3;
2393
+ var ThinkingIndicator = class {
2394
+ constructor(api, chatId, threadId, sendQueue) {
2395
+ this.api = api;
2396
+ this.chatId = chatId;
2397
+ this.threadId = threadId;
2398
+ this.sendQueue = sendQueue;
2399
+ }
2400
+ msgId;
2401
+ sending = false;
2402
+ dismissed = false;
2403
+ refreshTimer;
2404
+ showTime = 0;
2405
+ async show() {
2406
+ if (this.msgId || this.sending || this.dismissed) return;
2407
+ this.sending = true;
2408
+ this.showTime = Date.now();
2409
+ try {
2410
+ const result = await this.sendQueue.enqueue(
2411
+ () => this.api.sendMessage(this.chatId, "\u{1F4AD} <i>Thinking...</i>", {
2412
+ message_thread_id: this.threadId,
2413
+ parse_mode: "HTML",
2414
+ disable_notification: true
2415
+ })
2416
+ );
2417
+ if (result && !this.dismissed) {
2418
+ this.msgId = result.message_id;
2419
+ this.startRefreshTimer();
2420
+ }
2421
+ } catch (err) {
2422
+ log9.warn({ err }, "ThinkingIndicator.show() failed");
2423
+ } finally {
2424
+ this.sending = false;
2425
+ }
2426
+ }
2427
+ /** Clear state — stops refresh timer, no Telegram API call */
2428
+ dismiss() {
2429
+ this.dismissed = true;
2430
+ this.msgId = void 0;
2431
+ this.stopRefreshTimer();
2432
+ }
2433
+ /** Reset for a new prompt cycle */
2434
+ reset() {
2435
+ this.dismissed = false;
2436
+ }
2437
+ startRefreshTimer() {
2438
+ this.stopRefreshTimer();
2439
+ this.refreshTimer = setInterval(() => {
2440
+ if (this.dismissed || !this.msgId || Date.now() - this.showTime >= THINKING_MAX_MS) {
2441
+ this.stopRefreshTimer();
2442
+ return;
2443
+ }
2444
+ const elapsed = Math.round((Date.now() - this.showTime) / 1e3);
2445
+ this.sendQueue.enqueue(() => {
2446
+ if (this.dismissed) return Promise.resolve(void 0);
2447
+ return this.api.sendMessage(this.chatId, `\u{1F4AD} <i>Still thinking... (${elapsed}s)</i>`, {
2448
+ message_thread_id: this.threadId,
2449
+ parse_mode: "HTML",
2450
+ disable_notification: true
2451
+ });
2452
+ }).then((result) => {
2453
+ if (result && !this.dismissed) {
2454
+ this.msgId = result.message_id;
2455
+ }
2456
+ }).catch(() => {
2457
+ });
2458
+ }, THINKING_REFRESH_MS);
2459
+ }
2460
+ stopRefreshTimer() {
2461
+ if (this.refreshTimer) {
2462
+ clearInterval(this.refreshTimer);
2463
+ this.refreshTimer = void 0;
2464
+ }
2465
+ }
2466
+ };
2467
+ var UsageMessage = class {
2468
+ constructor(api, chatId, threadId, sendQueue) {
2469
+ this.api = api;
2470
+ this.chatId = chatId;
2471
+ this.threadId = threadId;
2472
+ this.sendQueue = sendQueue;
2473
+ }
2474
+ msgId;
2475
+ async send(usage) {
2476
+ const text = formatUsage(usage);
2477
+ try {
2478
+ if (this.msgId) {
2479
+ await this.sendQueue.enqueue(
2480
+ () => this.api.editMessageText(this.chatId, this.msgId, text, {
2481
+ parse_mode: "HTML"
2482
+ })
2483
+ );
2484
+ } else {
2485
+ const result = await this.sendQueue.enqueue(
2486
+ () => this.api.sendMessage(this.chatId, text, {
2487
+ message_thread_id: this.threadId,
2488
+ parse_mode: "HTML",
2489
+ disable_notification: true
2490
+ })
2491
+ );
2492
+ if (result) this.msgId = result.message_id;
2493
+ }
2494
+ } catch (err) {
2495
+ log9.warn({ err }, "UsageMessage.send() failed");
2496
+ }
2497
+ }
2498
+ async delete() {
2499
+ if (!this.msgId) return;
2500
+ const id = this.msgId;
2501
+ this.msgId = void 0;
2502
+ try {
2503
+ await this.sendQueue.enqueue(() => this.api.deleteMessage(this.chatId, id));
2504
+ } catch (err) {
2505
+ log9.warn({ err }, "UsageMessage.delete() failed");
2506
+ }
2507
+ }
2508
+ };
2509
+ function formatPlanCard(entries) {
2510
+ const statusIcon = {
2511
+ completed: "\u2705",
2512
+ in_progress: "\u{1F504}",
2513
+ pending: "\u2B1C",
2514
+ failed: "\u274C"
2515
+ };
2516
+ const total = entries.length;
2517
+ const done = entries.filter((e) => e.status === "completed").length;
2518
+ const ratio = total > 0 ? done / total : 0;
2519
+ const filled = Math.round(ratio * 10);
2520
+ const bar = "\u2593".repeat(filled) + "\u2591".repeat(10 - filled);
2521
+ const pct = Math.round(ratio * 100);
2522
+ const header = `\u{1F4CB} <b>Plan</b>
2523
+ ${bar} ${pct}% \xB7 ${done}/${total}`;
2524
+ const lines = entries.map((e, i) => {
2525
+ const icon = statusIcon[e.status] ?? "\u2B1C";
2526
+ return `${icon} ${i + 1}. ${e.content}`;
2527
+ });
2528
+ return [header, ...lines].join("\n");
2529
+ }
2530
+ var PlanCard = class {
2531
+ constructor(api, chatId, threadId, sendQueue) {
2532
+ this.api = api;
2533
+ this.chatId = chatId;
2534
+ this.threadId = threadId;
2535
+ this.sendQueue = sendQueue;
2536
+ }
2537
+ msgId;
2538
+ flushPromise = Promise.resolve();
2539
+ latestEntries;
2540
+ flushTimer;
2541
+ update(entries) {
2542
+ this.latestEntries = entries;
2543
+ if (this.flushTimer) clearTimeout(this.flushTimer);
2544
+ this.flushTimer = setTimeout(() => {
2545
+ this.flushTimer = void 0;
2546
+ this.flushPromise = this.flushPromise.then(() => this._flush()).catch(() => {
2547
+ });
2548
+ }, 3500);
2549
+ }
2550
+ async finalize() {
2551
+ if (!this.latestEntries) return;
2552
+ if (this.flushTimer) {
2553
+ clearTimeout(this.flushTimer);
2554
+ this.flushTimer = void 0;
2555
+ }
2556
+ await this.flushPromise;
2557
+ this.flushPromise = this.flushPromise.then(() => this._flush()).catch(() => {
2558
+ });
2559
+ await this.flushPromise;
2560
+ }
2561
+ destroy() {
2562
+ if (this.flushTimer) {
2563
+ clearTimeout(this.flushTimer);
2564
+ this.flushTimer = void 0;
2565
+ }
2566
+ }
2567
+ async _flush() {
2568
+ if (!this.latestEntries) return;
2569
+ const text = formatPlanCard(this.latestEntries);
2570
+ try {
2571
+ if (this.msgId) {
2572
+ await this.sendQueue.enqueue(
2573
+ () => this.api.editMessageText(this.chatId, this.msgId, text, {
2574
+ parse_mode: "HTML"
2575
+ })
2576
+ );
2577
+ } else {
2578
+ const result = await this.sendQueue.enqueue(
2579
+ () => this.api.sendMessage(this.chatId, text, {
2580
+ message_thread_id: this.threadId,
2581
+ parse_mode: "HTML",
2582
+ disable_notification: true
2583
+ })
2584
+ );
2585
+ if (result) this.msgId = result.message_id;
2586
+ }
2587
+ } catch (err) {
2588
+ log9.warn({ err }, "PlanCard flush failed");
2589
+ }
2590
+ }
2591
+ };
2592
+ var ActivityTracker = class {
2593
+ constructor(api, chatId, threadId, sendQueue) {
2594
+ this.api = api;
2595
+ this.chatId = chatId;
2596
+ this.threadId = threadId;
2597
+ this.sendQueue = sendQueue;
2598
+ this.thinking = new ThinkingIndicator(api, chatId, threadId, sendQueue);
2599
+ this.planCard = new PlanCard(api, chatId, threadId, sendQueue);
2600
+ this.usage = new UsageMessage(api, chatId, threadId, sendQueue);
2601
+ }
2602
+ isFirstEvent = true;
2603
+ hasPlanCard = false;
2604
+ thinking;
2605
+ planCard;
2606
+ usage;
2607
+ async onNewPrompt() {
2608
+ this.isFirstEvent = true;
2609
+ this.hasPlanCard = false;
2610
+ this.thinking.dismiss();
2611
+ this.thinking.reset();
2612
+ }
2613
+ async onThought() {
2614
+ await this._firstEventGuard();
2615
+ await this.thinking.show();
2616
+ }
2617
+ async onPlan(entries) {
2618
+ await this._firstEventGuard();
2619
+ this.thinking.dismiss();
2620
+ this.hasPlanCard = true;
2621
+ this.planCard.update(entries);
2622
+ }
2623
+ async onToolCall() {
2624
+ await this._firstEventGuard();
2625
+ this.thinking.dismiss();
2626
+ this.thinking.reset();
2627
+ }
2628
+ async onTextStart() {
2629
+ await this._firstEventGuard();
2630
+ this.thinking.dismiss();
2631
+ }
2632
+ async sendUsage(data) {
2633
+ await this.usage.send(data);
2634
+ }
2635
+ async onComplete() {
2636
+ if (this.hasPlanCard) {
2637
+ await this.planCard.finalize();
2638
+ } else {
2639
+ try {
2640
+ await this.sendQueue.enqueue(
2641
+ () => this.api.sendMessage(this.chatId, "\u2705 <b>Done</b>", {
2642
+ message_thread_id: this.threadId,
2643
+ parse_mode: "HTML",
2644
+ disable_notification: true
2645
+ })
2646
+ );
2647
+ } catch (err) {
2648
+ log9.warn({ err }, "ActivityTracker.onComplete() Done send failed");
2649
+ }
2650
+ }
2651
+ }
2652
+ destroy() {
2653
+ this.planCard.destroy();
2654
+ }
2655
+ async _firstEventGuard() {
2656
+ if (!this.isFirstEvent) return;
2657
+ this.isFirstEvent = false;
2658
+ await this.usage.delete();
2659
+ }
2660
+ };
2661
+
2263
2662
  // src/adapters/telegram/send-queue.ts
2264
2663
  var TelegramSendQueue = class {
2265
2664
  items = [];
@@ -2472,7 +2871,7 @@ function setupActionCallbacks(bot, core, chatId, getAssistantSessionId) {
2472
2871
  }
2473
2872
 
2474
2873
  // src/adapters/telegram/adapter.ts
2475
- var log8 = createChildLogger({ module: "telegram" });
2874
+ var log10 = createChildLogger({ module: "telegram" });
2476
2875
  function patchedFetch(input, init) {
2477
2876
  if (init?.signal && !(init.signal instanceof AbortSignal)) {
2478
2877
  const nativeController = new AbortController();
@@ -2495,11 +2894,26 @@ var TelegramAdapter = class extends ChannelAdapter {
2495
2894
  // sessionId → (toolCallId → state)
2496
2895
  permissionHandler;
2497
2896
  assistantSession = null;
2897
+ assistantInitializing = false;
2498
2898
  notificationTopicId;
2499
2899
  assistantTopicId;
2500
2900
  skillMessages = /* @__PURE__ */ new Map();
2501
2901
  // sessionId → pinned messageId
2502
2902
  sendQueue = new TelegramSendQueue(3e3);
2903
+ sessionTrackers = /* @__PURE__ */ new Map();
2904
+ getOrCreateTracker(sessionId, threadId) {
2905
+ let tracker = this.sessionTrackers.get(sessionId);
2906
+ if (!tracker) {
2907
+ tracker = new ActivityTracker(
2908
+ this.bot.api,
2909
+ this.telegramConfig.chatId,
2910
+ threadId,
2911
+ this.sendQueue
2912
+ );
2913
+ this.sessionTrackers.set(sessionId, tracker);
2914
+ }
2915
+ return tracker;
2916
+ }
2503
2917
  constructor(core, config) {
2504
2918
  super(core, config);
2505
2919
  this.telegramConfig = config;
@@ -2508,7 +2922,7 @@ var TelegramAdapter = class extends ChannelAdapter {
2508
2922
  this.bot = new Bot(this.telegramConfig.botToken, { client: { fetch: patchedFetch } });
2509
2923
  this.bot.catch((err) => {
2510
2924
  const rootCause = err.error instanceof Error ? err.error : err;
2511
- log8.error({ err: rootCause }, "Telegram bot error");
2925
+ log10.error({ err: rootCause }, "Telegram bot error");
2512
2926
  });
2513
2927
  this.bot.api.config.use(async (prev, method, payload, signal) => {
2514
2928
  const maxRetries = 3;
@@ -2522,7 +2936,7 @@ var TelegramAdapter = class extends ChannelAdapter {
2522
2936
  if (rateLimitedMethods.includes(method)) {
2523
2937
  this.sendQueue.onRateLimited();
2524
2938
  }
2525
- log8.warn(
2939
+ log10.warn(
2526
2940
  { method, retryAfter, attempt: attempt + 1 },
2527
2941
  "Rate limited by Telegram, retrying"
2528
2942
  );
@@ -2567,6 +2981,7 @@ var TelegramAdapter = class extends ChannelAdapter {
2567
2981
  (notification) => this.sendNotification(notification)
2568
2982
  );
2569
2983
  setupSkillCallbacks(this.bot, this.core);
2984
+ setupDangerousModeCallbacks(this.bot, this.core);
2570
2985
  setupActionCallbacks(
2571
2986
  this.bot,
2572
2987
  this.core,
@@ -2591,26 +3006,15 @@ var TelegramAdapter = class extends ChannelAdapter {
2591
3006
  this.setupRoutes();
2592
3007
  this.bot.start({
2593
3008
  allowed_updates: ["message", "callback_query"],
2594
- onStart: () => log8.info(
3009
+ onStart: () => log10.info(
2595
3010
  { chatId: this.telegramConfig.chatId },
2596
3011
  "Telegram bot started"
2597
3012
  )
2598
3013
  });
2599
- try {
2600
- this.assistantSession = await spawnAssistant(
2601
- this.core,
2602
- this,
2603
- this.assistantTopicId
2604
- );
2605
- } catch (err) {
2606
- log8.error({ err }, "Failed to spawn assistant");
2607
- }
2608
3014
  try {
2609
3015
  const config = this.core.configManager.get();
2610
3016
  const agents = this.core.agentManager.getAvailableAgents();
2611
- const agentList = agents.map(
2612
- (a) => `${escapeHtml(a.name)}${a.name === config.defaultAgent ? " (default)" : ""}`
2613
- ).join(", ");
3017
+ const agentList = agents.map((a) => `${escapeHtml(a.name)}${a.name === config.defaultAgent ? " (default)" : ""}`).join(", ");
2614
3018
  const workspace = escapeHtml(config.workspace.baseDir);
2615
3019
  const welcomeText = `\u{1F44B} <b>OpenACP Assistant</b> is online.
2616
3020
 
@@ -2624,7 +3028,32 @@ Workspace: <code>${workspace}</code>
2624
3028
  reply_markup: buildMenuKeyboard()
2625
3029
  });
2626
3030
  } catch (err) {
2627
- log8.warn({ err }, "Failed to send welcome message");
3031
+ log10.warn({ err }, "Failed to send welcome message");
3032
+ }
3033
+ try {
3034
+ log10.info("Spawning assistant session...");
3035
+ const { session, ready } = await spawnAssistant(
3036
+ this.core,
3037
+ this,
3038
+ this.assistantTopicId
3039
+ );
3040
+ this.assistantSession = session;
3041
+ this.assistantInitializing = true;
3042
+ log10.info({ sessionId: session.id }, "Assistant session ready, system prompt running in background");
3043
+ ready.then(() => {
3044
+ this.assistantInitializing = false;
3045
+ log10.info({ sessionId: session.id }, "Assistant ready for user messages");
3046
+ });
3047
+ } catch (err) {
3048
+ log10.error({ err }, "Failed to spawn assistant");
3049
+ this.bot.api.sendMessage(
3050
+ this.telegramConfig.chatId,
3051
+ `\u26A0\uFE0F <b>Failed to start assistant session.</b>
3052
+
3053
+ <code>${err instanceof Error ? err.message : String(err)}</code>`,
3054
+ { message_thread_id: this.assistantTopicId, parse_mode: "HTML" }
3055
+ ).catch(() => {
3056
+ });
2628
3057
  }
2629
3058
  }
2630
3059
  async stop() {
@@ -2632,7 +3061,7 @@ Workspace: <code>${workspace}</code>
2632
3061
  await this.assistantSession.destroy();
2633
3062
  }
2634
3063
  await this.bot.stop();
2635
- log8.info("Telegram bot stopped");
3064
+ log10.info("Telegram bot stopped");
2636
3065
  }
2637
3066
  setupRoutes() {
2638
3067
  this.bot.on("message:text", async (ctx) => {
@@ -2647,16 +3076,24 @@ Workspace: <code>${workspace}</code>
2647
3076
  }
2648
3077
  if (threadId === this.notificationTopicId) return;
2649
3078
  if (threadId === this.assistantTopicId) {
3079
+ if (!this.assistantSession) {
3080
+ await ctx.reply("\u26A0\uFE0F Assistant is not available yet. Please try again shortly.", { parse_mode: "HTML" });
3081
+ return;
3082
+ }
2650
3083
  await this.finalizeDraft(this.assistantSession.id);
2651
3084
  ctx.replyWithChatAction("typing").catch(() => {
2652
3085
  });
2653
3086
  handleAssistantMessage(this.assistantSession, ctx.message.text).catch(
2654
- (err) => log8.error({ err }, "Assistant error")
3087
+ (err) => log10.error({ err }, "Assistant error")
2655
3088
  );
2656
3089
  return;
2657
3090
  }
2658
3091
  const sessionId = this.core.sessionManager.getSessionByThread("telegram", String(threadId))?.id;
2659
3092
  if (sessionId) await this.finalizeDraft(sessionId);
3093
+ if (sessionId) {
3094
+ const tracker = this.sessionTrackers.get(sessionId);
3095
+ if (tracker) await tracker.onNewPrompt();
3096
+ }
2660
3097
  ctx.replyWithChatAction("typing").catch(() => {
2661
3098
  });
2662
3099
  this.core.handleMessage({
@@ -2664,11 +3101,12 @@ Workspace: <code>${workspace}</code>
2664
3101
  threadId: String(threadId),
2665
3102
  userId: String(ctx.from.id),
2666
3103
  text: ctx.message.text
2667
- }).catch((err) => log8.error({ err }, "handleMessage error"));
3104
+ }).catch((err) => log10.error({ err }, "handleMessage error"));
2668
3105
  });
2669
3106
  }
2670
3107
  // --- ChannelAdapter implementations ---
2671
3108
  async sendMessage(sessionId, content) {
3109
+ if (this.assistantInitializing && sessionId === this.assistantSession?.id) return;
2672
3110
  const session = this.core.sessionManager.getSession(
2673
3111
  sessionId
2674
3112
  );
@@ -2676,11 +3114,15 @@ Workspace: <code>${workspace}</code>
2676
3114
  const threadId = Number(session.threadId);
2677
3115
  switch (content.type) {
2678
3116
  case "thought": {
3117
+ const tracker = this.getOrCreateTracker(sessionId, threadId);
3118
+ await tracker.onThought();
2679
3119
  break;
2680
3120
  }
2681
3121
  case "text": {
2682
3122
  let draft = this.sessionDrafts.get(sessionId);
2683
3123
  if (!draft) {
3124
+ const tracker = this.getOrCreateTracker(sessionId, threadId);
3125
+ await tracker.onTextStart();
2684
3126
  draft = new MessageDraft(
2685
3127
  this.bot,
2686
3128
  this.telegramConfig.chatId,
@@ -2698,6 +3140,8 @@ Workspace: <code>${workspace}</code>
2698
3140
  break;
2699
3141
  }
2700
3142
  case "tool_call": {
3143
+ const tracker = this.getOrCreateTracker(sessionId, threadId);
3144
+ await tracker.onToolCall();
2701
3145
  await this.finalizeDraft(sessionId);
2702
3146
  const meta = content.metadata;
2703
3147
  if (!this.toolCallMessages.has(sessionId)) {
@@ -2737,7 +3181,7 @@ Workspace: <code>${workspace}</code>
2737
3181
  if (toolState) {
2738
3182
  if (meta.viewerLinks) {
2739
3183
  toolState.viewerLinks = meta.viewerLinks;
2740
- log8.debug({ toolId: meta.id, viewerLinks: meta.viewerLinks }, "Accumulated viewerLinks");
3184
+ log10.debug({ toolId: meta.id, viewerLinks: meta.viewerLinks }, "Accumulated viewerLinks");
2741
3185
  }
2742
3186
  const viewerFilePath = content.metadata?.viewerFilePath;
2743
3187
  if (viewerFilePath) toolState.viewerFilePath = viewerFilePath;
@@ -2746,7 +3190,7 @@ Workspace: <code>${workspace}</code>
2746
3190
  const isTerminal = meta.status === "completed" || meta.status === "failed";
2747
3191
  if (!isTerminal && !meta.viewerLinks) break;
2748
3192
  await toolState.ready;
2749
- log8.debug(
3193
+ log10.debug(
2750
3194
  { toolId: meta.id, status: meta.status, hasViewerLinks: !!toolState.viewerLinks, viewerLinks: toolState.viewerLinks, name: toolState.name, msgId: toolState.msgId },
2751
3195
  "Tool completed, preparing edit"
2752
3196
  );
@@ -2768,7 +3212,7 @@ Workspace: <code>${workspace}</code>
2768
3212
  )
2769
3213
  );
2770
3214
  } catch (err) {
2771
- log8.warn(
3215
+ log10.warn(
2772
3216
  { err, msgId: toolState.msgId, textLen: formattedText.length, hasViewerLinks: !!merged.viewerLinks },
2773
3217
  "Tool update edit failed"
2774
3218
  );
@@ -2777,37 +3221,41 @@ Workspace: <code>${workspace}</code>
2777
3221
  break;
2778
3222
  }
2779
3223
  case "plan": {
2780
- await this.finalizeDraft(sessionId);
2781
- await this.sendQueue.enqueue(
2782
- () => this.bot.api.sendMessage(
2783
- this.telegramConfig.chatId,
2784
- formatPlan(
2785
- content.metadata
2786
- ),
2787
- {
2788
- message_thread_id: threadId,
2789
- parse_mode: "HTML",
2790
- disable_notification: true
2791
- }
2792
- )
3224
+ const meta = content.metadata;
3225
+ const tracker = this.getOrCreateTracker(sessionId, threadId);
3226
+ await tracker.onPlan(
3227
+ meta.entries.map((e) => ({
3228
+ content: e.content,
3229
+ status: e.status,
3230
+ priority: e.priority ?? "medium"
3231
+ }))
2793
3232
  );
2794
3233
  break;
2795
3234
  }
2796
3235
  case "usage": {
3236
+ const meta = content.metadata;
2797
3237
  await this.finalizeDraft(sessionId);
2798
- await this.sendQueue.enqueue(
2799
- () => this.bot.api.sendMessage(
2800
- this.telegramConfig.chatId,
2801
- formatUsage(
2802
- content.metadata
2803
- ),
2804
- {
2805
- message_thread_id: threadId,
3238
+ const tracker = this.getOrCreateTracker(sessionId, threadId);
3239
+ await tracker.sendUsage(meta);
3240
+ if (this.notificationTopicId && sessionId !== this.assistantSession?.id) {
3241
+ const sess = this.core.sessionManager.getSession(sessionId);
3242
+ const sessionName = sess?.name || "Session";
3243
+ const chatIdStr = String(this.telegramConfig.chatId);
3244
+ const numericId = chatIdStr.startsWith("-100") ? chatIdStr.slice(4) : chatIdStr.replace("-", "");
3245
+ const deepLink = `https://t.me/c/${numericId}/${threadId}`;
3246
+ const text = `\u2705 <b>${escapeHtml(sessionName)}</b>
3247
+ Task completed.
3248
+
3249
+ <a href="${deepLink}">\u2192 Go to topic</a>`;
3250
+ this.sendQueue.enqueue(
3251
+ () => this.bot.api.sendMessage(this.telegramConfig.chatId, text, {
3252
+ message_thread_id: this.notificationTopicId,
2806
3253
  parse_mode: "HTML",
2807
- disable_notification: true
2808
- }
2809
- )
2810
- );
3254
+ disable_notification: false
3255
+ })
3256
+ ).catch(() => {
3257
+ });
3258
+ }
2811
3259
  break;
2812
3260
  }
2813
3261
  case "session_end": {
@@ -2815,21 +3263,33 @@ Workspace: <code>${workspace}</code>
2815
3263
  this.sessionDrafts.delete(sessionId);
2816
3264
  this.toolCallMessages.delete(sessionId);
2817
3265
  await this.cleanupSkillCommands(sessionId);
2818
- await this.sendQueue.enqueue(
2819
- () => this.bot.api.sendMessage(
2820
- this.telegramConfig.chatId,
2821
- `\u2705 <b>Done</b>`,
2822
- {
2823
- message_thread_id: threadId,
2824
- parse_mode: "HTML",
2825
- disable_notification: true
2826
- }
2827
- )
2828
- );
3266
+ const tracker = this.sessionTrackers.get(sessionId);
3267
+ if (tracker) {
3268
+ await tracker.onComplete();
3269
+ tracker.destroy();
3270
+ this.sessionTrackers.delete(sessionId);
3271
+ } else {
3272
+ await this.sendQueue.enqueue(
3273
+ () => this.bot.api.sendMessage(
3274
+ this.telegramConfig.chatId,
3275
+ `\u2705 <b>Done</b>`,
3276
+ {
3277
+ message_thread_id: threadId,
3278
+ parse_mode: "HTML",
3279
+ disable_notification: true
3280
+ }
3281
+ )
3282
+ );
3283
+ }
2829
3284
  break;
2830
3285
  }
2831
3286
  case "error": {
2832
3287
  await this.finalizeDraft(sessionId);
3288
+ const tracker = this.sessionTrackers.get(sessionId);
3289
+ if (tracker) {
3290
+ tracker.destroy();
3291
+ this.sessionTrackers.delete(sessionId);
3292
+ }
2833
3293
  await this.sendQueue.enqueue(
2834
3294
  () => this.bot.api.sendMessage(
2835
3295
  this.telegramConfig.chatId,
@@ -2846,17 +3306,27 @@ Workspace: <code>${workspace}</code>
2846
3306
  }
2847
3307
  }
2848
3308
  async sendPermissionRequest(sessionId, request) {
2849
- log8.info({ sessionId, requestId: request.id }, "Permission request sent");
3309
+ log10.info({ sessionId, requestId: request.id }, "Permission request sent");
2850
3310
  const session = this.core.sessionManager.getSession(
2851
3311
  sessionId
2852
3312
  );
2853
3313
  if (!session) return;
3314
+ if (session.dangerousMode) {
3315
+ const allowOption = request.options.find((o) => o.isAllow);
3316
+ if (allowOption && session.pendingPermission?.requestId === request.id) {
3317
+ log10.info({ sessionId, requestId: request.id, optionId: allowOption.id }, "Dangerous mode: auto-approving permission");
3318
+ session.pendingPermission.resolve(allowOption.id);
3319
+ session.pendingPermission = void 0;
3320
+ }
3321
+ return;
3322
+ }
2854
3323
  await this.sendQueue.enqueue(
2855
3324
  () => this.permissionHandler.sendPermissionRequest(session, request)
2856
3325
  );
2857
3326
  }
2858
3327
  async sendNotification(notification) {
2859
- log8.info(
3328
+ if (notification.sessionId === this.assistantSession?.id) return;
3329
+ log10.info(
2860
3330
  { sessionId: notification.sessionId, type: notification.type },
2861
3331
  "Notification sent"
2862
3332
  );
@@ -2870,10 +3340,18 @@ Workspace: <code>${workspace}</code>
2870
3340
  let text = `${emoji[notification.type] || "\u2139\uFE0F"} <b>${escapeHtml(notification.sessionName || "New session")}</b>
2871
3341
  `;
2872
3342
  text += escapeHtml(notification.summary);
2873
- if (notification.deepLink) {
3343
+ const deepLink = notification.deepLink ?? (() => {
3344
+ const session = this.core.sessionManager.getSession(notification.sessionId);
3345
+ const threadId = session?.threadId;
3346
+ if (!threadId) return void 0;
3347
+ const chatIdStr = String(this.telegramConfig.chatId);
3348
+ const numericId = chatIdStr.startsWith("-100") ? chatIdStr.slice(4) : chatIdStr.replace("-", "");
3349
+ return `https://t.me/c/${numericId}/${threadId}`;
3350
+ })();
3351
+ if (deepLink) {
2874
3352
  text += `
2875
3353
 
2876
- <a href="${notification.deepLink}">\u2192 Go to message</a>`;
3354
+ <a href="${deepLink}">\u2192 Go to topic</a>`;
2877
3355
  }
2878
3356
  await this.sendQueue.enqueue(
2879
3357
  () => this.bot.api.sendMessage(this.telegramConfig.chatId, text, {
@@ -2884,7 +3362,7 @@ Workspace: <code>${workspace}</code>
2884
3362
  );
2885
3363
  }
2886
3364
  async createSessionThread(sessionId, name) {
2887
- log8.info({ sessionId, name }, "Session topic created");
3365
+ log10.info({ sessionId, name }, "Session topic created");
2888
3366
  return String(
2889
3367
  await createSessionTopic(this.bot, this.telegramConfig.chatId, name)
2890
3368
  );
@@ -2906,6 +3384,7 @@ Workspace: <code>${workspace}</code>
2906
3384
  );
2907
3385
  }
2908
3386
  async sendSkillCommands(sessionId, commands) {
3387
+ if (sessionId === this.assistantSession?.id) return;
2909
3388
  const session = this.core.sessionManager.getSession(
2910
3389
  sessionId
2911
3390
  );
@@ -2968,7 +3447,7 @@ Workspace: <code>${workspace}</code>
2968
3447
  }
2969
3448
  );
2970
3449
  } catch (err) {
2971
- log8.error({ err, sessionId }, "Failed to send skill commands");
3450
+ log10.error({ err, sessionId }, "Failed to send skill commands");
2972
3451
  }
2973
3452
  await this.updateCommandAutocomplete(session.agentName, commands);
2974
3453
  }
@@ -3004,12 +3483,12 @@ Workspace: <code>${workspace}</code>
3004
3483
  await this.bot.api.setMyCommands(all, {
3005
3484
  scope: { type: "chat", chat_id: this.telegramConfig.chatId }
3006
3485
  });
3007
- log8.info(
3486
+ log10.info(
3008
3487
  { count: all.length, skills: validSkills.length },
3009
3488
  "Updated command autocomplete"
3010
3489
  );
3011
3490
  } catch (err) {
3012
- log8.error(
3491
+ log10.error(
3013
3492
  { err, commands: all },
3014
3493
  "Failed to update command autocomplete"
3015
3494
  );
@@ -3018,8 +3497,8 @@ Workspace: <code>${workspace}</code>
3018
3497
  async finalizeDraft(sessionId) {
3019
3498
  const draft = this.sessionDrafts.get(sessionId);
3020
3499
  if (!draft) return;
3021
- const finalMsgId = await draft.finalize();
3022
3500
  this.sessionDrafts.delete(sessionId);
3501
+ const finalMsgId = await draft.finalize();
3023
3502
  if (sessionId === this.assistantSession?.id) {
3024
3503
  const fullText = this.sessionTextBuffers.get(sessionId);
3025
3504
  this.sessionTextBuffers.delete(sessionId);
@@ -3058,4 +3537,4 @@ export {
3058
3537
  ApiServer,
3059
3538
  TelegramAdapter
3060
3539
  };
3061
- //# sourceMappingURL=chunk-WKHCVK5P.js.map
3540
+ //# sourceMappingURL=chunk-C6IFPAWN.js.map