@cosmicstack/mercury-agent 0.2.0 → 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/README.md +13 -1
- package/dist/index.js +89 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,4 +193,16 @@ Configure multiple LLM providers. Mercury tries them in order and falls back aut
|
|
|
193
193
|
|
|
194
194
|
## License
|
|
195
195
|
|
|
196
|
-
MIT © [Cosmic Stack](https://github.com/cosmicstack-labs)
|
|
196
|
+
MIT © [Cosmic Stack](https://github.com/cosmicstack-labs)
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Disclaimer
|
|
201
|
+
|
|
202
|
+
**This is AI - it can break sometimes, please use this at your own risk.**
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Suggestions and Contributions
|
|
207
|
+
|
|
208
|
+
For suggestions, contributions, or any inquiries, please reach out to us at [support@cosmicstack.org](mailto:support@cosmicstack.org).
|
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, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1950
1992
|
}
|
|
@@ -2165,7 +2207,7 @@ var TokenBudget = class {
|
|
|
2165
2207
|
|
|
2166
2208
|
// src/capabilities/permissions.ts
|
|
2167
2209
|
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
2168
|
-
import { join as join6, resolve } from "path";
|
|
2210
|
+
import { join as join6, resolve, sep } from "path";
|
|
2169
2211
|
import { homedir as homedir2 } from "os";
|
|
2170
2212
|
import { parse as parseYaml3, stringify as stringifyYaml3 } from "yaml";
|
|
2171
2213
|
var DEFAULT_MANIFEST = {
|
|
@@ -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() {
|
|
@@ -2421,7 +2492,7 @@ var PermissionManager = class {
|
|
|
2421
2492
|
const scopes = this.manifest.capabilities.filesystem.scopes;
|
|
2422
2493
|
for (const scope of scopes) {
|
|
2423
2494
|
const scopeResolved = resolve(scope.path.replace(/^~/, homedir2()));
|
|
2424
|
-
if (resolvedPath === scopeResolved || resolvedPath.startsWith(scopeResolved +
|
|
2495
|
+
if (resolvedPath === scopeResolved || resolvedPath.startsWith(scopeResolved + sep)) {
|
|
2425
2496
|
return scope;
|
|
2426
2497
|
}
|
|
2427
2498
|
}
|
|
@@ -2455,7 +2526,9 @@ var PermissionManager = class {
|
|
|
2455
2526
|
const pathPatterns = [
|
|
2456
2527
|
/(?:^|\s)(\/[^\s]+)/,
|
|
2457
2528
|
/(?:^|\s)(~\/[^\s]+)/,
|
|
2458
|
-
/(?:^|\s)\.\.\/([^\s]+)
|
|
2529
|
+
/(?:^|\s)\.\.\/([^\s]+)/,
|
|
2530
|
+
/(?:^|\s)([A-Za-z]:\\[^\s]+)/,
|
|
2531
|
+
/(?:^|\s)(\\\\[^\s]+)/
|
|
2459
2532
|
];
|
|
2460
2533
|
for (const p of pathPatterns) {
|
|
2461
2534
|
const match = command.match(p);
|
|
@@ -4196,7 +4269,7 @@ function banner() {
|
|
|
4196
4269
|
}
|
|
4197
4270
|
console.log("");
|
|
4198
4271
|
console.log(chalk6.white(" an AI agent for personal tasks"));
|
|
4199
|
-
console.log(chalk6.dim(" v0.2.
|
|
4272
|
+
console.log(chalk6.dim(" v0.2.1 \xB7 by Cosmic Stack \xB7 mercury.cosmicstack.org"));
|
|
4200
4273
|
console.log("");
|
|
4201
4274
|
}
|
|
4202
4275
|
function splashScreen() {
|
|
@@ -4439,11 +4512,17 @@ async function runAgent(isDaemon = false) {
|
|
|
4439
4512
|
await agent.birth();
|
|
4440
4513
|
await agent.wake();
|
|
4441
4514
|
const cliChannel = channels.get("cli");
|
|
4442
|
-
|
|
4443
|
-
|
|
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) {
|
|
4444
4522
|
return cliChannel.askPermission(prompt);
|
|
4445
|
-
}
|
|
4446
|
-
|
|
4523
|
+
}
|
|
4524
|
+
return "no";
|
|
4525
|
+
});
|
|
4447
4526
|
const activeCh = channels.getActiveChannels();
|
|
4448
4527
|
const toolNames = capabilities.getToolNames();
|
|
4449
4528
|
if (!isDaemon) {
|
|
@@ -4476,7 +4555,7 @@ async function runAgent(isDaemon = false) {
|
|
|
4476
4555
|
process.on("SIGTERM", shutdown);
|
|
4477
4556
|
}
|
|
4478
4557
|
var program = new Command();
|
|
4479
|
-
program.name("mercury").description("Mercury \u2014 Soul-driven AI agent with permission-hardened tools, token budgets, and multi-channel access.").version("0.2.
|
|
4558
|
+
program.name("mercury").description("Mercury \u2014 Soul-driven AI agent with permission-hardened tools, token budgets, and multi-channel access.").version("0.2.1").option("-v, --verbose", "Show debug logs").action(async () => {
|
|
4480
4559
|
if (!isSetupComplete()) {
|
|
4481
4560
|
await configure();
|
|
4482
4561
|
autoDaemonize();
|