@poe-platform/safe-bash 0.1.70 → 0.1.71

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.
@@ -14,7 +14,8 @@ export { portableSearchCommands, type PortableSearchOptions } from "./commands/s
14
14
  export * from "./commands/regex-execution/public.js";
15
15
  export interface BrowserCommandsOptions {
16
16
  readonly replace?: boolean;
17
+ readonly maxDirectoryEntries?: number;
17
18
  }
18
- export declare function createBrowserCommands(): readonly CommandDefinition[];
19
+ export declare function createBrowserCommands(options?: BrowserCommandsOptions): readonly CommandDefinition[];
19
20
  export declare function browserCommands(options?: BrowserCommandsOptions): VirtualShellPlugin;
20
21
  //# sourceMappingURL=browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAOlF,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACjG,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACnG,cAAc,sCAAsC,CAAC;AAErD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,qBAAqB,IAAI,SAAS,iBAAiB,EAAE,CAKpE;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,kBAAkB,CAaxF"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAOlF,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACjG,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACnG,cAAc,sCAAsC,CAAC;AAErD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,SAAS,iBAAiB,EAAE,CAKxG;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,kBAAkB,CAaxF"}
@@ -3405,6 +3405,32 @@ async function moveAcrossDevices(context, source, target, noClobber, budget) {
3405
3405
  return true;
3406
3406
  }
3407
3407
 
3408
+ // packages/safe-bash/src/commands/directory-admission.ts
3409
+ init_platform();
3410
+ function createDirectoryReader(maxEntries = 1e4) {
3411
+ if (!Number.isSafeInteger(maxEntries) || maxEntries < 0) {
3412
+ throw new RangeError("maxDirectoryEntries must be a nonnegative safe integer");
3413
+ }
3414
+ return async (context, path, ordered = false) => {
3415
+ context.signal.throwIfAborted();
3416
+ const entries = await context.fs.readdir(path, { signal: context.signal, maxEntries });
3417
+ context.signal.throwIfAborted();
3418
+ if (entries.length > maxEntries) {
3419
+ throw new FsError("EFBIG", { syscall: "readdir", path, message: "directory entry limit exceeded" });
3420
+ }
3421
+ await yieldTurn(context.signal);
3422
+ if (ordered) {
3423
+ for (let index = 1; index < entries.length; index++) {
3424
+ if (index % 256 === 0) await yieldTurn(context.signal);
3425
+ if (entries[index - 1].name > entries[index].name) {
3426
+ return entries.slice().sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
3427
+ }
3428
+ }
3429
+ }
3430
+ return entries;
3431
+ };
3432
+ }
3433
+
3408
3434
  // packages/safe-bash/src/commands/filesystem.ts
