@openacp/cli 0.2.22 → 0.2.24

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 (44) hide show
  1. package/dist/autostart-YBYXQA77.js +18 -0
  2. package/dist/autostart-YBYXQA77.js.map +1 -0
  3. package/dist/{setup-XQBEZZQB.js → chunk-4BN7NSKB.js} +140 -9
  4. package/dist/chunk-4BN7NSKB.js.map +1 -0
  5. package/dist/chunk-CQMS5U7Z.js +63 -0
  6. package/dist/chunk-CQMS5U7Z.js.map +1 -0
  7. package/dist/{chunk-XOVJLTEC.js → chunk-FGXG3H3F.js} +14 -58
  8. package/dist/chunk-FGXG3H3F.js.map +1 -0
  9. package/dist/{chunk-HTXK4NLG.js → chunk-IX63F4JG.js} +463 -44
  10. package/dist/chunk-IX63F4JG.js.map +1 -0
  11. package/dist/{chunk-ZATQZUJT.js → chunk-MNJDYDGH.js} +9 -1
  12. package/dist/{chunk-ZATQZUJT.js.map → chunk-MNJDYDGH.js.map} +1 -1
  13. package/dist/chunk-PQRVTUNH.js +145 -0
  14. package/dist/chunk-PQRVTUNH.js.map +1 -0
  15. package/dist/chunk-QWUJIKTX.js +527 -0
  16. package/dist/chunk-QWUJIKTX.js.map +1 -0
  17. package/dist/chunk-S6O7SM6A.js +129 -0
  18. package/dist/chunk-S6O7SM6A.js.map +1 -0
  19. package/dist/chunk-WXS6ONOD.js +103 -0
  20. package/dist/chunk-WXS6ONOD.js.map +1 -0
  21. package/dist/cli.js +354 -4
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config-2XALNLAA.js +14 -0
  24. package/dist/config-2XALNLAA.js.map +1 -0
  25. package/dist/config-editor-56B6YU7B.js +11 -0
  26. package/dist/config-editor-56B6YU7B.js.map +1 -0
  27. package/dist/daemon-3E5OMLT3.js +29 -0
  28. package/dist/daemon-3E5OMLT3.js.map +1 -0
  29. package/dist/index.d.ts +96 -18
  30. package/dist/index.js +35 -6
  31. package/dist/install-cloudflared-57NRTI4E.js +8 -0
  32. package/dist/install-cloudflared-57NRTI4E.js.map +1 -0
  33. package/dist/{main-GC6JY7DS.js → main-YNCSLYVV.js} +43 -11
  34. package/dist/main-YNCSLYVV.js.map +1 -0
  35. package/dist/setup-FTNJACSC.js +27 -0
  36. package/dist/setup-FTNJACSC.js.map +1 -0
  37. package/dist/{tunnel-service-I6NUMBT4.js → tunnel-service-I6WM6USB.js} +10 -10
  38. package/dist/tunnel-service-I6WM6USB.js.map +1 -0
  39. package/package.json +2 -2
  40. package/dist/chunk-HTXK4NLG.js.map +0 -1
  41. package/dist/chunk-XOVJLTEC.js.map +0 -1
  42. package/dist/main-GC6JY7DS.js.map +0 -1
  43. package/dist/setup-XQBEZZQB.js.map +0 -1
  44. package/dist/tunnel-service-I6NUMBT4.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createChildLogger,
3
3
  createSessionLogger
4
- } from "./chunk-ZATQZUJT.js";
4
+ } from "./chunk-MNJDYDGH.js";
5
5
 
6
6
  // src/core/streams.ts
