@cosmicstack/mercury-agent 0.2.1 → 0.2.2

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.
package/dist/index.js CHANGED
@@ -848,6 +848,7 @@ You can override this:
848
848
  });
849
849
  }
850
850
  this.capabilities.setChannelContext(msg.channelId, msg.channelType);
851
+ this.capabilities.permissions.setCurrentChannelType(msg.channelType);
851
852
  const fallbackIterator = this.providers.getFallbackIterator();
852
853
  let result = null;
853
854
  let usedProvider = null;
@@ -1720,7 +1721,7 @@ var CLIChannel = class extends BaseChannel {
1720
1721
  // src/channels/telegram.ts
1721
1722
  import fs2 from "fs";
1722
1723
  import path2 from "path";
1723
- import { Bot, InputFile } from "grammy";
1724
+ import { Bot, InputFile, InlineKeyboard } from "grammy";
1724
1725
  import { autoRetry } from "@grammyjs/auto-retry";
1725
1726
  var MAX_MESSAGE_LENGTH = 4096;
1726
1727
  var TelegramChannel = class extends BaseChannel {
@@ -1734,6 +1735,7 @@ var TelegramChannel = class extends BaseChannel {
1734
1735
  ownerChatId = null;
1735
1736
  typingInterval = null;
1736
1737
  chatCommandContext;
1738
+ pendingApprovals = /* @__PURE__ */ new Map();
1737
1739
  setChatCommandContext(ctx) {
1738
1740
  this.chatCommandContext = ctx;
1739
1741
  }
@@ -1762,6 +1764,18 @@ var TelegramChannel = class extends BaseChannel {
1762
1764
  };
1763
1765
  this.emit(msg);
1764
1766
  });
1767
+ bot.on("callback_query:data", async (ctx) => {
1768
+ const data = ctx.callbackQuery.data;
1769
+ const resolver = this.pendingApprovals.get(data);
1770
+ if (!resolver) {
1771
+ await ctx.answerCallbackQuery({ text: "Expired" });
1772
+ return;
1773
+ }
1774
+ this.pendingApprovals.delete(data);
1775
+ const action = data.split(":")[1];
1776
+ resolver(action);
1777
+ await ctx.answerCallbackQuery({ text: action === "no" ? "Denied" : "Approved" });
1778
+ });
1765
1779
  bot.catch((err) => {
1766
1780
  logger.error({ err: err.message }, "Telegram bot error");
1767
1781
  });
@@ -1945,6 +1959,34 @@ var TelegramChannel = class extends BaseChannel {
1945
1959
  this.stopTypingLoop();
1946
1960
  }
1947
1961
  }
1962
+ async askPermission(prompt, targetId) {
1963
+ const chatId = this.parseChatId(targetId);
1964
+ if (!chatId || !this.bot) return "no";
1965
+ const id = `perm_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1966
+ const keyboard = new InlineKeyboard().text("Allow", `${id}:yes`).text("Always", `${id}:always`).text("Deny", `${id}:no`);
1967
+ const html = mdToTelegram(prompt);
1968
+ try {
1969
+ await this.bot.api.sendMessage(chatId, html, {
1970
+ parse_mode: "HTML",
1971
+ reply_markup: keyboard
1972
+ });
1973
+ } catch {
1974
+ await this.bot.api.sendMessage(chatId, this.stripHtml(html), {
1975
+ reply_markup: keyboard
1976
+ });
1977
+ }
1978
+ return new Promise((resolve9) => {
1979
+ this.pendingApprovals.set(`${id}:yes`, () => resolve9("yes"));
1980
+ this.pendingApprovals.set(`${id}:always`, () => resolve9("always"));
1981
+ this.pendingApprovals.set(`${id}:no`, () => resolve9("no"));
1982
+ setTimeout(() => {
1983
+ this.pendingApprovals.delete(`${id}:yes`);
1984
+ this.pendingApprovals.delete(`${id}:always`);
1985
+ this.pendingApprovals.delete(`${id}:no`);
1986
+ resolve9("no");
1987
+ }, 12e4);
1988
+ });
1989
+ }
1948
1990
  escapeHtml(text) {
1949
1991
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1950
1992
  }
@@ -2258,10 +2300,17 @@ var PermissionManager = class {
2258
2300
  autoApproveAll = false;
2259
2301
  elevatedCommands = /* @__PURE__ */ new Set();
2260
2302
  pendingApprovals = /* @__PURE__ */ new Set();
2303
+ currentChannelType = "cli";
2261
2304
  constructor() {
2262
2305
  this.cwd = process.cwd();
2263
2306
  this.manifest = this.load();
2264
2307
  }
2308
+ setCurrentChannelType(type) {
2309
+ this.currentChannelType = type;
2310
+ }
2311
+ getCurrentChannelType() {
2312
+ return this.currentChannelType;
2313
+ }
2265
2314
  onAsk(handler) {
2266
2315
  this.askHandler = handler;
2267
2316
  }
@@ -2390,9 +2439,31 @@ var PermissionManager = class {
2390
2439
  }
2391
2440
  for (const pattern of shell.needsApproval) {
2392
2441
  if (this.matchPattern(trimmed, pattern)) {
2442
+ if (this.currentChannelType === "telegram" && this.askHandler) {
2443
+ const result = await this.askHandler(`Run command: ${trimmed}`);
2444
+ if (result === "yes") {
2445
+ return { allowed: true, needsApproval: false };
2446
+ }
2447
+ if (result === "always") {
2448
+ this.addApprovedCommand(baseCmd);
2449
+ return { allowed: true, needsApproval: false };
2450
+ }
2451
+ return { allowed: false, reason: `User denied: ${trimmed}`, needsApproval: false };
2452
+ }
2393
2453
  return { allowed: false, reason: `Command requires approval: matches "${pattern}"`, needsApproval: true };
2394
2454
  }
2395
2455
  }
2456
+ if (this.currentChannelType === "telegram" && this.askHandler) {
2457
+ const result = await this.askHandler(`Run command: ${trimmed}`);
2458
+ if (result === "yes") {
2459
+ return { allowed: true, needsApproval: false };
2460
+ }
2461
+ if (result === "always") {
2462
+ this.addApprovedCommand(baseCmd);
2463
+ return { allowed: true, needsApproval: false };
2464
+ }
2465
+ return { allowed: false, reason: `User denied: ${trimmed}`, needsApproval: false };
2466
+ }
2396
2467
  return { allowed: false, reason: "Command not in auto-approve list \u2014 requires approval", needsApproval: true };
2397
2468
  }
2398
2469
  isGitReadAllowed() {
@@ -4441,11 +4512,17 @@ async function runAgent(isDaemon = false) {
4441
4512
  await agent.birth();
4442
4513
  await agent.wake();
4443
4514
  const cliChannel = channels.get("cli");
4444
- if (cliChannel) {
4445
- capabilities.permissions.onAsk(async (prompt) => {
4515
+ const tgChannel = channels.get("telegram");
4516
+ capabilities.permissions.onAsk(async (prompt) => {
4517
+ const channelType = capabilities.permissions.getCurrentChannelType();
4518
+ if (channelType === "telegram" && tgChannel) {
4519
+ return tgChannel.askPermission(prompt);
4520
+ }
4521
+ if (cliChannel) {
4446
4522
  return cliChannel.askPermission(prompt);
4447
- });
4448
- }
4523
+ }
4524
+ return "no";
4525
+ });
4449
4526
  const activeCh = channels.getActiveChannels();
4450
4527
  const toolNames = capabilities.getToolNames();
4451
4528
  if (!isDaemon) {