@poe-platform/safe-bash 0.1.614 → 0.1.616

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.
@@ -3245,7 +3245,7 @@ async function parseEnvOptions(args, environment, signal, argumentValues) {
3245
3245
  const values = /* @__PURE__ */ new Map();
3246
3246
  const operands = [];
3247
3247
  const operandValues = [];
3248
- const longOptions = /* @__PURE__ */ new Map([
3248
+ const longOptions2 = /* @__PURE__ */ new Map([
3249
3249
  ["ignore-environment", "i"],
3250
3250
  ["unset", "u"],
3251
3251
  ["null", "0"],
@@ -3280,7 +3280,7 @@ async function parseEnvOptions(args, environment, signal, argumentValues) {
3280
3280
  if (argument2.startsWith("--")) {
3281
3281
  const equals = argument2.indexOf("=");
3282
3282
  const name2 = argument2.slice(2, equals < 0 ? void 0 : equals);
3283
- const key = longOptions.get(name2);
3283
+ const key = longOptions2.get(name2);
3284
3284
  if (!key) throw new UsageError(`unrecognized option '${argument2}'`);
3285
3285
  const required = key === "u" || key === "C" || key === "S";
3286
3286
  if (!required && equals >= 0) throw new UsageError(`option '--${name2}' does not take an argument`);
@@ -3555,11 +3555,11 @@ function executionCommands(execute4, configuration = {}) {
3555
3555
  const operandIndices = [];
3556
3556
  let replacementOrigin;
3557
3557
  const shortOptions = "0rn:s:I:d:tP:xE:";
3558
- const longOptions = { null: "0", "no-run-if-empty": "r", "max-args": "n", "max-chars": "s", replace: "I", delimiter: "d", verbose: "t", "max-procs": "P", exit: "x", eof: "E" };
3558
+ const longOptions2 = { null: "0", "no-run-if-empty": "r", "max-args": "n", "max-chars": "s", replace: "I", delimiter: "d", verbose: "t", "max-procs": "P", exit: "x", eof: "E" };
3559
3559
  const parsed = options(
3560
3560
  argumentValues.args,
3561
3561
  shortOptions,
3562
- longOptions,
3562
+ longOptions2,
3563
3563
  true,
3564
3564
  (index) => {
3565
3565
  operandIndices.push(index);
@@ -26729,7 +26729,8 @@ function entryBounds(entry, limits) {
26729
26729
  format(entry.method, entry.flags ?? 2048, entry.method === 8 || (entry.flags ?? 0) & 8 ? 20 : 10);
26730
26730
  if (entry.directory !== entry.name.endsWith("/") || entry.directory && (entry.symlink || entry.size !== 0)) fail("ZIP inconsistent directory metadata");
26731
26731
  const type = entry.mode & 61440;
26732
- if (type !== 0 && type !== (entry.directory ? 16384 : entry.symlink ? 40960 : 32768)) fail("ZIP unsupported or conflicting file type");
26732
+ const pipePayload = !entry.directory && !entry.symlink && type === 4096;
26733
+ if (type !== 0 && !pipePayload && type !== (entry.directory ? 16384 : entry.symlink ? 40960 : 32768)) fail("ZIP unsupported or conflicting file type");
26733
26734
  if (!Number.isFinite(entry.modified.getTime())) fail("ZIP invalid modification time");
26734
26735
  }
26735
26736
  async function copyBytes(source2, destination2, start, chunkSize2, signal) {
@@ -26896,7 +26897,7 @@ async function* decodeZipEntry(entry, limits, signal) {
26896
26897
  await reader.close();
26897
26898
  }
26898
26899
  }
26899
- async function makeZipEntry(name2, bytes3, attributes, limits, signal, level = 6) {
26900
+ async function makeZipEntry(name2, bytes3, attributes, limits, signal, level = 6, forceCompression = false) {
26900
26901
  const chunkSize2 = admit(limits, signal);
26901
26902
  const entry = { name: name2, data: bytes3, size: bytes3.length, method: 0, crc32: 0, ...attributes, modified: new Date(attributes.modified.getTime()) };
26902
26903
  entryBounds(entry, limits);
@@ -26908,15 +26909,16 @@ async function makeZipEntry(name2, bytes3, attributes, limits, signal, level = 6
26908
26909
  yield bytes3;
26909
26910
  })(), signal);
26910
26911
  try {
26911
- if (level !== 0 && bytes3.length && !entry.directory && !entry.symlink) {
26912
+ if (level !== 0 && (bytes3.length || forceCompression) && !entry.directory && !entry.symlink) {
26912
26913
  const chunks = [];
26913
26914
  let length = 0;
26914
26915
  for await (const chunk of codec(reader, { mode: "deflate-raw", chunkSize: chunkSize2, level }, signal)) {
26915
26916
  length += chunk.length;
26916
- if (length >= bytes3.length) break;
26917
+ if (length > limits.maxArchiveBytes) fail("ZIP compressed byte limit exceeded");
26918
+ if (!forceCompression && length >= bytes3.length) break;
26917
26919
  chunks.push(new Uint8Array(chunk));
26918
26920
  }
26919
- if (length < bytes3.length) {
26921
+ if (forceCompression || length < bytes3.length) {
26920
26922
  entry.data = new Uint8Array(length);
26921
26923
  let offset = 0;
26922
26924
  for (const chunk of chunks) {
@@ -26946,7 +26948,7 @@ function timestampExtra(modified) {
26946
26948
  view.setInt32(5, seconds, true);
26947
26949
  return bytes3;
26948
26950
  }
26949
- async function writeZipArchive(archive, limits, signal) {
26951
+ async function writeZipArchive(archive, limits, signal, descriptors = false) {
26950
26952
  const chunkSize2 = admit(limits, signal);
26951
26953
  number3(archive.entries.length, Math.min(limits.maxMembers, 65534), "member");
26952
26954
  number3(archive.comment.length, Math.min(limits.maxTextBytes, 65535), "archive comment");
@@ -26961,7 +26963,8 @@ async function writeZipArchive(archive, limits, signal) {
26961
26963
  total += entry.size;
26962
26964
  number3(total, limits.maxTotalBytes, "total byte");
26963
26965
  const rawName = entry.rawName ?? pathBytes(entry.name, limits);
26964
- const flags3 = (entry.flags ?? 2048) & ~8;
26966
+ const descriptor = descriptors && !entry.directory;
26967
+ const flags3 = (entry.flags ?? 2048) & ~8 | (descriptor ? 8 : 0);
26965
26968
  const comment2 = entry.comment ?? new Uint8Array();
26966
26969
  number3(comment2.length, Math.min(limits.maxTextBytes, 65535), "entry comment");
26967
26970
  if (flags3 & 2048) text2(comment2);
@@ -26989,8 +26992,8 @@ async function writeZipArchive(archive, limits, signal) {
26989
26992
  if (mode !== entry.mode || Boolean(entry.externalAttributes & 16) && !entry.directory) fail("ZIP retained file attributes mismatch");
26990
26993
  }
26991
26994
  encoded2.push({ entry, rawName, flags: flags3, localExtra, centralExtra, comment: comment2, date: date2, time, offset: localLength });
26992
- localLength += 30 + rawName.length + localExtra.length + entry.data.length;
26993
- length += 76 + 2 * rawName.length + localExtra.length + centralExtra.length + comment2.length + entry.data.length;
26995
+ localLength += 30 + rawName.length + localExtra.length + entry.data.length + (descriptor ? 16 : 0);
26996
+ length += 76 + 2 * rawName.length + localExtra.length + centralExtra.length + comment2.length + entry.data.length + (descriptor ? 16 : 0);
26994
26997
  number3(length, Math.min(limits.maxArchiveBytes, 4294967294), "archive byte");
26995
26998
  }
26996
26999
  number3(length, Math.min(limits.maxArchiveBytes, 4294967294), "archive byte");
@@ -27000,21 +27003,28 @@ async function writeZipArchive(archive, limits, signal) {
27000
27003
  for (const item of encoded2) {
27001
27004
  await yieldTurn(signal);
27002
27005
  const { entry, rawName, flags: flags3, localExtra, centralExtra, comment: comment2, date: date2, time, offset } = item;
27003
- const version = entry.method === 8 ? 20 : 10;
27006
+ const version = entry.method === 8 || flags3 & 8 ? 20 : 10;
27004
27007
  view.setUint32(offset, 67324752, true);
27005
27008
  view.setUint16(offset + 4, version, true);
27006
27009
  view.setUint16(offset + 6, flags3, true);
27007
27010
  view.setUint16(offset + 8, entry.method, true);
27008
27011
  view.setUint16(offset + 10, time, true);
27009
27012
  view.setUint16(offset + 12, date2, true);
27010
- view.setUint32(offset + 14, entry.crc32, true);
27011
- view.setUint32(offset + 18, entry.data.length, true);
27012
- view.setUint32(offset + 22, entry.size, true);
27013
+ view.setUint32(offset + 14, flags3 & 8 ? 0 : entry.crc32, true);
27014
+ view.setUint32(offset + 18, flags3 & 8 ? 0 : entry.data.length, true);
27015
+ view.setUint32(offset + 22, flags3 & 8 ? 0 : entry.size, true);
27013
27016
  view.setUint16(offset + 26, rawName.length, true);
27014
27017
  view.setUint16(offset + 28, localExtra.length, true);
27015
27018
  bytes3.set(rawName, offset + 30);
27016
27019
  bytes3.set(localExtra, offset + 30 + rawName.length);
27017
27020
  await copyBytes(entry.data, bytes3, offset + 30 + rawName.length + localExtra.length, chunkSize2, signal);
27021
+ if (flags3 & 8) {
27022
+ const descriptor = offset + 30 + rawName.length + localExtra.length + entry.data.length;
27023
+ view.setUint32(descriptor, 134695760, true);
27024
+ view.setUint32(descriptor + 4, entry.crc32, true);
27025
+ view.setUint32(descriptor + 8, entry.data.length, true);
27026
+ view.setUint32(descriptor + 12, entry.size, true);
27027
+ }
27018
27028
  view.setUint32(central, 33639248, true);
27019
27029
  view.setUint16(central + 4, entry.versionMadeBy ?? 798, true);
27020
27030
  view.setUint16(central + 6, version, true);
@@ -27029,7 +27039,8 @@ async function writeZipArchive(archive, limits, signal) {
27029
27039
  view.setUint16(central + 30, centralExtra.length, true);
27030
27040
  view.setUint16(central + 32, comment2.length, true);
27031
27041
  view.setUint16(central + 36, entry.internalAttributes ?? 0, true);
27032
- view.setUint32(central + 38, entry.externalAttributes ?? (entry.mode | (entry.directory ? 16384 : entry.symlink ? 40960 : 32768)) * 65536 + (entry.directory ? 16 : 0), true);
27042
+ const mode = entry.mode & 61440 ? entry.mode : entry.mode | (entry.directory ? 16384 : entry.symlink ? 40960 : 32768);
27043
+ view.setUint32(central + 38, entry.externalAttributes ?? mode * 65536 + (entry.directory ? 16 : 0), true);
27033
27044
  view.setUint32(central + 42, offset, true);
27034
27045
  bytes3.set(rawName, central + 46);
27035
27046
  bytes3.set(centralExtra, central + 46 + rawName.length);
@@ -27066,6 +27077,7 @@ var ZipScope = class {
27066
27077
  closedReason = new Error("ZIP command is closed");
27067
27078
  drain;
27068
27079
  work = 0;
27080
+ stdinSource;
27069
27081
  close = () => {
27070
27082
  if (!this.drain) {
27071
27083
  this.drain = Promise.resolve().then(async () => {
@@ -27104,6 +27116,9 @@ var ZipScope = class {
27104
27116
  throw error;
27105
27117
  }
27106
27118
  }
27119
+ get stdin() {
27120
+ return this.stdinSource ??= this.source(this.original.stdin);
27121
+ }
27107
27122
  source(source2) {
27108
27123
  const iterator = source2[Symbol.asyncIterator]();
27109
27124
  let closing;
@@ -27376,7 +27391,8 @@ var Answers = class {
27376
27391
  }
27377
27392
  };
27378
27393
 
27379
- // packages/safe-bash/src/commands/archive/zip.ts
27394
+ // packages/safe-bash/src/commands/archive/zip/options.ts
27395
+ init_platform();
27380
27396
  var ZipFailure = class extends Error {
27381
27397
  constructor(status2, label, detail) {
27382
27398
  super(detail);
@@ -27386,6 +27402,107 @@ var ZipFailure = class extends Error {
27386
27402
  status;
27387
27403
  label;
27388
27404
  };
27405
+ var longOptions = {
27406
+ "recurse-paths": "r",
27407
+ quiet: "q",
27408
+ "junk-paths": "j",
27409
+ "no-dir-entries": "D",
27410
+ symlinks: "y",
27411
+ test: "T",
27412
+ "names-stdin": "@",
27413
+ update: "u",
27414
+ freshen: "f",
27415
+ delete: "d",
27416
+ include: "i",
27417
+ exclude: "x",
27418
+ suffixes: "n",
27419
+ store: "0",
27420
+ "compression-method": "Z",
27421
+ "compress-1": "1",
27422
+ "compress-2": "2",
27423
+ "compress-3": "3",
27424
+ "compress-4": "4",
27425
+ "compress-5": "5",
27426
+ "compress-6": "6",
27427
+ "compress-7": "7",
27428
+ "compress-8": "8",
27429
+ "compress-9": "9"
27430
+ };
27431
+ var reservedOptions = [
27432
+ "adjust-sfx",
27433
+ "temp-path",
27434
+ "entry-comments",
27435
+ "display-bytes",
27436
+ "display-counts",
27437
+ "display-dots",
27438
+ "display-globaldots",
27439
+ "dot-size",
27440
+ "display-usize",
27441
+ "display-volume",
27442
+ "difference-archive",
27443
+ "encrypt",
27444
+ "fix",
27445
+ "fixfix",
27446
+ "fifo",
27447
+ "filesync",
27448
+ "force-descriptors",
27449
+ "force-zip64",
27450
+ "grow",
27451
+ "help",
27452
+ "more-help",
27453
+ "junk-sfx",
27454
+ "DOS-names",
27455
+ "to-crlf",
27456
+ "from-crlf",
27457
+ "logfile-path",
27458
+ "log-append",
27459
+ "log-info",
27460
+ "license",
27461
+ "move",
27462
+ "must-match",
27463
+ "no-wild",
27464
+ "latest-time",
27465
+ "output-file",
27466
+ "paths",
27467
+ "password",
27468
+ "recurse-patterns",
27469
+ "regex",
27470
+ "split-size",
27471
+ "split-pause",
27472
+ "split-verbose",
27473
+ "split-bell",
27474
+ "show-command",
27475
+ "show-debug",
27476
+ "show-files",
27477
+ "show-options",
27478
+ "from-date",
27479
+ "before-date",
27480
+ "unzip-command",
27481
+ "copy-entries",
27482
+ "verbose",
27483
+ "version",
27484
+ "wild-stop-dirs",
27485
+ "strip-extra",
27486
+ "archive-comment"
27487
+ ];
27488
+ function normalizeZipOption(argument2) {
27489
+ if (!argument2.startsWith("--") || argument2 === "--") return argument2;
27490
+ const equal2 = argument2.indexOf("=");
27491
+ const name2 = argument2.slice(2, equal2 < 0 ? void 0 : equal2);
27492
+ const names = [...Object.keys(longOptions), ...reservedOptions];
27493
+ const matches2 = names.includes(name2) ? [name2] : names.filter((option) => option.startsWith(name2));
27494
+ if (matches2.length > 1) throw new ZipFailure(16, "Invalid command arguments", `long option '${name2}' ambiguous`);
27495
+ const matched = matches2[0];
27496
+ const short = matched === void 0 ? void 0 : longOptions[matched];
27497
+ if (!short) throw new ZipFailure(16, "Invalid command arguments", `unsupported option: ${argument2}`);
27498
+ if (equal2 >= 0 && short !== "i" && short !== "x" && short !== "n" && short !== "Z") {
27499
+ throw new ZipFailure(16, "Invalid command arguments", `option '${matched}' does not allow a value`);
27500
+ }
27501
+ return `-${short}${equal2 < 0 ? "" : argument2.slice(equal2)}`;
27502
+ }
27503
+
27504
+ // packages/safe-bash/src/commands/archive/zip.ts
27505
+ var defaultStoreSuffixes = [".Z", ".zip", ".zoo", ".arc", ".lzh", ".arj"];
27389
27506
  async function parse12(scope, limits) {
27390
27507
  const context2 = scope.context;
27391
27508
  if (context2.args.length > limits.maxArgumentBytes) fail("argument count limit exceeded");
@@ -27414,6 +27531,8 @@ async function parse12(scope, limits) {
27414
27531
  let storeLinks = false;
27415
27532
  let test = false;
27416
27533
  let level = 6;
27534
+ let method = "deflate";
27535
+ let suffixes = defaultStoreSuffixes;
27417
27536
  let stdinNames = false;
27418
27537
  let literal = false;
27419
27538
  let firstOperand = -1;
@@ -27421,8 +27540,9 @@ async function parse12(scope, limits) {
27421
27540
  const includes = [];
27422
27541
  const excludes = [];
27423
27542
  for (let index = 0; index < context2.args.length; index++) {
27424
- const argument2 = context2.args[index];
27425
- checkPath(argument2, limits);
27543
+ const original = context2.args[index];
27544
+ checkPath(original, limits);
27545
+ const argument2 = literal ? original : normalizeZipOption(original);
27426
27546
  if (!literal && argument2 === "--") {
27427
27547
  if (archive === void 0) throw new ZipFailure(16, "Invalid command arguments", "can't use -- before archive name");
27428
27548
  literal = true;
@@ -27440,17 +27560,43 @@ async function parse12(scope, limits) {
27440
27560
  else if (flag === "y") storeLinks = true;
27441
27561
  else if (flag === "T") test = true;
27442
27562
  else if (flag === "@") stdinNames = true;
27443
- else if (flag !== void 0 && flag >= "0" && flag <= "9") level = Number(flag);
27444
- else if (flag === "i" || flag === "x") {
27563
+ else if (flag !== void 0 && flag >= "0" && flag <= "9") {
27564
+ level = Number(flag);
27565
+ if (level === 0) method = "store";
27566
+ } else if (flag === "n" || flag === "Z") {
27567
+ let value2 = argument2.slice(offset + 1);
27568
+ if (!value2) {
27569
+ const next = context2.args[index + 1];
27570
+ if (next === void 0 || next.startsWith("-") && next !== "-") throw new ZipFailure(16, "Invalid command arguments", `option '${flag}' requires a value`);
27571
+ value2 = next;
27572
+ index++;
27573
+ }
27574
+ if (value2.startsWith("=")) value2 = value2.slice(1);
27575
+ if (flag === "n") {
27576
+ suffixes = value2 ? value2.split(":").filter((suffix2) => suffix2.length > 0) : defaultStoreSuffixes;
27577
+ if (value2 && suffixes.length > limits.maxMembers) fail("suffix count limit exceeded");
27578
+ } else {
27579
+ const matches2 = ["store", "deflate", "bzip2"].filter((name2) => name2.startsWith(value2.toLowerCase()));
27580
+ const selected = matches2.length === 1 ? matches2[0] : void 0;
27581
+ if (!selected) throw new ZipFailure(16, "Invalid command arguments", "Option -Z (--compression-method): unknown method");
27582
+ if (selected === "bzip2") throw new ZipFailure(19, "Not supported", "Compression method bzip2 not enabled");
27583
+ method = selected === "store" ? "store" : "deflate";
27584
+ }
27585
+ break;
27586
+ } else if (flag === "i" || flag === "x") {
27445
27587
  const patterns2 = flag === "i" ? includes : excludes;
27446
27588
  const before = patterns2.length;
27447
27589
  const append = (pattern) => {
27448
- checkPath(pattern, limits);
27590
+ if (pattern) checkPath(pattern, limits);
27449
27591
  if (includes.length + excludes.length >= limits.maxMembers) fail("pattern count limit exceeded");
27450
27592
  patterns2.push(pattern);
27451
27593
  };
27452
- if (offset + 1 < argument2.length) append(argument2.slice(offset + 1));
27453
- while (index + 1 < context2.args.length) {
27594
+ const attached = offset + 1 < argument2.length;
27595
+ if (attached) {
27596
+ const value2 = argument2.slice(offset + 1);
27597
+ append(value2.startsWith("=") ? value2.slice(1) : value2);
27598
+ }
27599
+ while (!attached && index + 1 < context2.args.length) {
27454
27600
  const next = context2.args[index + 1];
27455
27601
  if (next === "@") {
27456
27602
  index++;
@@ -27471,13 +27617,16 @@ async function parse12(scope, limits) {
27471
27617
  operands.push(argument2);
27472
27618
  }
27473
27619
  }
27474
- if (archive === void 0) throw new ZipFailure(16, "Invalid command arguments", "expected zip [-r] [-q] [-j] [-@] [-0..-9] ARCHIVE FILES... [-i PATTERNS...] [-x PATTERNS...]");
27475
- if (archive === "-" || operands.includes("-")) throw new ZipFailure(16, "Invalid command arguments", "standard input/output archives are unsupported");
27476
- if (!archive.slice(archive.lastIndexOf("/") + 1).includes(".")) archive += ".zip";
27620
+ if (archive === void 0) {
27621
+ if (action !== "add") throw new ZipFailure(16, "Invalid command arguments", "expected archive name");
27622
+ archive = "-";
27623
+ if (!stdinNames) operands.push("-");
27624
+ }
27625
+ if (archive !== "-" && !archive.slice(archive.lastIndexOf("/") + 1).includes(".")) archive += ".zip";
27477
27626
  checkPath(archive, limits);
27478
27627
  const names = [];
27479
27628
  if (stdinNames) {
27480
- const input3 = await collectBytes(scope.source(context2.stdin), { maxBytes: limits.maxFilesFromBytes, signal: context2.signal });
27629
+ const input3 = await collectBytes(scope.stdin, { maxBytes: limits.maxFilesFromBytes, signal: context2.signal });
27481
27630
  let start = 0;
27482
27631
  let lines3 = 0;
27483
27632
  for (let end = 0; end <= input3.length; end++) {
@@ -27496,7 +27645,7 @@ async function parse12(scope, limits) {
27496
27645
  start = end + 1;
27497
27646
  }
27498
27647
  }
27499
- return { action, archive, recursive, quiet, junkPaths, omitDirectories, storeLinks, test, includes, excludes, level, operands: [...names, ...operands], firstOperand };
27648
+ return { action, archive, recursive, quiet, junkPaths, omitDirectories, storeLinks, test, includes, excludes, level, method, suffixes, operands: [...names, ...operands], firstOperand };
27500
27649
  }
27501
27650
  function memberName(path, limits) {
27502
27651
  if (path.startsWith("//") && !path.startsWith("///")) fail("UNC source paths are unsupported");
@@ -27538,21 +27687,29 @@ async function filterName(name2, selection, includeCount) {
27538
27687
  async function prepare(scope, parsed, budget) {
27539
27688
  const context2 = scope.context;
27540
27689
  const limits = budget.limits;
27541
- const outputName = vfsPath(context2.cwd, parsed.archive);
27542
- const parentName = dirname(outputName);
27543
- const parent = await scope.operation(() => context2.fs.realpath(parentName, { signal: context2.signal }));
27544
- const parentStat = await scope.operation(() => context2.fs.lstat(parent, { signal: context2.signal }));
27545
- const output2 = `${parent === "/" ? "" : parent}/${outputName.slice(outputName.lastIndexOf("/") + 1)}`;
27546
- checkPath(output2, limits);
27547
- const existing2 = await scope.stat(output2);
27690
+ if (parsed.archive === "-" && parsed.action !== "add") throw new ZipFailure(16, "Invalid command arguments", "can't use -d, -f, -u, -U, or -g on stdout\n");
27691
+ let publication;
27692
+ if (parsed.archive !== "-") {
27693
+ const outputName = vfsPath(context2.cwd, parsed.archive);
27694
+ const parentName = dirname(outputName);
27695
+ const parent = await scope.operation(() => context2.fs.realpath(parentName, { signal: context2.signal }));
27696
+ const parentStat = await scope.operation(() => context2.fs.lstat(parent, { signal: context2.signal }));
27697
+ const output3 = `${parent === "/" ? "" : parent}/${outputName.slice(outputName.lastIndexOf("/") + 1)}`;
27698
+ checkPath(output3, limits);
27699
+ const existing3 = await scope.stat(output3);
27700
+ publication = { output: output3, parentName, parent, parentStat, existing: existing3 };
27701
+ }
27702
+ const output2 = publication?.output;
27703
+ const existing2 = publication?.existing;
27704
+ if (parsed.archive === "-" && parsed.test && !parsed.quiet) await budget.output(" zip warning: can't use -T on stdout, -T ignored\n");
27548
27705
  if (existing2 && (existing2.type !== "file" || !hasIdentity(existing2) || existing2.nlink !== 1)) fail("updating archive requires a regular, single-link file with known backing identity; archive aliases are unsupported");
27549
27706
  let archive = { entries: [], comment: new Uint8Array() };
27550
- if (existing2) {
27707
+ if (existing2 && publication) {
27551
27708
  if (!Number.isSafeInteger(existing2.size) || existing2.size < 0 || existing2.size > limits.maxArchiveBytes) fail("archive byte limit exceeded");
27552
- const bytes4 = await collectBytes(scope.input(output2), { maxBytes: limits.maxArchiveBytes, signal: context2.signal });
27709
+ const bytes4 = await collectBytes(scope.input(publication.output), { maxBytes: limits.maxArchiveBytes, signal: context2.signal });
27553
27710
  if (bytes4.length !== existing2.size) fail("archive changed while reading");
27554
27711
  archive = await readZipArchive(bytes4, limits, context2.signal);
27555
- const current = await scope.stat(output2);
27712
+ const current = await scope.stat(publication.output);
27556
27713
  if (!current || !unchanged4(existing2, current)) fail("archive changed while reading");
27557
27714
  }
27558
27715
  const old = new Map(archive.entries.map((entry) => [entry.name, entry]));
@@ -27565,12 +27722,35 @@ async function prepare(scope, parsed, budget) {
27565
27722
  let visits = 0;
27566
27723
  let work = 0;
27567
27724
  let compressedBytes = 0;
27725
+ const encodeSelected = async (source2, name2, bytes4, attributes) => {
27726
+ const store = parsed.method === "store" || parsed.level !== 9 && parsed.suffixes.some((suffix2) => name2.endsWith(suffix2));
27727
+ if (!store && parsed.level === 0 && bytes4.length && !attributes.directory && !attributes.symlink) throw new ZipFailure(5, "Internal logic error", "bad pack level");
27728
+ const level = store ? 0 : parsed.level;
27729
+ let entry = await makeZipEntry(name2, bytes4, attributes, limits, context2.signal, level, parsed.archive === "-" && !store);
27730
+ const prior = old.get(name2);
27731
+ if (prior?.comment) entry = { ...entry, comment: prior.comment };
27732
+ if (entry.data.length > limits.maxArchiveBytes - compressedBytes) fail("archive byte limit exceeded");
27733
+ compressedBytes += entry.data.length;
27734
+ selected.set(name2, { entry, source: source2 });
27735
+ };
27568
27736
  const visit = async (source2, name2, depth) => {
27569
27737
  context2.signal.throwIfAborted();
27570
27738
  if (++visits > limits.maxMembers) fail("traversal member limit exceeded");
27571
27739
  if (++work > limits.maxPatternSteps) fail("archive work limit exceeded");
27572
27740
  if (visits % 128 === 0) await yieldTurn(context2.signal);
27573
27741
  if (depth > limits.maxDepth) fail("archive recursion depth limit exceeded");
27742
+ if (source2 === "-") {
27743
+ const previous = selected.get(name2);
27744
+ if (previous && previous.source !== source2) throw new ZipFailure(16, "Invalid command arguments", "cannot repeat names in zip file");
27745
+ if (previous || !await filterName(name2, selection, parsed.includes.length)) return;
27746
+ const prior2 = old.get(name2);
27747
+ const modified = /* @__PURE__ */ new Date();
27748
+ if (parsed.action === "freshen" && !prior2 || prior2 && (parsed.action === "update" || parsed.action === "freshen") && Math.floor(modified.getTime() / 1e3) <= Math.floor(prior2.modified.getTime() / 1e3)) return;
27749
+ const bytes4 = await collectBytes(scope.stdin, { maxBytes: Math.min(limits.maxEntryBytes, limits.maxTotalBytes - budget.totalBytes), signal: context2.signal });
27750
+ await budget.member(bytes4.length);
27751
+ await encodeSelected(source2, name2, bytes4, { modified, mode: 4528, directory: false, symlink: false });
27752
+ return;
27753
+ }
27574
27754
  const path = vfsPath(context2.cwd, source2);
27575
27755
  checkPath(path, limits);
27576
27756
  let canonical;
@@ -27623,12 +27803,7 @@ async function prepare(scope, parsed, budget) {
27623
27803
  if (!directory2 && bytes4.length !== stat.size) fail(`source changed while reading: ${source2}`);
27624
27804
  const current = await inspectSource(scope, path, parsed.storeLinks);
27625
27805
  if (current.canonical !== canonical || !unchanged4(stat, current.stat)) fail(`source changed while reading: ${source2}`);
27626
- let entry = await makeZipEntry(name2, bytes4, { modified: new Date(stat.mtimeMs), mode: stat.mode, directory: directory2, symlink }, limits, context2.signal, parsed.level);
27627
- if ([".z", ".zip", ".zoo", ".arc", ".lzh", ".arj"].some((suffix2) => name2.toLowerCase().endsWith(suffix2))) entry = { ...entry, method: 0, data: bytes4 };
27628
- if (prior?.comment) entry = { ...entry, comment: prior.comment };
27629
- if (entry.data.length > limits.maxArchiveBytes - compressedBytes) fail("archive byte limit exceeded");
27630
- compressedBytes += entry.data.length;
27631
- selected.set(name2, { entry, source: source2 });
27806
+ await encodeSelected(source2, name2, bytes4, { modified: new Date(stat.mtimeMs), mode: stat.mode, directory: directory2, symlink });
27632
27807
  }
27633
27808
  }
27634
27809
  if (directory2 && parsed.recursive) {
@@ -27709,8 +27884,8 @@ async function prepare(scope, parsed, budget) {
27709
27884
  append(entry, false);
27710
27885
  }
27711
27886
  if (!entries2.length) queue(" zip warning: zip file empty\n");
27712
- const bytes3 = await writeZipArchive({ entries: entries2, comment: archive.comment }, limits, context2.signal);
27713
- if (parsed.test) {
27887
+ const bytes3 = await writeZipArchive({ entries: entries2, comment: archive.comment }, limits, context2.signal, parsed.archive === "-");
27888
+ if (parsed.test && parsed.archive !== "-") {
27714
27889
  for (const message3 of progress) await budget.output(message3);
27715
27890
  progress.length = 0;
27716
27891
  progressBytes = 0;
@@ -27735,7 +27910,7 @@ async function prepare(scope, parsed, budget) {
27735
27910
  `);
27736
27911
  }
27737
27912
  }
27738
- return { output: output2, parentName, parent, parentStat, existing: existing2, bytes: bytes3, progress };
27913
+ return { publication, bytes: bytes3, progress };
27739
27914
  }
27740
27915
  function createZipCommand(options2 = {}) {
27741
27916
  const limits = settings2(options2);
@@ -27743,13 +27918,25 @@ function createZipCommand(options2 = {}) {
27743
27918
  original.signal.throwIfAborted();
27744
27919
  const scope = new ZipScope(original, limits);
27745
27920
  const context2 = scope.context;
27746
- const budget = new Budget14(context2, limits);
27921
+ let budget = new Budget14(context2, limits);
27747
27922
  try {
27748
27923
  const parsed = await parse12(scope, limits);
27924
+ if (parsed.archive === "-") budget = new Budget14({ ...context2, stdout: context2.stderr }, limits);
27749
27925
  const prepared = await prepare(scope, parsed, budget);
27750
27926
  if (!prepared) return { exitCode: 12 };
27751
- await writeFileOutput(context2, prepared.bytes, () => scope.operation(() => publishZip(scope, prepared)));
27752
- for (const message3 of prepared.progress) await budget.output(message3);
27927
+ const publication = prepared.publication;
27928
+ if (publication) {
27929
+ await writeFileOutput(context2, prepared.bytes, () => scope.operation(() => publishZip(scope, { ...publication, bytes: prepared.bytes })));
27930
+ for (const message3 of prepared.progress) await budget.output(message3);
27931
+ } else {
27932
+ for (const message3 of prepared.progress) await budget.output(message3);
27933
+ const output2 = createOutputOperation(context2, context2.stdout);
27934
+ try {
27935
+ await writeBytes(output2.output, prepared.bytes, output2.signal);
27936
+ } finally {
27937
+ await output2.close();
27938
+ }
27939
+ }
27753
27940
  return { exitCode: 0 };
27754
27941
  } catch (error) {
27755
27942
  original.signal.throwIfAborted();
@@ -28155,7 +28342,7 @@ function createUnzipCommand(options2 = {}) {
28155
28342
  }
28156
28343
  let path = extraction.member(root, entry.name);
28157
28344
  const fileType = entry.mode & 61440;
28158
- if (fileType && fileType !== 32768 && fileType !== 16384 && fileType !== 40960) fail("unsupported special ZIP entry");
28345
+ if (fileType && fileType !== 32768 && fileType !== 16384 && fileType !== 40960 && fileType !== 4096) fail("unsupported special ZIP entry");
28159
28346
  if (path === root && !entry.directory) fail("entry would replace extraction root");
28160
28347
  let shown = parsed.destination === void 0 ? entry.name : `${parsed.destination.endsWith("/") ? parsed.destination : `${parsed.destination}/`}${entry.name}`;
28161
28348
  await extraction.parents(root, path, true);