7
7
  function nodeToWebWritable(nodeStream) {
@@ -580,6 +580,7 @@ var Session = class {
580
580
  try {
581
581
  const start = Date.now();
582
582
  await this.agentInstance.prompt('Reply with only "ready".');
583
+ this.status = "active";
583
584
  this.log.info({ durationMs: Date.now() - start }, "Warm-up complete");
584
585
  } catch (err) {
585
586
  this.log.error({ err }, "Warm-up failed");
@@ -1259,6 +1260,187 @@ var ChannelAdapter = class {
1259
1260
  }
1260
1261
  };
1261
1262
 
1263
+ // src/core/api-server.ts
1264
+ import * as http from "http";
1265
+ import * as fs3 from "fs";
1266
+ import * as path4 from "path";
1267
+ import * as os2 from "os";
1268
+ var log4 = createChildLogger({ module: "api-server" });
1269
+ var DEFAULT_PORT_FILE = path4.join(os2.homedir(), ".openacp", "api.port");
1270
+ var ApiServer = class {
1271
+ constructor(core, config, portFilePath) {
1272
+ this.core = core;
1273
+ this.config = config;
1274
+ this.portFilePath = portFilePath ?? DEFAULT_PORT_FILE;
1275
+ }
1276
+ server = null;
1277
+ actualPort = 0;
1278
+ portFilePath;
1279
+ async start() {
1280
+ this.server = http.createServer((req, res) => this.handleRequest(req, res));
1281
+ await new Promise((resolve, reject) => {
1282
+ this.server.on("error", (err) => {
1283
+ if (err.code === "EADDRINUSE") {
1284
+ log4.warn({ port: this.config.port }, "API port in use, continuing without API server");
1285
+ this.server = null;
1286
+ resolve();
1287
+ } else {
1288
+ reject(err);
1289
+ }
1290
+ });
1291
+ this.server.listen(this.config.port, this.config.host, () => {
1292
+ const addr = this.server.address();
1293
+ if (addr && typeof addr === "object") {
1294
+ this.actualPort = addr.port;
1295
+ }
1296
+ this.writePortFile();
1297
+ log4.info({ host: this.config.host, port: this.actualPort }, "API server listening");
1298
+ resolve();
1299
+ });
1300
+ });
1301
+ }
1302
+ async stop() {
1303
+ this.removePortFile();
1304
+ if (this.server) {
1305
+ await new Promise((resolve) => {
1306
+ this.server.close(() => resolve());
1307
+ });
1308
+ this.server = null;
1309
+ }
1310
+ }
1311
+ getPort() {
1312
+ return this.actualPort;
1313
+ }
1314
+ writePortFile() {
1315
+ const dir = path4.dirname(this.portFilePath);
1316
+ fs3.mkdirSync(dir, { recursive: true });
1317
+ fs3.writeFileSync(this.portFilePath, String(this.actualPort));
1318
+ }
1319
+ removePortFile() {
1320
+ try {
1321
+ fs3.unlinkSync(this.portFilePath);
1322
+ } catch {
1323
+ }
1324
+ }
1325
+ async handleRequest(req, res) {
1326
+ const method = req.method?.toUpperCase();
1327
+ const url = req.url || "";
1328
+ try {
1329
+ if (method === "POST" && url === "/api/sessions") {
1330
+ await this.handleCreateSession(req, res);
1331
+ } else if (method === "DELETE" && url.match(/^\/api\/sessions\/(.+)$/)) {
1332
+ const sessionId = url.match(/^\/api\/sessions\/(.+)$/)[1];
1333
+ await this.handleCancelSession(sessionId, res);
1334
+ } else if (method === "GET" && url === "/api/sessions") {
1335
+ await this.handleListSessions(res);
1336
+ } else if (method === "GET" && url === "/api/agents") {
1337
+ await this.handleListAgents(res);
1338
+ } else {
1339
+ this.sendJson(res, 404, { error: "Not found" });
1340
+ }
1341
+ } catch (err) {
1342
+ log4.error({ err }, "API request error");
1343
+ this.sendJson(res, 500, { error: "Internal server error" });
1344
+ }
1345
+ }
1346
+ async handleCreateSession(req, res) {
1347
+ const body = await this.readBody(req);
1348
+ let agent;
1349
+ let workspace;
1350
+ if (body) {
1351
+ try {
1352
+ const parsed = JSON.parse(body);
1353
+ agent = parsed.agent;
1354
+ workspace = parsed.workspace;
1355
+ } catch {
1356
+ this.sendJson(res, 400, { error: "Invalid JSON body" });
1357
+ return;
1358
+ }
1359
+ }
1360
+ const config = this.core.configManager.get();
1361
+ const activeSessions = this.core.sessionManager.listSessions().filter((s) => s.status === "active" || s.status === "initializing");
1362
+ if (activeSessions.length >= config.security.maxConcurrentSessions) {
1363
+ this.sendJson(res, 429, {
1364
+ error: `Max concurrent sessions (${config.security.maxConcurrentSessions}) reached. Cancel a session first.`
1365
+ });
1366
+ return;
1367
+ }
1368
+ const [adapterId, adapter] = this.core.adapters.entries().next().value ?? [null, null];
1369
+ const channelId = adapterId ?? "api";
1370
+ const session = await this.core.handleNewSession(channelId, agent, workspace);
1371
+ if (adapter) {
1372
+ try {
1373
+ const threadId = await adapter.createSessionThread(session.id, `\u{1F504} ${session.agentName} \u2014 New Session`);
1374
+ session.threadId = threadId;
1375
+ this.core.wireSessionEvents(session, adapter);
1376
+ } catch (err) {
1377
+ log4.warn({ err, sessionId: session.id }, "Failed to create session thread on adapter, running headless");
1378
+ }
1379
+ }
1380
+ if (!adapter) {
1381
+ session.agentInstance.onPermissionRequest = async (request) => {
1382
+ const allowOption = request.options.find((o) => o.isAllow);
1383
+ log4.debug({ sessionId: session.id, permissionId: request.id, option: allowOption?.id }, "Auto-approving permission for API session");
1384
+ return allowOption?.id ?? request.options[0]?.id ?? "";
1385
+ };
1386
+ }
1387
+ session.warmup().catch((err) => log4.warn({ err, sessionId: session.id }, "API session warmup failed"));
1388
+ this.sendJson(res, 200, {
1389
+ sessionId: session.id,
1390
+ agent: session.agentName,
1391
+ status: session.status,
1392
+ workspace: session.workingDirectory
1393
+ });
1394
+ }
1395
+ async handleCancelSession(sessionId, res) {
1396
+ const session = this.core.sessionManager.getSession(sessionId);
1397
+ if (!session) {
1398
+ this.sendJson(res, 404, { error: `Session "${sessionId}" not found` });
1399
+ return;
1400
+ }
1401
+ await session.cancel();
1402
+ this.sendJson(res, 200, { ok: true });
1403
+ }
1404
+ async handleListSessions(res) {
1405
+ const sessions = this.core.sessionManager.listSessions();
1406
+ this.sendJson(res, 200, {
1407
+ sessions: sessions.map((s) => ({
1408
+ id: s.id,
1409
+ agent: s.agentName,
1410
+ status: s.status,
1411
+ name: s.name ?? null,
1412
+ workspace: s.workingDirectory
1413
+ }))
1414
+ });
1415
+ }
1416
+ async handleListAgents(res) {
1417
+ const agents = this.core.agentManager.getAvailableAgents();
1418
+ const defaultAgent = this.core.configManager.get().defaultAgent;
1419
+ this.sendJson(res, 200, {
1420
+ agents: agents.map((a) => ({
1421
+ name: a.name,
1422
+ command: a.command,
1423
+ args: a.args
1424
+ })),
1425
+ default: defaultAgent
1426
+ });
1427
+ }
1428
+ sendJson(res, status, data) {
1429
+ res.writeHead(status, { "Content-Type": "application/json" });
1430
+ res.end(JSON.stringify(data));
1431
+ }
1432
+ readBody(req) {
1433
+ return new Promise((resolve) => {
1434
+ let data = "";
1435
+ req.on("data", (chunk) => {
1436
+ data += chunk;
1437
+ });
1438
+ req.on("end", () => resolve(data));
1439
+ req.on("error", () => resolve(""));
1440
+ });
1441
+ }
1442
+ };
1443
+
1262
1444
  // src/adapters/telegram/adapter.ts
1263
1445
  import { Bot } from "grammy";
1264
1446
 
@@ -1453,24 +1635,33 @@ var MessageDraft = class {
1453
1635
  });
1454
1636
  this.messageId = msg.message_id;
1455
1637
  } else {
1456
- await this.bot.api.editMessageText(this.chatId, this.messageId, truncated, {
1457
- parse_mode: "HTML"
1458
- });
1638
+ await this.bot.api.editMessageText(
1639
+ this.chatId,
1640
+ this.messageId,
1641
+ truncated,
1642
+ {
1643
+ parse_mode: "HTML"
1644
+ }
1645
+ );
1459
1646
  }
