@poe-platform/safe-bash 0.1.610 → 0.1.611

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.
@@ -27194,6 +27194,188 @@ async function publishZip(scope, prepared) {
27194
27194
  if (failure) throw failure.reason;
27195
27195
  }
27196
27196
 
27197
+ // packages/safe-bash/src/commands/archive/unzip/arguments.ts
27198
+ init_platform();
27199
+ function parseArguments(context2, limits) {
27200
+ const { args } = context2;
27201
+ let bytes3 = 0;
27202
+ for (const argument2 of args) {
27203
+ bytes3 += import_buffer.Buffer.byteLength(argument2) + 1;
27204
+ if (bytes3 > limits.maxArgumentBytes) fail("argument byte limit exceeded");
27205
+ if (argument2.includes("\0")) fail("NUL in argument");
27206
+ }
27207
+ if (context2.argumentValues) {
27208
+ const argumentsValue = getCommandArguments(context2);
27209
+ let rawBytes = 0;
27210
+ for (const value2 of argumentsValue.values) {
27211
+ const size = shellValueByteLength(value2) + 1;
27212
+ if (size > limits.maxArgumentBytes - rawBytes) fail("argument byte limit exceeded");
27213
+ rawBytes += size;
27214
+ }
27215
+ for (const value2 of argumentsValue.values) text2(shellValueBytes(value2));
27216
+ }
27217
+ let list = false;
27218
+ let pipe = false;
27219
+ let overwrite = false;
27220
+ let destination2;
27221
+ let archive;
27222
+ let ended = false;
27223
+ const patterns2 = [];
27224
+ for (let index = 0; index < args.length; index++) {
27225
+ const argument2 = args[index];
27226
+ if (!ended && argument2 === "--") {
27227
+ ended = true;
27228
+ continue;
27229
+ }
27230
+ if (!ended && argument2.startsWith("-") && argument2 !== "-") {
27231
+ for (let offset = 1; offset < argument2.length; offset++) {
27232
+ const flag = argument2[offset];
27233
+ if (flag === "l") list = true;
27234
+ else if (flag === "p") pipe = true;
27235
+ else if (flag === "o") overwrite = true;
27236
+ else if (flag === "d") {
27237
+ if (destination2 !== void 0) fail("-d may only be specified once");
27238
+ destination2 = argument2.slice(offset + 1) || args[++index];
27239
+ if (!destination2) fail("must specify directory to which to extract with -d option");
27240
+ checkPath(destination2, limits);
27241
+ break;
27242
+ } else fail(`unsupported option: -${flag}`);
27243
+ }
27244
+ } else if (archive === void 0) archive = argument2;
27245
+ else patterns2.push(argument2);
27246
+ }
27247
+ if (archive === void 0) fail("usage: unzip [-l] [-p] [-o] [-d DIR] ARCHIVE [FILES...]");
27248
+ checkPath(archive, limits);
27249
+ return { list: list && !pipe, pipe, overwrite, destination: destination2, archive, patterns: patterns2 };
27250
+ }
27251
+ function tokenize2(pattern) {
27252
+ const characters = Array.from(pattern);
27253
+ const tokens2 = [];
27254
+ for (let index = 0; index < characters.length; index++) {
27255
+ const character = characters[index];
27256
+ if (character === "*") {
27257
+ if (tokens2.at(-1)?.kind !== "star") tokens2.push({ kind: "star" });
27258
+ } else if (character === "?") tokens2.push({ kind: "any" });
27259
+ else if (character === "\\") {
27260
+ const escaped3 = characters[++index];
27261
+ tokens2.push(escaped3 === void 0 ? { kind: "never" } : { kind: "literal", value: escaped3 });
27262
+ } else if (character === "[") {
27263
+ const negative = characters[index + 1] === "!" || characters[index + 1] === "^";
27264
+ if (negative) index++;
27265
+ const ranges = [];
27266
+ let closed = false;
27267
+ while (++index < characters.length) {
27268
+ let first = characters[index];
27269
+ if (first === "]") {
27270
+ closed = true;
27271
+ break;
27272
+ }
27273
+ if (first === "\\") first = characters[++index] ?? "";
27274
+ let last = first;
27275
+ if (characters[index + 1] === "-" && characters[index + 2] && characters[index + 2] !== "]") {
27276
+ index += 2;
27277
+ last = characters[index];
27278
+ if (last === "\\") last = characters[++index] ?? "";
27279
+ }
27280
+ ranges.push([first.codePointAt(0) ?? -1, last.codePointAt(0) ?? -1]);
27281
+ }
27282
+ tokens2.push(closed ? { kind: "class", ranges, negative } : { kind: "never" });
27283
+ } else tokens2.push({ kind: "literal", value: character });
27284
+ }
27285
+ return tokens2;
27286
+ }
27287
+ var Selection = class {
27288
+ constructor(patterns2, limits, signal) {
27289
+ this.limits = limits;
27290
+ this.signal = signal;
27291
+ this.patterns = patterns2.map(tokenize2);
27292
+ }
27293
+ limits;
27294
+ signal;
27295
+ work = 0;
27296
+ patterns;
27297
+ matched = /* @__PURE__ */ new Set();
27298
+ step() {
27299
+ if (++this.work > this.limits.maxPatternSteps) fail("pattern work limit exceeded");
27300
+ }
27301
+ async matches(name2, firstMatchOnly = false) {
27302
+ if (!this.patterns.length) return true;
27303
+ const characters = Array.from(name2);
27304
+ let selected = false;
27305
+ for (let pattern = 0; pattern < this.patterns.length; pattern++) {
27306
+ this.step();
27307
+ let states = new Uint8Array(characters.length + 1);
27308
+ states[0] = 1;
27309
+ for (const token of this.patterns[pattern]) {
27310
+ const next = new Uint8Array(states.length);
27311
+ for (let index = 0; index < states.length; index++) {
27312
+ this.step();
27313
+ if (token.kind === "star") next[index] = states[index] || (index > 0 ? next[index - 1] : 0);
27314
+ else if (states[index] && index < characters.length) {
27315
+ const character = characters[index];
27316
+ let match = token.kind === "any" || token.kind === "literal" && token.value === character;
27317
+ if (token.kind === "class") {
27318
+ let inRange = false;
27319
+ for (const [first, last] of token.ranges) {
27320
+ this.step();
27321
+ if (character.codePointAt(0) >= first && character.codePointAt(0) <= last) inRange = true;
27322
+ }
27323
+ match = inRange !== token.negative;
27324
+ }
27325
+ if (match) next[index + 1] = 1;
27326
+ }
27327
+ if (this.work % 4096 === 0) await yieldTurn(this.signal);
27328
+ }
27329
+ states = next;
27330
+ }
27331
+ if (states[characters.length]) {
27332
+ this.matched.add(pattern);
27333
+ if (firstMatchOnly) return true;
27334
+ selected = true;
27335
+ }
27336
+ }
27337
+ return selected;
27338
+ }
27339
+ };
27340
+ var Answers = class {
27341
+ constructor(source2, limits, signal) {
27342
+ this.limits = limits;
27343
+ this.signal = signal;
27344
+ this.iterator = readBytes(source2, signal)[Symbol.asyncIterator]();
27345
+ }
27346
+ limits;
27347
+ signal;
27348
+ iterator;
27349
+ chunk = new Uint8Array();
27350
+ offset = 0;
27351
+ bytes = 0;
27352
+ pulls = 0;
27353
+ async read(maximum = 9) {
27354
+ const answer = [];
27355
+ while (answer.length < maximum) {
27356
+ this.signal.throwIfAborted();
27357
+ if (this.offset === this.chunk.length) {
27358
+ if (++this.pulls > this.limits.maxPatternSteps) fail("overwrite input work limit exceeded");
27359
+ if (this.pulls % 64 === 0) await yieldTurn(this.signal);
27360
+ const next = await this.iterator.next();
27361
+ if (next.done) break;
27362
+ if (next.value.length > this.limits.maxFilesFromBytes - this.bytes) fail("overwrite input byte limit exceeded");
27363
+ this.bytes += next.value.length;
27364
+ this.chunk = Uint8Array.from(next.value);
27365
+ this.offset = 0;
27366
+ if (!this.chunk.length) continue;
27367
+ }
27368
+ const byte = this.chunk[this.offset++];
27369
+ answer.push(byte);
27370
+ if (byte === 10) break;
27371
+ }
27372
+ return answer.length ? import_buffer.Buffer.from(answer).toString("utf8") : void 0;
27373
+ }
27374
+ async close() {
27375
+ await this.iterator.return?.();
27376
+ }
27377
+ };
27378
+
27197
27379
  // packages/safe-bash/src/commands/archive/zip.ts