3409
3435
  async function preflightOperands(context, operands, check) {
3410
3436
  for (const operand of operands) {
@@ -3441,22 +3467,22 @@ function needCapability(context, capability) {
3441
3467
  if (!context.fs.capabilitiesFor && context.fs.capabilities[declaration] === false) throw new FsError("ENOTSUP", { syscall: capability });
3442
3468
  if (!context.fs[capability]) throw new FsError("ENOTSUP", { syscall: capability });
3443
3469
  }
3444
- async function admitEmptyDirectory(context, path) {
3470
+ async function admitEmptyDirectory(context, path, readDirectory) {
3445
3471
  try {
3446
3472
  await admitFilesystemModes(context, "rmdir", ["directory"], [path]);
3447
3473
  } catch (error) {
3448
3474
  context.signal.throwIfAborted();
3449
3475
  if (codeOf(error) === "ENOTSUP") {
3450
3476
  const capabilities = await context.fs.capabilitiesFor?.(path, { signal: context.signal }) ?? context.fs.capabilities;
3451
- if (capabilities.write !== false && capabilities.readdir !== false && (await context.fs.readdir(path, { signal: context.signal })).length) {
3477
+ if (capabilities.write !== false && capabilities.readdir !== false && (await readDirectory(context, path)).length) {
3452
3478
  throw new FsError("ENOTEMPTY", { syscall: "rmdir", path, cause: error });
3453
3479
  }
3454
3480
  }
3455
3481
  throw error;
3456
3482
  }
3457
3483
  }
3458
- async function removeEmptyDirectory(context, path) {
3459
- await admitEmptyDirectory(context, path);
3484
+ async function removeEmptyDirectory(context, path, readDirectory) {
3485
+ await admitEmptyDirectory(context, path, readDirectory);
3460
3486
  context.signal.throwIfAborted();
3461
3487
  if (!context.fs.rmdir) throw new FsError("ENOTSUP", { syscall: "rmdir", path });
3462
3488
  await context.fs.rmdir(path, { signal: context.signal });
@@ -3468,7 +3494,7 @@ async function destinations(context, operands) {
3468
3494
  if (operands.length > 2 && !directory) throw new FsError("ENOTDIR", { path: target });
3469
3495
  return { target, directory, sources: operands.slice(0, -1) };
3470
3496
  }
3471
- async function copy(context, source, target, flags, top = true, ancestors = /* @__PURE__ */ new Set(), preflight = false) {
3497
+ async function copy(context, source, target, flags, readDirectory, top = true, ancestors = /* @__PURE__ */ new Set(), preflight = false) {
3472
3498
  context.signal.throwIfAborted();
3473
3499
  const link = await context.fs.lstat(source, { signal: context.signal });
3474
3500
  const preserveLink = link.type === "symlink" && !flags.has("L") && (flags.has("P") || !top);
@@ -3491,8 +3517,8 @@ async function copy(context, source, target, flags, top = true, ancestors = /* @
3491
3517
  await admitFilesystemModes(context, "cp", ["recursive"], [target]);
3492
3518
  if (!targetStat && !preflight) await context.fs.mkdir(target, { mode: sourceStat.mode & 511, signal: context.signal });
3493
3519
  const next = new Set(ancestors).add(physicalSource);
3494
- for (const entry of (await context.fs.readdir(source, { signal: context.signal })).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)) {
3495
- await copy(context, joinPath(source, entry.name), joinPath(target, entry.name), flags, false, next, preflight);
3520
+ for (const entry of await readDirectory(context, source, true)) {
3521
+ await copy(context, joinPath(source, entry.name), joinPath(target, entry.name), flags, readDirectory, false, next, preflight);
3496
3522
  }
3497
3523
  } else if (preserveLink) {
3498
3524
  await admitFilesystemModes(context, "cp", ["symlink"], [target]);
@@ -3548,7 +3574,8 @@ function modeText(stat) {
3548
3574
  if (stat.mode & 512) text = text.slice(0, 9) + (stat.mode & 1 ? "t" : "T");
3549
3575
  return text;
3550
3576
  }
3551
- function filesystemCommands() {
3577
+ function filesystemCommands(maxDirectoryEntries) {
3578
+ const readDirectory = createDirectoryReader(maxDirectoryEntries);
3552
3579
  return [
3553
3580
  define("mkdir", async (context) => {
3554
3581
  const parsed = options(context.args, "pm:v", { parents: "p", mode: "m", verbose: "v" });
@@ -3613,6 +3640,7 @@ function filesystemCommands() {
3613
3640
  source,
3614
3641
  destination.directory ? joinPath(destination.target, basename(source)) : destination.target,
3615
3642
  parsed.flags,
3643
+ readDirectory,
3616
3644
  true,
3617
3645
  /* @__PURE__ */ new Set(),
3618
3646
  true
@@ -3620,7 +3648,7 @@ function filesystemCommands() {
3620
3648
  });
3621
3649
  return eachOperand(context, destination.sources, async (operand) => {
3622
3650
  const source = pathOf(context, operand);
3623
- await copy(context, source, destination.directory ? joinPath(destination.target, basename(source)) : destination.target, parsed.flags);
3651
+ await copy(context, source, destination.directory ? joinPath(destination.target, basename(source)) : destination.target, parsed.flags, readDirectory);
3624
3652
  });
3625
3653
  }),
3626
3654
  define("mv", async (context) => {
@@ -3659,7 +3687,7 @@ function filesystemCommands() {
3659
3687
  const stat = await maybeStat(context, path, false);
3660
3688
  if (!stat) return;
3661
3689
  const mode = stat.type === "directory" ? parsed.flags.has("r") || parsed.flags.has("R") ? "recursive" : "directory" : "file";
3662
- if (mode === "directory") await admitEmptyDirectory(context, path);
3690
+ if (mode === "directory") await admitEmptyDirectory(context, path, readDirectory);
3663
3691
  else await admitFilesystemModes(context, "rm", [mode], [path]);
3664
3692
  });
3665
3693
  return eachOperand(context, parsed.operands, async (operand) => {
@@ -3674,7 +3702,7 @@ function filesystemCommands() {
3674
3702
  if (stat.type === "directory" && !recursive && !parsed.flags.has("d")) throw new FsError("EISDIR", { path });
3675
3703
  if (stat.type === "directory" && !recursive) {
3676
3704
  try {
3677
- await removeEmptyDirectory(context, path);
3705
+ await removeEmptyDirectory(context, path, readDirectory);
3678
3706
  } catch (error) {
3679
3707
  context.signal.throwIfAborted();
3680
3708
  if (!parsed.flags.has("f") || codeOf(error) !== "ENOENT") throw error;
@@ -3693,7 +3721,7 @@ function filesystemCommands() {
3693
3721
  let path = pathOf(context, operand);
3694
3722
  const stop = dirname(pathOf(context, operand.split("/").find((part) => part && part !== ".") ?? operand));
3695
3723
  do {
3696
- await admitEmptyDirectory(context, path);
3724
+ await admitEmptyDirectory(context, path, readDirectory);
3697
3725
  path = dirname(path);
3698
3726
  } while (parsed.flags.has("p") && path !== "/" && path !== stop);
3699
3727
  });
@@ -3702,7 +3730,7 @@ function filesystemCommands() {
3702
3730
  const stop = dirname(pathOf(context, operand.split("/").find((part) => part && part !== ".") ?? operand));
3703
3731
  do {
3704
3732
  if (path === "/") throw new FsError("EBUSY", { path });
3705
- await removeEmptyDirectory(context, path);
3733
+ await removeEmptyDirectory(context, path, readDirectory);
3706
3734
  if (parsed.flags.has("v")) await output(context, `rmdir: removing directory '${path}'
3707
3735
  `);
3708
3736
  path = dirname(path);
@@ -3834,10 +3862,12 @@ function filesystemCommands() {
3834
3862
  `);
3835
3863
  headerWritten = true;
3836
3864
  }
3837
- const entries = await context.fs.readdir(path, { signal: context.signal });
3865
+ const entries = await readDirectory(context, path, true);
3838
3866
  const names = entries.map((entry) => entry.name).filter((name2) => parsed.flags.has("a") || parsed.flags.has("A") || !name2.startsWith("."));
3839
- if (parsed.flags.has("a")) names.push(".", "..");
3840
- names.sort();
3867
+ if (parsed.flags.has("a")) for (const name2 of [".", ".."]) {
3868
+ const index = names.findIndex((entry) => entry > name2);
3869
+ names.splice(index < 0 ? names.length : index, 0, name2);
3870
+ }
3841
3871
  if (parsed.flags.has("r")) names.reverse();
3842
3872
  for (const name2 of names) await render(joinPath(path, name2), name2);
3843
3873
  if (parsed.flags.has("R")) for (const name2 of names) {
@@ -18866,10 +18896,10 @@ function createBoundedRegexProvider(input3 = {}) {
18866
18896
  }
18867
18897
 
18868
18898
  // packages/safe-bash/src/browser.ts
18869
- function createBrowserCommands() {
18899
+ function createBrowserCommands(options3 = {}) {
18870
18900
  return [
18871
18901
  ...basicCommands(),
18872
- ...filesystemCommands(),
18902
+ ...filesystemCommands(options3.maxDirectoryEntries),
18873
18903
  ...predicateCommands(),
18874
18904
  ...streamCommands(),
18875
18905
  ...textCommands()
@@ -18879,7 +18909,7 @@ function browserCommands(options3 = {}) {
18879
18909
  return {
18880
18910
  name: "browser-commands",
18881
18911
  setup(host) {
18882
- const commands = createBrowserCommands();
18912
+ const commands = createBrowserCommands(options3);
18883
18913
  if (!options3.replace) {
18884
18914
  for (const command2 of commands) {
18885
18915
  if (host.commands.has(command2.name)) throw new Error(`Command already registered: ${command2.name}`);