1460
1647
  } catch {
1461
1648
  try {
1462
1649
  if (!this.messageId) {
1463
- const msg = await this.bot.api.sendMessage(this.chatId, this.buffer.slice(0, 4096), {
1464
- message_thread_id: this.threadId,
1465
- disable_notification: true
1466
- });
1650
+ const msg = await this.bot.api.sendMessage(
1651
+ this.chatId,
1652
+ this.buffer.slice(0, 4096),
1653
+ {
1654
+ message_thread_id: this.threadId,
1655
+ disable_notification: true
1656
+ }
1657
+ );
1467
1658
  this.messageId = msg.message_id;
1468
1659
  }
1469
1660
  } catch {
1470
1661
  }
1471
1662
  }
1472
1663
  }
1473
- async finalize() {
1664
+ async finalize(replyMarkup) {
1474
1665
  if (this.flushTimer) {
1475
1666
  clearTimeout(this.flushTimer);
1476
1667
  this.flushTimer = void 0;
@@ -1482,25 +1673,38 @@ var MessageDraft = class {
1482
1673
  try {
1483
1674
  for (let i = 0; i < chunks.length; i++) {
1484
1675
  const chunk = chunks[i];
1676
+ const isLast = i === chunks.length - 1;
1677
+ const markup = isLast && replyMarkup ? { reply_markup: replyMarkup } : {};
1485
1678
  if (i === 0 && this.messageId) {
1486
- await this.bot.api.editMessageText(this.chatId, this.messageId, chunk, {
1487
- parse_mode: "HTML"
1488
- });
1679
+ await this.bot.api.editMessageText(
1680
+ this.chatId,
1681
+ this.messageId,
1682
+ chunk,
1683
+ {
1684
+ parse_mode: "HTML",
1685
+ ...markup
1686
+ }
1687
+ );
1489
1688
  } else {
1490
1689
  const msg = await this.bot.api.sendMessage(this.chatId, chunk, {
1491
1690
  message_thread_id: this.threadId,
1492
1691
  parse_mode: "HTML",
1493
- disable_notification: true
1692
+ disable_notification: true,
1693
+ ...markup
1494
1694
  });
1495
1695
  this.messageId = msg.message_id;
1496
1696
  }
1497
1697
  }
1498
1698
  } catch {
1499
1699
  try {
1500
- await this.bot.api.sendMessage(this.chatId, this.buffer.slice(0, 4096), {
1501
- message_thread_id: this.threadId,
1502
- disable_notification: true
1503
- });
1700
+ await this.bot.api.sendMessage(
1701
+ this.chatId,
1702
+ this.buffer.slice(0, 4096),
1703
+ {
1704
+ message_thread_id: this.threadId,
1705
+ disable_notification: true
1706
+ }
1707
+ );
1504
1708
  } catch {
1505
1709
  }
1506
1710
  }
@@ -1509,6 +1713,9 @@ var MessageDraft = class {
1509
1713
  getMessageId() {
1510
1714
  return this.messageId;
1511
1715
  }
1716
+ getBuffer() {
1717
+ return this.buffer;
1718
+ }
1512
1719
  };
1513
1720
 
1514
1721
  // src/adapters/telegram/topics.ts
@@ -1545,7 +1752,7 @@ function buildDeepLink(chatId, messageId) {
1545
1752
  // src/adapters/telegram/commands.ts
1546
1753
  import { InlineKeyboard } from "grammy";
1547
1754
  import { nanoid as nanoid2 } from "nanoid";
1548
- var log5 = createChildLogger({ module: "telegram-commands" });
1755
+ var log6 = createChildLogger({ module: "telegram-commands" });
1549
1756
  function setupCommands(bot, core, chatId) {
1550
1757
  bot.command("new", (ctx) => handleNew(ctx, core, chatId));
1551
1758
  bot.command("new_chat", (ctx) => handleNewChat(ctx, core, chatId));
@@ -1600,7 +1807,7 @@ async function handleNew(ctx, core, chatId) {
1600
1807
  const args = matchStr.split(" ").filter(Boolean);
1601
1808
  const agentName = args[0];
1602
1809
  const workspace = args[1];
1603
- log5.info({ userId: ctx.from?.id, agentName }, "New session command");
1810
+ log6.info({ userId: ctx.from?.id, agentName }, "New session command");
1604
1811
  let threadId;
1605
1812
  try {
1606
1813
  const topicName = `\u{1F504} New Session`;
@@ -1633,15 +1840,16 @@ async function handleNew(ctx, core, chatId) {
1633
1840
  parse_mode: "HTML"
1634
1841
  }
1635
1842
  );
1636
- session.warmup().catch((err) => log5.error({ err }, "Warm-up error"));
1843
+ session.warmup().catch((err) => log6.error({ err }, "Warm-up error"));
1637
1844
  } catch (err) {
1845
+ log6.error({ err }, "Session creation failed");
1638
1846
  if (threadId) {
1639
1847
  try {
1640
1848
  await ctx.api.deleteForumTopic(chatId, threadId);
1641
1849
  } catch {
1642
1850
  }
1643
1851
  }
1644
- const message = err instanceof Error ? err.message : String(err);
1852
+ const message = err instanceof Error ? err.message : typeof err === "object" ? JSON.stringify(err) : String(err);
1645
1853
  await ctx.reply(`\u274C ${escapeHtml(message)}`, { parse_mode: "HTML" });
1646
1854
  }
1647
1855
  }
@@ -1686,7 +1894,7 @@ async function handleNewChat(ctx, core, chatId) {
1686
1894
  parse_mode: "HTML"
1687
1895
  }
1688
1896
  );
1689
- session.warmup().catch((err) => log5.error({ err }, "Warm-up error"));
1897
+ session.warmup().catch((err) => log6.error({ err }, "Warm-up error"));
1690
1898
  } catch (err) {
1691
1899
  const message = err instanceof Error ? err.message : String(err);
1692
1900
  await ctx.reply(`\u274C ${escapeHtml(message)}`, { parse_mode: "HTML" });
@@ -1700,7 +1908,7 @@ async function handleCancel(ctx, core) {
1700
1908
  String(threadId)
1701
1909
  );
1702
1910
  if (session) {
1703
- log5.info({ sessionId: session.id }, "Cancel session command");
1911
+ log6.info({ sessionId: session.id }, "Cancel session command");
1704
1912
  await session.cancel();
1705
1913
  await ctx.reply("\u26D4 Session cancelled.", { parse_mode: "HTML" });
1706
1914
  }
@@ -1808,6 +2016,41 @@ function setupSkillCallbacks(bot, core) {
1808
2016
  await session.enqueuePrompt(`/${entry.commandName}`);
1809
2017
  });
1810
2018
  }
2019
+ async function executeNewSession(bot, core, chatId, agentName, workspace) {
2020
+ const threadId = await createSessionTopic(bot, chatId, "\u{1F504} New Session");
2021
+ await bot.api.sendMessage(chatId, "\u23F3 Setting up session, please wait...", {
2022
+ message_thread_id: threadId,
2023
+ parse_mode: "HTML"
2024
+ });
2025
+ try {
2026
+ const session = await core.handleNewSession(
2027
+ "telegram",
2028
+ agentName,
2029
+ workspace
2030
+ );
2031
+ session.threadId = String(threadId);
2032
+ await core.sessionManager.updateSessionPlatform(session.id, {
2033
+ topicId: threadId
2034
+ });
2035
+ const finalName = `\u{1F504} ${session.agentName} \u2014 New Session`;
2036
+ await renameSessionTopic(bot, chatId, threadId, finalName);
2037
+ session.warmup().catch((err) => log6.error({ err }, "Warm-up error"));
2038
+ return { session, threadId };
2039
+ } catch (err) {
2040
+ try {
2041
+ await bot.api.deleteForumTopic(chatId, threadId);
2042
+ } catch {
2043
+ }
2044
+ throw err;
2045
+ }
2046
+ }
2047
+ async function executeCancelSession(core, excludeSessionId) {
2048
+ const sessions = core.sessionManager.listSessions("telegram").filter((s) => s.status === "active" && s.id !== excludeSessionId).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2049
+ const session = sessions[0];
2050
+ if (!session) return null;
2051
+ await session.cancel();
2052
+ return session;
2053
+ }
1811
2054
  var STATIC_COMMANDS = [
1812
2055
  { command: "new", description: "Create new session" },
1813
2056
  { command: "new_chat", description: "New chat, same agent & workspace" },
@@ -1821,7 +2064,7 @@ var STATIC_COMMANDS = [
1821
2064
  // src/adapters/telegram/permissions.ts
1822
2065
  import { InlineKeyboard as InlineKeyboard2 } from "grammy";
1823
2066
  import { nanoid as nanoid3 } from "nanoid";
1824
- var log6 = createChildLogger({ module: "telegram-permissions" });
2067
+ var log7 = createChildLogger({ module: "telegram-permissions" });
1825
2068
  var PermissionHandler = class {
1826
2069
  constructor(bot, chatId, getSession, sendNotification) {
1827
2070
  this.bot = bot;
@@ -1881,7 +2124,7 @@ ${escapeHtml(request.description)}`,
1881
2124
  }
1882
2125
  const session = this.getSession(pending.sessionId);
1883
2126
  const isAllow = pending.options.find((o) => o.id === optionId)?.isAllow ?? false;
1884
- log6.info({ requestId: pending.requestId, optionId, isAllow }, "Permission responded");
2127
+ log7.info({ requestId: pending.requestId, optionId, isAllow }, "Permission responded");
1885
2128
  if (session?.pendingPermission?.requestId === pending.requestId) {
1886
2129
  session.pendingPermission.resolve(optionId);
1887
2130
  session.pendingPermission = void 0;
@@ -1947,8 +2190,166 @@ function redirectToAssistant(chatId, assistantTopicId) {
1947
2190
  return `\u{1F4AC} Please use the <a href="${link}">\u{1F916} Assistant</a> topic to chat with OpenACP.`;
1948
2191
  }
1949
2192
 
2193
+ // src/adapters/telegram/action-detect.ts
2194
+ import { nanoid as nanoid4 } from "nanoid";
2195
+ import { InlineKeyboard as InlineKeyboard3 } from "grammy";
2196
+ var CMD_NEW_RE = /\/new(?:\s+([^\s\u0080-\uFFFF]+)(?:\s+([^\s\u0080-\uFFFF]+))?)?/;
2197
+ var CMD_CANCEL_RE = /\/cancel\b/;
2198
+ var KW_NEW_RE = /(?:tao|tạo|create|new)\s+session/i;
2199
+ var KW_CANCEL_RE = /(?:huy|huỷ|cancel|dung|dừng)\s+session/i;
2200
+ function detectAction(text) {
2201
+ if (!text) return null;
2202
+ const cancelCmd = CMD_CANCEL_RE.exec(text);
2203
+ if (cancelCmd) return { action: "cancel_session" };
2204
+ const newCmd = CMD_NEW_RE.exec(text);
2205
+ if (newCmd) {
2206
+ return {
2207
+ action: "new_session",
2208
+ agent: newCmd[1] || void 0,
2209
+ workspace: newCmd[2] || void 0
2210
+ };
2211
+ }
2212
+ if (KW_CANCEL_RE.test(text)) return { action: "cancel_session" };
2213
+ if (KW_NEW_RE.test(text))
2214
+ return { action: "new_session", agent: void 0, workspace: void 0 };
2215
+ return null;
2216
+ }
2217
+ var ACTION_TTL_MS = 5 * 60 * 1e3;
2218
+ var actionMap = /* @__PURE__ */ new Map();
2219
+ function storeAction(action) {
2220
+ const id = nanoid4(10);
2221
+ actionMap.set(id, { action, createdAt: Date.now() });
2222
+ for (const [key, entry] of actionMap) {
2223
+ if (Date.now() - entry.createdAt > ACTION_TTL_MS) {
2224
+ actionMap.delete(key);
2225
+ }
2226
+ }
2227
+ return id;
2228
+ }
2229
+ function getAction(id) {
2230
+ const entry = actionMap.get(id);
2231
+ if (!entry) return void 0;
2232
+ if (Date.now() - entry.createdAt > ACTION_TTL_MS) {
2233
+ actionMap.delete(id);
2234
+ return void 0;
2235
+ }
2236
+ return entry.action;
2237
+ }
2238
+ function removeAction(id) {
2239
+ actionMap.delete(id);
2240
+ }
2241
+ function buildActionKeyboard(actionId, action) {
2242
+ const keyboard = new InlineKeyboard3();
2243
+ if (action.action === "new_session") {
2244
+ keyboard.text("\u2705 T\u1EA1o session", `a:${actionId}`);
2245
+ keyboard.text("\u274C Hu\u1EF7", `a:dismiss:${actionId}`);
2246
+ } else {
2247
+ keyboard.text("\u26D4 Hu\u1EF7 session", `a:${actionId}`);
2248
+ keyboard.text("\u274C Kh\xF4ng", `a:dismiss:${actionId}`);
2249
+ }
2250
+ return keyboard;
2251
+ }
2252
+ function setupActionCallbacks(bot, core, chatId, getAssistantSessionId) {
2253
+ bot.callbackQuery(/^a:dismiss:/, async (ctx) => {
2254
+ const actionId = ctx.callbackQuery.data.replace("a:dismiss:", "");
2255
+ removeAction(actionId);
2256
+ try {
2257
+ await ctx.editMessageReplyMarkup({
2258
+ reply_markup: { inline_keyboard: [] }
2259
+ });
2260
+ } catch {
2261
+ }
2262
+ await ctx.answerCallbackQuery({ text: "\u0110\xE3 hu\u1EF7" });
2263
+ });
2264
+ bot.callbackQuery(/^a:(?!dismiss)/, async (ctx) => {
2265
+ const actionId = ctx.callbackQuery.data.replace("a:", "");
2266
+ const action = getAction(actionId);
2267
+ if (!action) {
2268
+ await ctx.answerCallbackQuery({ text: "Action \u0111\xE3 h\u1EBFt h\u1EA1n" });
2269
+ return;
2270
+ }
2271
+ removeAction(actionId);
2272
+ try {
2273
+ if (action.action === "new_session") {
2274
+ await ctx.answerCallbackQuery({ text: "\u23F3 \u0110ang t\u1EA1o session..." });
2275
+ const { threadId } = await executeNewSession(
2276
+ bot,
2277
+ core,
2278
+ chatId,
2279
+ action.agent,
2280
+ action.workspace
2281
+ );
2282
+ const topicLink = `https://t.me/c/${String(chatId).replace("-100", "")}/${threadId}`;
2283
+ const originalText = ctx.callbackQuery.message?.text ?? "";
2284
+ try {
2285
+ await ctx.editMessageText(
2286
+ originalText + `
2287
+
2288
+ \u2705 Session created \u2192 <a href="${topicLink}">Go to topic</a>`,
2289
+ { parse_mode: "HTML" }
2290
+ );
2291
+ } catch {
2292
+ await ctx.editMessageReplyMarkup({
2293
+ reply_markup: { inline_keyboard: [] }
2294
+ });
2295
+ }
2296
+ } else if (action.action === "cancel_session") {
2297
+ const assistantId = getAssistantSessionId();
2298
+ const cancelled = await executeCancelSession(core, assistantId);
2299
+ if (cancelled) {
2300
+ await ctx.answerCallbackQuery({ text: "\u26D4 Session \u0111\xE3 hu\u1EF7" });
2301
+ const originalText = ctx.callbackQuery.message?.text ?? "";
2302
+ try {
2303
+ await ctx.editMessageText(
2304
+ originalText + `
2305
+
2306
+ \u26D4 Session "${cancelled.name ?? cancelled.id}" \u0111\xE3 hu\u1EF7`,
2307
+ { parse_mode: "HTML" }
2308
+ );
2309
+ } catch {
2310
+ await ctx.editMessageReplyMarkup({
2311
+ reply_markup: { inline_keyboard: [] }
2312
+ });
2313
+ }
2314
+ } else {
2315
+ await ctx.answerCallbackQuery({
2316
+ text: "Kh\xF4ng c\xF3 session n\xE0o \u0111ang ch\u1EA1y"
2317
+ });
2318
+ try {
2319
+ await ctx.editMessageReplyMarkup({
2320
+ reply_markup: { inline_keyboard: [] }
2321
+ });
2322
+ } catch {
2323
+ }
2324
+ }
2325
+ }
2326
+ } catch {
2327
+ await ctx.answerCallbackQuery({ text: "\u274C L\u1ED7i, th\u1EED l\u1EA1i sau" });
2328
+ try {
2329
+ await ctx.editMessageReplyMarkup({
2330
+ reply_markup: { inline_keyboard: [] }
2331
+ });
2332
+ } catch {
2333
+ }
2334
+ }
2335
+ });
2336
+ }
2337
+
1950
2338
  // src/adapters/telegram/adapter.ts
1951
- var log7 = createChildLogger({ module: "telegram" });
2339
+ var log8 = createChildLogger({ module: "telegram" });
2340
+ function patchedFetch(input, init) {
2341
+ if (init?.signal && !(init.signal instanceof AbortSignal)) {
2342
+ const nativeController = new AbortController();
2343
+ const polyfillSignal = init.signal;
2344
+ if (polyfillSignal.aborted) {
2345
+ nativeController.abort();
2346
+ } else {
2347
+ polyfillSignal.addEventListener("abort", () => nativeController.abort());
2348
+ }
2349
+ init = { ...init, signal: nativeController.signal };
2350
+ }
2351
+ return fetch(input, init);
2352
+ }
1952
2353
  var TelegramAdapter = class extends ChannelAdapter {
1953
2354
  bot;
1954
2355
  telegramConfig;
@@ -1966,10 +2367,10 @@ var TelegramAdapter = class extends ChannelAdapter {
1966
2367
  this.telegramConfig = config;
1967
2368
  }
1968
2369
  async start() {
1969
- this.bot = new Bot(this.telegramConfig.botToken, { client: { fetch } });
2370
+ this.bot = new Bot(this.telegramConfig.botToken, { client: { fetch: patchedFetch } });
1970
2371
  this.bot.catch((err) => {
1971
2372
  const rootCause = err.error instanceof Error ? err.error : err;
1972
- log7.error({ err: rootCause }, "Telegram bot error");
2373
+ log8.error({ err: rootCause }, "Telegram bot error");
1973
2374
  });
1974
2375
  this.bot.api.config.use((prev, method, payload, signal) => {
1975
2376
  if (method === "getUpdates") {
@@ -2008,6 +2409,12 @@ var TelegramAdapter = class extends ChannelAdapter {
2008
2409
  (notification) => this.sendNotification(notification)
2009
2410
  );
2010
2411
  setupSkillCallbacks(this.bot, this.core);
2412
+ setupActionCallbacks(
2413
+ this.bot,
2414
+ this.core,
2415
+ this.telegramConfig.chatId,
2416
+ () => this.assistantSession?.id
2417
+ );
2011
2418
  setupMenuCallbacks(
2012
2419
  this.bot,
2013
2420
  this.core,
@@ -2022,7 +2429,7 @@ var TelegramAdapter = class extends ChannelAdapter {
2022
2429
  this.setupRoutes();
2023
2430
  this.bot.start({
2024
2431
  allowed_updates: ["message", "callback_query"],
2025
- onStart: () => log7.info(
2432
+ onStart: () => log8.info(
2026
2433
  { chatId: this.telegramConfig.chatId },
2027
2434
  "Telegram bot started"
2028
2435
  )
@@ -2034,7 +2441,7 @@ var TelegramAdapter = class extends ChannelAdapter {
2034
2441
  this.assistantTopicId
2035
2442
  );
2036
2443
  } catch (err) {
2037
- log7.error({ err }, "Failed to spawn assistant");
2444
+ log8.error({ err }, "Failed to spawn assistant");
2038
2445
  }
2039
2446
  try {
2040
2447
  const config = this.core.configManager.get();
@@ -2055,7 +2462,7 @@ Workspace: <code>${workspace}</code>
2055
2462
  reply_markup: buildMenuKeyboard()
2056
2463
  });
2057
2464
  } catch (err) {
2058
- log7.warn({ err }, "Failed to send welcome message");
2465
+ log8.warn({ err }, "Failed to send welcome message");
2059
2466
  }
2060
2467
  }
2061
2468
  async stop() {
@@ -2063,7 +2470,7 @@ Workspace: <code>${workspace}</code>
2063
2470
  await this.assistantSession.destroy();
2064
2471
  }
2065
2472
  await this.bot.stop();
2066
- log7.info("Telegram bot stopped");
2473
+ log8.info("Telegram bot stopped");
2067
2474
  }
2068
2475
  setupRoutes() {
2069
2476
  this.bot.on("message:text", async (ctx) => {
@@ -2081,7 +2488,7 @@ Workspace: <code>${workspace}</code>
2081
2488
  ctx.replyWithChatAction("typing").catch(() => {
2082
2489
  });
2083
2490
  handleAssistantMessage(this.assistantSession, ctx.message.text).catch(
2084
- (err) => log7.error({ err }, "Assistant error")
2491
+ (err) => log8.error({ err }, "Assistant error")
2085
2492
  );
2086
2493
  return;
2087
2494
  }
@@ -2092,7 +2499,7 @@ Workspace: <code>${workspace}</code>
2092
2499
  threadId: String(threadId),
2093
2500
  userId: String(ctx.from.id),
2094
2501
  text: ctx.message.text
2095
- }).catch((err) => log7.error({ err }, "handleMessage error"));
2502
+ }).catch((err) => log8.error({ err }, "handleMessage error"));
2096
2503
  });
2097
2504
  }
2098
2505
  // --- ChannelAdapter implementations ---
@@ -2182,6 +2589,7 @@ Workspace: <code>${workspace}</code>
2182
2589
  break;
2183
2590
  }
