@cosmicstack/mercury-agent 0.2.5 → 0.2.7

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
@@ -7,7 +7,6 @@ import { dirname as dirname3, join as join11 } from "path";
7
7
  import { Command } from "commander";
8
8
  import readline2 from "readline";
9
9
  import chalk6 from "chalk";
10
- import figlet from "figlet";
11
10
 
12
11
  // src/utils/config.ts
13
12
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -2304,6 +2303,7 @@ var PermissionManager = class {
2304
2303
  elevatedCommands = /* @__PURE__ */ new Set();
2305
2304
  pendingApprovals = /* @__PURE__ */ new Set();
2306
2305
  currentChannelType = "cli";
2306
+ tempScopes = [];
2307
2307
  constructor() {
2308
2308
  this.cwd = process.cwd();
2309
2309
  this.manifest = this.load();
@@ -2394,12 +2394,18 @@ var PermissionManager = class {
2394
2394
  }
2395
2395
  const resolved = resolve(path3);
2396
2396
  const scope = this.findScope(resolved);
2397
+ const tempScope = this.findTempScope(resolved);
2397
2398
  if (scope) {
2398
2399
  if (mode === "read" && scope.read) return { allowed: true };
2399
2400
  if (mode === "write" && scope.write) return { allowed: true };
2400
2401
  return { allowed: false, reason: `Permission denied: ${mode} access to ${path3} (scope has ${mode}=false)` };
2401
2402
  }
2402
- return await this.requestScope(resolved, mode);
2403
+ if (tempScope) {
2404
+ if (mode === "read" && tempScope.read) return { allowed: true };
2405
+ if (mode === "write" && tempScope.write) return { allowed: true };
2406
+ return { allowed: false, reason: `Permission denied: ${mode} access to ${path3}` };
2407
+ }
2408
+ return { allowed: false, reason: `Permission denied for ${mode} access to ${path3}` };
2403
2409
  }
2404
2410
  async checkShellCommand(command) {
2405
2411
  if (this.autoApproveAll) {
@@ -2430,7 +2436,7 @@ var PermissionManager = class {
2430
2436
  if (hasPathTraversal) {
2431
2437
  const scopeCheck = await this.checkFsAccess(hasPathTraversal, "write");
2432
2438
  if (!scopeCheck.allowed) {
2433
- return { allowed: false, reason: scopeCheck.reason, needsApproval: true };
2439
+ return { allowed: false, reason: `No permission to access ${hasPathTraversal}. Use approve_scope tool with path="${hasPathTraversal}" and mode="write" to request access.`, needsApproval: false };
2434
2440
  }
2435
2441
  }
2436
2442
  }
@@ -2502,9 +2508,6 @@ var PermissionManager = class {
2502
2508
  return void 0;
2503
2509
  }
2504
2510
  async requestScopeExternal(path3, mode) {
2505
- return this.requestScope(path3, mode);
2506
- }
2507
- async requestScope(path3, mode) {
2508
2511
  if (!this.askHandler) {
2509
2512
  return { allowed: false, reason: `Permission denied for ${mode} access to ${path3}` };
2510
2513
  }
@@ -2517,11 +2520,26 @@ Allow access?`;
2517
2520
  this.addScope(path3, mode === "read", mode === "write");
2518
2521
  return { allowed: true };
2519
2522
  }
2520
- if (response === "yes" || response === "y") {
2523
+ if (response === "yes") {
2524
+ this.addTempScope(path3, mode === "read", mode === "write");
2521
2525
  return { allowed: true };
2522
2526
  }
2523
2527
  return { allowed: false, reason: `Permission denied for ${mode} access to ${path3}` };
2524
2528
  }
2529
+ addTempScope(path3, read, write) {
2530
+ const resolved = resolve(path3);
2531
+ this.tempScopes.push({ path: resolved, read, write });
2532
+ logger.info({ path: resolved, read, write }, "Temp permission scope added (session only)");
2533
+ }
2534
+ findTempScope(resolvedPath) {
2535
+ for (const scope of this.tempScopes) {
2536
+ const scopeResolved = resolve(scope.path.replace(/^~/, homedir2()));
2537
+ if (resolvedPath === scopeResolved || resolvedPath.startsWith(scopeResolved + sep)) {
2538
+ return scope;
2539
+ }
2540
+ }
2541
+ return void 0;
2542
+ }
2525
2543
  matchPattern(command, pattern) {
2526
2544
  const regexStr = "^" + pattern.replace(/\*/g, ".*").replace(/\?/g, ".") + "$";
2527
2545
  try {
@@ -2861,18 +2879,18 @@ import { z as z8 } from "zod";
2861
2879
  import { resolve as resolve9 } from "path";
2862
2880
  function createApproveScopeTool(permissions) {
2863
2881
  return tool8({
2864
- description: "Request user approval to add a directory to the allowed filesystem scopes. Use this when a file operation fails due to scope permissions. The user will see an approval prompt (inline keyboard on Telegram, readline on CLI). If approved, the scope is added permanently.",
2882
+ description: 'Request user approval to access a directory outside current scopes. Use this when a file tool returns a permission denied error. The user gets an approval prompt (Allow/Always/Deny buttons on Telegram, yes/always/no on CLI). "Allow" grants session-only access. "Always" persists to disk. After approval, retry the original file operation.',
2865
2883
  parameters: z8.object({
2866
- path: z8.string().describe("The directory path to add to allowed scopes"),
2884
+ path: z8.string().describe("The directory path to request access to"),
2867
2885
  mode: z8.enum(["read", "write"]).describe("The access mode needed")
2868
2886
  }),
2869
2887
  execute: async ({ path: path3, mode }) => {
2870
2888
  const resolved = resolve9(path3);
2871
2889
  const result = await permissions.requestScopeExternal(resolved, mode);
2872
2890
  if (result.allowed) {
2873
- return `Access approved for ${mode} access to ${resolved}`;
2891
+ return `Access approved for ${mode} access to ${resolved}. You can now retry the file operation.`;
2874
2892
  }
2875
- return `Access denied for ${mode} access to ${resolved}`;
2893
+ return `Access denied for ${mode} access to ${resolved}. The user did not approve scope access.`;
2876
2894
  }
2877
2895
  });
2878
2896
  }
@@ -4300,11 +4318,17 @@ var pkgVersion = JSON.parse(readFileSync12(join11(__dirname, "..", "package.json
4300
4318
  function hr() {
4301
4319
  console.log(chalk6.dim("\u2500".repeat(50)));
4302
4320
  }
4321
+ var MERCURY_ASCII = [
4322
+ " __ _____________ ________ ________ __",
4323
+ " / |/ / ____/ __ \\/ ____/ / / / __ \\/ < /",
4324
+ " / /|_/ / __/ / /_/ / / / / / / /_/ /\\ / ",
4325
+ " / / / / /___/ _, _/ /___/ /_/ / _, _/ / / ",
4326
+ "/_/ /_/_____/_/ |_|\\____/\\____/_/ |_| /_/ "
4327
+ ].filter((l) => l.trim());
4303
4328
  function banner() {
4304
4329
  console.log("");
4305
- const art = figlet.textSync("MERCURY", { font: "Slant", horizontalLayout: "default" });
4306
- for (const line of art.split("\n")) {
4307
- if (line.trim()) console.log(chalk6.bold.cyan(` ${line}`));
4330
+ for (const line of MERCURY_ASCII) {
4331
+ console.log(chalk6.bold.cyan(` ${line}`));
4308
4332
  }
4309
4333
  console.log("");
4310
4334
  console.log(chalk6.white(" an AI agent for personal tasks"));
@@ -4313,9 +4337,8 @@ function banner() {
4313
4337
  }
4314
4338
  function splashScreen() {
4315
4339
  console.log("");
4316
- const art = figlet.textSync("MERCURY", { font: "Slant", horizontalLayout: "default" });
4317
- for (const line of art.split("\n")) {
4318
- if (line.trim()) console.log(chalk6.bold.cyan(` ${line}`));
4340
+ for (const line of MERCURY_ASCII) {
4341
+ console.log(chalk6.bold.cyan(` ${line}`));
4319
4342
  }
4320
4343
  console.log("");
4321
4344
  console.log(chalk6.dim(" an AI agent for personal tasks"));