27198
27380
  var ZipFailure = class extends Error {
27199
27381
  constructor(status2, label, detail) {
@@ -27229,17 +27411,42 @@ function parse12(context2, limits) {
27229
27411
  let literal = false;
27230
27412
  let firstOperand = -1;
27231
27413
  const operands = [];
27232
- for (const [index, argument2] of context2.args.entries()) {
27414
+ const includes = [];
27415
+ const excludes = [];
27416
+ for (let index = 0; index < context2.args.length; index++) {
27417
+ const argument2 = context2.args[index];
27233
27418
  checkPath(argument2, limits);
27234
27419
  if (!literal && argument2 === "--") {
27235
27420
  if (archive === void 0) throw new ZipFailure(16, "Invalid command arguments", "can't use -- before archive name");
27236
27421
  literal = true;
27237
27422
  } else if (!literal && argument2.startsWith("-") && argument2 !== "-") {
27238
- for (const flag of argument2.slice(1)) {
27423
+ for (let offset = 1; offset < argument2.length; offset++) {
27424
+ const flag = argument2[offset];
27239
27425
  if (flag === "r") recursive = true;
27240
27426
  else if (flag === "q") quiet = true;
27241
27427
  else if (flag === "j") junkPaths = true;
27242
- else throw new ZipFailure(16, "Invalid command arguments", `unsupported option: ${argument2}`);
27428
+ else if (flag === "i" || flag === "x") {
27429
+ const patterns2 = flag === "i" ? includes : excludes;
27430
+ const before = patterns2.length;
27431
+ const append = (pattern) => {
27432
+ checkPath(pattern, limits);
27433
+ if (includes.length + excludes.length >= limits.maxMembers) fail("pattern count limit exceeded");
27434
+ patterns2.push(pattern);
27435
+ };
27436
+ if (offset + 1 < argument2.length) append(argument2.slice(offset + 1));
27437
+ while (index + 1 < context2.args.length) {
27438
+ const next = context2.args[index + 1];
27439
+ if (next === "@") {
27440
+ index++;
27441
+ break;
27442
+ }
27443
+ if (next.startsWith("-") && next !== "-") break;
27444
+ append(next);
27445
+ index++;
27446
+ }
27447
+ if (patterns2.length === before) throw new ZipFailure(16, "Invalid command arguments", `option '${flag}' requires a value`);
27448
+ break;
27449
+ } else throw new ZipFailure(16, "Invalid command arguments", `unsupported option: ${argument2}`);
27243
27450
  }
27244
27451
  } else if (archive === void 0) archive = argument2;
27245
27452
  else {
@@ -27252,7 +27459,7 @@ function parse12(context2, limits) {
27252
27459
  if (archive === "-" || operands.includes("-")) throw new ZipFailure(16, "Invalid command arguments", "standard input/output archives are unsupported");
27253
27460
  if (!archive.slice(archive.lastIndexOf("/") + 1).includes(".")) archive += ".zip";
27254
27461
  checkPath(archive, limits);
27255
- return { archive, recursive, quiet, junkPaths, operands, firstOperand };
27462
+ return { archive, recursive, quiet, junkPaths, includes, excludes, operands, firstOperand };
27256
27463
  }
27257
27464
  function memberName(path, limits) {
27258
27465
  if (path.startsWith("//") && !path.startsWith("///")) fail("UNC source paths are unsupported");
@@ -27289,6 +27496,7 @@ async function prepare(scope, parsed, budget) {
27289
27496
  }
27290
27497
  const old = new Map(archive.entries.map((entry) => [entry.name, entry]));
27291
27498
  const selected = /* @__PURE__ */ new Map();
27499
+ const selection = new Selection([...parsed.includes, ...parsed.excludes], limits, context2.signal);
27292
27500
  const ancestors = [];
27293
27501
  let visits = 0;
27294
27502
  let work = 0;
@@ -27322,9 +27530,18 @@ async function prepare(scope, parsed, budget) {
27322
27530
  }
27323
27531
  if (existing2 && !hasIdentity(stat)) fail("cannot exclude archive aliases when source backing identity is unknown");
27324
27532
  const directory2 = stat.type === "directory";
27325
- if (parsed.junkPaths) name2 = directory2 ? "" : name2.slice(name2.lastIndexOf("/") + 1);
27326
27533
  if (directory2 && name2 && !name2.endsWith("/")) name2 += "/";
27327
- if (name2) {
27534
+ selection.matched.clear();
27535
+ await selection.matches(name2);
27536
+ let included = parsed.includes.length === 0;
27537
+ let excluded = false;
27538
+ for (const pattern of selection.matched) {
27539
+ if (pattern < parsed.includes.length) included = true;
27540
+ else excluded = true;
27541
+ }
27542
+ const sourceName = name2;
27543
+ if (parsed.junkPaths) name2 = directory2 ? "" : name2.slice(name2.lastIndexOf("/") + 1);
27544
+ if (name2 && included && !excluded) {
27328
27545
  checkPath(name2, limits);
27329
27546
  const previous = selected.get(name2);
27330
27547
  if (previous && previous.source !== source2) {
@@ -27359,7 +27576,7 @@ async function prepare(scope, parsed, budget) {
27359
27576
  for (const child of children) {
27360
27577
  if (!child.name || child.name === "." || child.name === ".." || child.name.includes("/") || child.name.includes("\0")) fail("invalid filesystem directory entry");
27361
27578
  const prefix3 = source2 === "." ? "" : source2.endsWith("/") ? source2 : `${source2}/`;
27362
- await visit(`${prefix3}${child.name}`, `${name2}${child.name}`, depth + 1);
27579
+ await visit(`${prefix3}${child.name}`, `${sourceName}${child.name}`, depth + 1);
27363
27580
  }
27364
27581
  } finally {
27365
27582
  ancestors.pop();
@@ -27367,7 +27584,7 @@ async function prepare(scope, parsed, budget) {
27367
27584
  }
27368
27585
  };
27369
27586
  for (const operand of parsed.operands) await visit(operand, memberName(operand, limits), 0);
27370
- if (!selected.size) {
27587
+ if (!selected.size && !parsed.includes.length) {
27371
27588
  const detail = parsed.recursive && parsed.firstOperand >= 0 ? `try: zip ${context2.args.slice(0, parsed.firstOperand).join(" ")} . -i ${context2.args.slice(parsed.firstOperand).join(" ")}` : parsed.archive;
27372
27589
  throw new ZipFailure(12, "Nothing to do!", detail);
27373
27590
  }
@@ -27400,6 +27617,7 @@ async function prepare(scope, parsed, budget) {
27400
27617
  entries2.push(entry);
27401
27618
  append(entry, false);
27402
27619
  }
27620
+ if (!entries2.length && !parsed.quiet) await budget.output(" zip warning: zip file empty\n");
27403
27621
  const bytes3 = await writeZipArchive({ entries: entries2, comment: archive.comment }, limits, context2.signal);
27404
27622
  return { output: output2, parentName, parent, parentStat, existing: existing2, bytes: bytes3, progress };
27405
27623
  }
@@ -27442,188 +27660,6 @@ zip error: ${error.label} (${error.message})
27442
27660
  // packages/safe-bash/src/commands/archive/unzip.ts
27443
27661
  init_platform();
27444
27662
 
27445
- // packages/safe-bash/src/commands/archive/unzip/arguments.ts
27446
- init_platform();
27447
- function parseArguments(context2, limits) {
27448
- const { args } = context2;
27449
- let bytes3 = 0;
27450
- for (const argument2 of args) {
27451
- bytes3 += import_buffer.Buffer.byteLength(argument2) + 1;
27452
- if (bytes3 > limits.maxArgumentBytes) fail("argument byte limit exceeded");
27453
- if (argument2.includes("\0")) fail("NUL in argument");
27454
- }
27455
- if (context2.argumentValues) {
27456
- const argumentsValue = getCommandArguments(context2);
27457
- let rawBytes = 0;
27458
- for (const value2 of argumentsValue.values) {
27459
- const size = shellValueByteLength(value2) + 1;
27460
- if (size > limits.maxArgumentBytes - rawBytes) fail("argument byte limit exceeded");
27461
- rawBytes += size;
27462
- }
27463
- for (const value2 of argumentsValue.values) text2(shellValueBytes(value2));
27464
- }
27465
- let list = false;
27466
- let pipe = false;
27467
- let overwrite = false;
27468
- let destination2;
27469
- let archive;
27470
- let ended = false;
27471
- const patterns2 = [];
27472
- for (let index = 0; index < args.length; index++) {
27473
- const argument2 = args[index];
27474
- if (!ended && argument2 === "--") {
27475
- ended = true;
27476
- continue;
27477
- }
27478
- if (!ended && argument2.startsWith("-") && argument2 !== "-") {
27479
- for (let offset = 1; offset < argument2.length; offset++) {
27480
- const flag = argument2[offset];
27481
- if (flag === "l") list = true;
27482
- else if (flag === "p") pipe = true;
27483
- else if (flag === "o") overwrite = true;
27484
- else if (flag === "d") {
27485
- if (destination2 !== void 0) fail("-d may only be specified once");
27486
- destination2 = argument2.slice(offset + 1) || args[++index];
27487
- if (!destination2) fail("must specify directory to which to extract with -d option");
27488
- checkPath(destination2, limits);
27489
- break;
27490
- } else fail(`unsupported option: -${flag}`);
27491
- }
27492
- } else if (archive === void 0) archive = argument2;
27493
- else patterns2.push(argument2);
27494
- }
27495
- if (archive === void 0) fail("usage: unzip [-l] [-p] [-o] [-d DIR] ARCHIVE [FILES...]");
27496
- checkPath(archive, limits);
27497
- return { list: list && !pipe, pipe, overwrite, destination: destination2, archive, patterns: patterns2 };
27498
- }
27499
- function tokenize2(pattern) {
27500
- const characters = Array.from(pattern);
27501
- const tokens2 = [];
27502
- for (let index = 0; index < characters.length; index++) {
27503
- const character = characters[index];
27504
- if (character === "*") {
27505
- if (tokens2.at(-1)?.kind !== "star") tokens2.push({ kind: "star" });
27506
- } else if (character === "?") tokens2.push({ kind: "any" });
27507
- else if (character === "\\") {
27508
- const escaped3 = characters[++index];
27509
- tokens2.push(escaped3 === void 0 ? { kind: "never" } : { kind: "literal", value: escaped3 });
27510
- } else if (character === "[") {
27511
- const negative = characters[index + 1] === "!" || characters[index + 1] === "^";
27512
- if (negative) index++;
27513
- const ranges = [];
27514
- let closed = false;
27515
- while (++index < characters.length) {
27516
- let first = characters[index];
27517
- if (first === "]") {
27518
- closed = true;
27519
- break;
27520
- }
27521
- if (first === "\\") first = characters[++index] ?? "";
27522
- let last = first;
27523
- if (characters[index + 1] === "-" && characters[index + 2] && characters[index + 2] !== "]") {
27524
- index += 2;
27525
- last = characters[index];
27526
- if (last === "\\") last = characters[++index] ?? "";
27527
- }
27528
- ranges.push([first.codePointAt(0) ?? -1, last.codePointAt(0) ?? -1]);
27529
- }
27530
- tokens2.push(closed ? { kind: "class", ranges, negative } : { kind: "never" });
27531
- } else tokens2.push({ kind: "literal", value: character });
27532
- }
27533
- return tokens2;
27534
- }
27535
- var Selection = class {
27536
- constructor(patterns2, limits, signal) {
27537
- this.limits = limits;
27538
- this.signal = signal;
27539
- this.patterns = patterns2.map(tokenize2);
27540
- }
27541
- limits;
27542
- signal;
27543
- work = 0;
27544
- patterns;
27545
- matched = /* @__PURE__ */ new Set();
27546
- step() {
27547
- if (++this.work > this.limits.maxPatternSteps) fail("pattern work limit exceeded");
27548
- }
27549
- async matches(name2, firstMatchOnly = false) {
27550
- if (!this.patterns.length) return true;
27551
- const characters = Array.from(name2);
27552
- let selected = false;
27553
- for (let pattern = 0; pattern < this.patterns.length; pattern++) {
27554
- this.step();
27555
- let states = new Uint8Array(characters.length + 1);
27556
- states[0] = 1;
27557
- for (const token of this.patterns[pattern]) {
27558
- const next = new Uint8Array(states.length);
27559
- for (let index = 0; index < states.length; index++) {
27560
- this.step();
27561
- if (token.kind === "star") next[index] = states[index] || (index > 0 ? next[index - 1] : 0);
27562
- else if (states[index] && index < characters.length) {
27563
- const character = characters[index];
27564
- let match = token.kind === "any" || token.kind === "literal" && token.value === character;
27565
- if (token.kind === "class") {
27566
- let inRange = false;
27567
- for (const [first, last] of token.ranges) {
27568
- this.step();
27569
- if (character.codePointAt(0) >= first && character.codePointAt(0) <= last) inRange = true;
27570
- }
27571
- match = inRange !== token.negative;
27572
- }
27573
- if (match) next[index + 1] = 1;
27574
- }
27575
- if (this.work % 4096 === 0) await yieldTurn(this.signal);
27576
- }
27577
- states = next;
27578
- }
27579
- if (states[characters.length]) {
27580
- this.matched.add(pattern);
27581
- if (firstMatchOnly) return true;
27582
- selected = true;
27583
- }
27584
- }
27585
- return selected;
27586
- }
27587
- };
27588
- var Answers = class {
27589
- constructor(source2, limits, signal) {
27590
- this.limits = limits;
27591
- this.signal = signal;
27592
- this.iterator = readBytes(source2, signal)[Symbol.asyncIterator]();
27593
- }
27594
- limits;
27595
- signal;
27596
- iterator;
27597
- chunk = new Uint8Array();
27598
- offset = 0;
27599
- bytes = 0;
27600
- pulls = 0;
27601
- async read(maximum = 9) {
27602
- const answer = [];
27603
- while (answer.length < maximum) {
27604
- this.signal.throwIfAborted();
27605
- if (this.offset === this.chunk.length) {
27606
- if (++this.pulls > this.limits.maxPatternSteps) fail("overwrite input work limit exceeded");
27607
- if (this.pulls % 64 === 0) await yieldTurn(this.signal);
27608
- const next = await this.iterator.next();
27609
- if (next.done) break;
27610
- if (next.value.length > this.limits.maxFilesFromBytes - this.bytes) fail("overwrite input byte limit exceeded");
27611
- this.bytes += next.value.length;
27612
- this.chunk = Uint8Array.from(next.value);
27613
- this.offset = 0;
27614
- if (!this.chunk.length) continue;
27615
- }
27616
- const byte = this.chunk[this.offset++];
27617
- answer.push(byte);
27618
- if (byte === 10) break;
27619
- }
27620
- return answer.length ? import_buffer.Buffer.from(answer).toString("utf8") : void 0;
27621
- }
27622
- async close() {
27623
- await this.iterator.return?.();
27624
- }
27625
- };
27626
-
27627
27663
  // packages/safe-bash/src/commands/archive/unzip/safety.ts
27628
27664
  init_platform();
27629
27665
  import { retainFileSystemCleanup as retainFileSystemCleanup3 } from "@poe-platform/safe-fs/core";