2184
2591
  case "usage": {
2592
+ await this.finalizeDraft(sessionId);
2185
2593
  await this.bot.api.sendMessage(
2186
2594
  this.telegramConfig.chatId,
2187
2595
  formatUsage(
@@ -2227,7 +2635,7 @@ Workspace: <code>${workspace}</code>
2227
2635
  }
2228
2636
  }
2229
2637
  async sendPermissionRequest(sessionId, request) {
2230
- log7.info({ sessionId, requestId: request.id }, "Permission request sent");
2638
+ log8.info({ sessionId, requestId: request.id }, "Permission request sent");
2231
2639
  const session = this.core.sessionManager.getSession(
2232
2640
  sessionId
2233
2641
  );
@@ -2235,7 +2643,7 @@ Workspace: <code>${workspace}</code>
2235
2643
  await this.permissionHandler.sendPermissionRequest(session, request);
2236
2644
  }
2237
2645
  async sendNotification(notification) {
2238
- log7.info(
2646
+ log8.info(
2239
2647
  { sessionId: notification.sessionId, type: notification.type },
2240
2648
  "Notification sent"
2241
2649
  );
@@ -2261,7 +2669,7 @@ Workspace: <code>${workspace}</code>
2261
2669
  });
2262
2670
  }
2263
2671
  async createSessionThread(sessionId, name) {
2264
- log7.info({ sessionId, name }, "Session topic created");
2672
+ log8.info({ sessionId, name }, "Session topic created");
2265
2673
  return String(
2266
2674
  await createSessionTopic(this.bot, this.telegramConfig.chatId, name)
2267
2675
  );
@@ -2325,7 +2733,7 @@ Workspace: <code>${workspace}</code>
2325
2733
  }
2326
2734
  );
2327
2735
  } catch (err) {
2328
- log7.error({ err, sessionId }, "Failed to send skill commands");
2736
+ log8.error({ err, sessionId }, "Failed to send skill commands");
2329
2737
  }
2330
2738
  await this.updateCommandAutocomplete(session.agentName, commands);
2331
2739
  }
@@ -2356,12 +2764,12 @@ Workspace: <code>${workspace}</code>
2356
2764
  await this.bot.api.setMyCommands(all, {
2357
2765
  scope: { type: "chat", chat_id: this.telegramConfig.chatId }
2358
2766
  });
2359
- log7.info(
2767
+ log8.info(
2360
2768
  { count: all.length, skills: validSkills.length },
2361
2769
  "Updated command autocomplete"
2362
2770
  );
2363
2771
  } catch (err) {
2364
- log7.error(
2772
+ log8.error(
2365
2773
  { err, commands: all },
2366
2774
  "Failed to update command autocomplete"
2367
2775
  );
@@ -2369,10 +2777,20 @@ Workspace: <code>${workspace}</code>
2369
2777
  }
2370
2778
  async finalizeDraft(sessionId) {
2371
2779
  const draft = this.sessionDrafts.get(sessionId);
2372
- if (draft) {
2373
- await draft.finalize();
2374
- this.sessionDrafts.delete(sessionId);
2780
+ if (!draft) return;
2781
+ let keyboard;
2782
+ if (sessionId === this.assistantSession?.id) {
2783
+ const fullText = draft.getBuffer();
2784
+ if (fullText) {
2785
+ const detected = detectAction(fullText);
2786
+ if (detected) {
2787
+ const actionId = storeAction(detected);
2788
+ keyboard = buildActionKeyboard(actionId, detected);
2789
+ }
2790
+ }
2375
2791
  }
2792
+ await draft.finalize(keyboard);
2793
+ this.sessionDrafts.delete(sessionId);
2376
2794
  }
2377
2795
  };
2378
2796
 
@@ -2387,6 +2805,7 @@ export {
2387
2805
  NotificationManager,
2388
2806
  OpenACPCore,
2389
2807
  ChannelAdapter,
2808
+ ApiServer,
2390
2809
  TelegramAdapter
2391
2810
  };
2392
- //# sourceMappingURL=chunk-HTXK4NLG.js.map
2811
+ //# sourceMappingURL=chunk-IX63F4JG.js.map