@poe-platform/safe-bash 0.1.520 → 0.1.522

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.
@@ -4411,7 +4411,7 @@ function streamCommands(maxTeeTargets = 64, maxTailFollowHandles = 64) {
4411
4411
  else utf82.write(chunk);
4412
4412
  }
4413
4413
  if (!singleByte) utf82.finish();
4414
- for (const field of Object.keys(totals)) totals[field] += counts[field];
4414
+ for (const field2 of Object.keys(totals)) totals[field2] += counts[field2];
4415
4415
  await print(counts, parsed.operands.length ? name2 : void 0);
4416
4416
  } catch (error) {
4417
4417
  await diagnostic(context2, error);
@@ -4995,7 +4995,7 @@ function textCommands() {
4995
4995
  const delimiter = parsed.flags.has("z") ? 0 : 10;
4996
4996
  const key = (bytes3) => {
4997
4997
  let offset = 0;
4998
- for (let field = 0; field < skipFields; field++) {
4998
+ for (let field2 = 0; field2 < skipFields; field2++) {
4999
4999
  while (offset < bytes3.length && (bytes3[offset] === 32 || bytes3[offset] === 9)) offset++;
5000
5000
  while (offset < bytes3.length && bytes3[offset] !== 32 && bytes3[offset] !== 9) offset++;
5001
5001
  }
@@ -5059,13 +5059,13 @@ function textCommands() {
5059
5059
  if (parsed.flags.has("s")) continue;
5060
5060
  await writer.write(line.bytes);
5061
5061
  } else {
5062
- let field = 1;
5062
+ let field2 = 1;
5063
5063
  let start = 0;
5064
5064
  let emitted = false;
5065
5065
  while (true) {
5066
5066
  const checkpoint = work.charge();
5067
5067
  if (checkpoint) await checkpoint;
5068
- if (selected(field++)) {
5068
+ if (selected(field2++)) {
5069
5069
  if (emitted) await writer.text(outputDelimiter ?? delimiter);
5070
5070
  await writer.write(record4.subarray(start, boundary < 0 ? record4.length : boundary));
5071
5071
  emitted = true;
@@ -5375,8 +5375,8 @@ async function splitString(source2, environment, work) {
5375
5375
  else finish();
5376
5376
  continue;
5377
5377
  }
5378
- const controls = { f: "\f", n: "\n", r: "\r", t: " ", v: "\v" };
5379
- if (Object.hasOwn(controls, escaped3)) append(controls[escaped3]);
5378
+ const controls2 = { f: "\f", n: "\n", r: "\r", t: " ", v: "\v" };
5379
+ if (Object.hasOwn(controls2, escaped3)) append(controls2[escaped3]);
5380
5380
  else if (`"#$'\\`.includes(escaped3)) append(escaped3);
5381
5381
  else throw new EnvSplitError(`invalid sequence '\\${escaped3}' in -S`);
5382
5382
  continue;
@@ -5459,8 +5459,8 @@ async function splitBytes(source2, environment, work) {
5459
5459
  else finish();
5460
5460
  continue;
5461
5461
  }
5462
- const controls = { 102: 12, 110: 10, 114: 13, 116: 9, 118: 11 };
5463
- if (Object.hasOwn(controls, escaped3)) append(Uint8Array.of(controls[escaped3]));
5462
+ const controls2 = { 102: 12, 110: 10, 114: 13, 116: 9, 118: 11 };
5463
+ if (Object.hasOwn(controls2, escaped3)) append(Uint8Array.of(controls2[escaped3]));
5464
5464
  else if ([34, 35, 36, 39, 92].includes(escaped3)) append(Uint8Array.of(escaped3));
5465
5465
  else throw new EnvSplitError(`invalid sequence '\\${String.fromCharCode(escaped3)}' in -S`);
5466
5466
  continue;
@@ -6111,6 +6111,144 @@ async function matchTokens(patternTokens, value2, work, start, end) {
6111
6111
  return tokenIndex === patternTokens.length;
6112
6112
  }
6113
6113
 
6114
+ // packages/safe-bash/src/commands/find-format.ts
6115
+ init_platform();
6116
+ var controls = { 97: 7, 98: 8, 102: 12, 110: 10, 114: 13, 116: 9, 118: 11, 92: 92 };
6117
+ var FindFormatBudget = class {
6118
+ constructor(context2) {
6119
+ this.context = context2;
6120
+ }
6121
+ context;
6122
+ arguments = 0;
6123
+ steps = 0;
6124
+ bytes = 0;
6125
+ untilYield = 4096;
6126
+ exhausted = false;
6127
+ fail(label) {
6128
+ this.exhausted = true;
6129
+ throw new FsError("EFBIG", { message: `find printf ${label} limit exceeded` });
6130
+ }
6131
+ admitFormat(length) {
6132
+ this.arguments += length;
6133
+ if (this.arguments > 65536) throw new UsageError("printf format byte limit exceeded (65536)");
6134
+ }
6135
+ async step(count2 = 1) {
6136
+ this.context.signal.throwIfAborted();
6137
+ this.steps += count2;
6138
+ if (this.steps > 32 * 1024 * 1024) this.fail("work");
6139
+ this.untilYield -= count2;
6140
+ if (this.untilYield <= 0) {
6141
+ this.untilYield = 4096;
6142
+ await yieldTurn(this.context.signal);
6143
+ }
6144
+ }
6145
+ async write(bytes3) {
6146
+ this.admitOutput(bytes3.length);
6147
+ this.bytes += bytes3.length;
6148
+ for (let offset = 0; offset < bytes3.length; offset += 4096) {
6149
+ const chunk = bytes3.subarray(offset, offset + 4096);
6150
+ await this.step(chunk.length);
6151
+ await output(this.context, chunk);
6152
+ }
6153
+ }
6154
+ admitOutput(length) {
6155
+ if (length > 8 * 1024 * 1024 - this.bytes) this.fail("output");
6156
+ }
6157
+ async text(text3) {
6158
+ this.admitOutput(text3.length);
6159
+ for (let offset = 0; offset < text3.length; ) {
6160
+ let end = Math.min(text3.length, offset + 1024);
6161
+ if (end < text3.length && text3.charCodeAt(end - 1) >= 55296 && text3.charCodeAt(end - 1) <= 56319) end--;
6162
+ const part = text3.slice(offset, end);
6163
+ const length = import_buffer.Buffer.byteLength(part);
6164
+ this.admitOutput(length);
6165
+ await this.write(import_buffer.Buffer.from(part));
6166
+ offset = end;
6167
+ }
6168
+ }
6169
+ };
6170
+ async function field(entry, code, budget) {
6171
+ if (code === "p") return entry.display;
6172
+ if (code === "P") return entry.relative;
6173
+ if (code === "H") return entry.root;
6174
+ if (code === "s") return String(entry.stat.size);
6175
+ if (code === "d") return String(entry.depth);
6176
+ if (code === "y") return { file: "f", directory: "d", symlink: "l", character: "c" }[entry.stat.type];
6177
+ let end = entry.display.length;
6178
+ while (end > 1 && entry.display[end - 1] === "/") {
6179
+ await budget.step();
6180
+ end--;
6181
+ }
6182
+ let slash = end - 1;
6183
+ while (slash >= 0 && entry.display[slash] !== "/") {
6184
+ await budget.step();
6185
+ slash--;
6186
+ }
6187
+ const start = code === "f" ? slash + 1 : 0;
6188
+ const finish = code === "f" ? end : slash;
6189
+ if (code === "f" && end === 1 && entry.display[0] === "/") return "/";
6190
+ if (code === "h" && slash < 0) return ".";
6191
+ budget.admitOutput(finish - start);
6192
+ for (let offset = start; offset < finish; offset += 4096) await budget.step(Math.min(4096, finish - offset));
6193
+ return entry.display.slice(start, finish);
6194
+ }
6195
+ async function compileFindFormat(value2, budget) {
6196
+ if (typeof value2 === "string" && value2.length > 65536) budget.admitFormat(value2.length);
6197
+ budget.admitFormat(shellValueByteLength(value2));
6198
+ const source2 = shellValueBytes(value2);
6199
+ const parts = [];
6200
+ let literal = 0;
6201
+ let index = 0;
6202
+ const flush = () => {
6203
+ if (index > literal) parts.push({ start: literal, end: index });
6204
+ };
6205
+ while (index < source2.length) {
6206
+ await budget.step();
6207
+ const byte = source2[index];
6208
+ if (byte !== 37 && byte !== 92) {
6209
+ index++;
6210
+ continue;
6211
+ }
6212
+ flush();
6213
+ const next = source2[++index];
6214
+ if (byte === 37) {
6215
+ if (next === 37) parts.push({ byte: 37 });
6216
+ else if (next !== void 0 && "pfhsdPHy".includes(String.fromCharCode(next))) parts.push({ directive: String.fromCharCode(next) });
6217
+ else throw new UsageError("unsupported printf format directive or modifier");
6218
+ index++;
6219
+ } else {
6220
+ if (next === 99) {
6221
+ literal = source2.length;
6222
+ break;
6223
+ }
6224
+ if (next !== void 0 && Object.hasOwn(controls, next)) {
6225
+ parts.push({ byte: controls[next] });
6226
+ index++;
6227
+ } else if (next !== void 0 && next >= 48 && next <= 55) {
6228
+ let value3 = 0;
6229
+ const end = Math.min(source2.length, index + 3);
6230
+ while (index < end && source2[index] >= 48 && source2[index] <= 55) {
6231
+ await budget.step();
6232
+ value3 = value3 * 8 + source2[index++] - 48;
6233
+ }
6234
+ parts.push({ byte: value3 & 255 });
6235
+ } else throw new UsageError("unsupported printf format escape");
6236
+ }
6237
+ literal = index;
6238
+ }
6239
+ if (literal < source2.length && index > literal) parts.push({ start: literal, end: index });
6240
+ return async (entry) => {
6241
+ for (const part of parts) {
6242
+ await budget.step();
6243
+ if ("directive" in part) await budget.text(await field(entry, part.directive, budget));
6244
+ else if ("byte" in part) {
6245
+ budget.admitOutput(1);
6246
+ await budget.write(Uint8Array.of(part.byte));
6247
+ } else await budget.write(source2.subarray(part.start, part.end));
6248
+ }
6249
+ };
6250
+ }
6251
+
6114
6252
  // packages/safe-bash/src/commands/find.ts
6115
6253
  function findCommands(execute5, maxDirectoryEntries) {
6116
6254
  const readDirectory = createDirectoryReader(maxDirectoryEntries);
@@ -6151,7 +6289,7 @@ function findCommands(execute5, maxDirectoryEntries) {
6151
6289
  explicitDepth = true;
6152
6290
  args.splice(index, 1);
6153
6291
  values.splice(index, 1);
6154
- } else if (["-name", "-iname", "-path", "-ipath", "-type", "-size", "-mtime", "-mmin", "-newer"].includes(args[index])) index += 2;
6292
+ } else if (["-name", "-iname", "-path", "-ipath", "-type", "-size", "-mtime", "-mmin", "-newer", "-printf"].includes(args[index])) index += 2;
6155
6293
  else index++;
6156
6294
  }
6157
6295
  let offset = 0;
@@ -6161,6 +6299,8 @@ function findCommands(execute5, maxDirectoryEntries) {
6161
6299
  let prunes = false;
6162
6300
  const references = /* @__PURE__ */ new Map();
6163
6301
  const flushes = [];
6302
+ const formats2 = [];
6303
+ const formatBudget = new FindFormatBudget(context2);
6164
6304
  const primary = () => {
6165
6305
  const token = args[offset++];
6166
6306
  if (token === void 0) throw new UsageError("missing expression");
@@ -6267,6 +6407,19 @@ function findCommands(execute5, maxDirectoryEntries) {
6267
6407
  return true;
6268
6408
  };
6269
6409
  }
6410
+ if (token === "-printf") {
6411
+ if (args[offset] === void 0) throw new UsageError("-printf requires a format");
6412
+ const operand = values[offset++];
6413
+ let render2;
6414
+ formats2.push(async () => {
6415
+ render2 = await compileFindFormat(operand, formatBudget);
6416
+ });
6417
+ explicitAction = true;
6418
+ return async (entry) => {
6419
+ await render2(entry);
6420
+ return true;
6421
+ };
6422
+ }
6270
6423
  if (token === "-exec") {
6271
6424
  explicitAction = true;
6272
6425
  const command7 = [];
@@ -6324,6 +6477,7 @@ function findCommands(execute5, maxDirectoryEntries) {
6324
6477
  };
6325
6478
  const evaluate = args.length ? disjunction() : async () => true;
6326
6479
  if (offset !== args.length) throw new UsageError(`unexpected expression '${args[offset]}'`);
6480
+ for (const prepare of formats2) await prepare();
6327
6481
  if (deletes && prunes && !explicitDepth) throw new PublicDiagnostic("-delete implies -depth; -prune is ineffective unless -depth is explicitly supplied");
6328
6482
  for (const reference of references.keys()) {
6329
6483
  context2.signal.throwIfAborted();
@@ -6339,7 +6493,7 @@ function findCommands(execute5, maxDirectoryEntries) {
6339
6493
  context2.signal.throwIfAborted();
6340
6494
  references.set(reference, stat.mtimeMs);
6341
6495
  }
6342
- const visit = async (display2, depth, ancestors) => {
6496
+ const visit = async (display2, depth, ancestors, root, relative) => {
6343
6497
  context2.signal.throwIfAborted();
6344
6498
  const path = pathOf(context2, display2);
6345
6499
  try {
@@ -6353,7 +6507,7 @@ function findCommands(execute5, maxDirectoryEntries) {
6353
6507
  if (codeOf(error) !== "ENOENT") throw error;
6354
6508
  }
6355
6509
  }
6356
- const entry = { path, display: display2, stat, symlink, depth, prune: false };
6510
+ const entry = { path, display: display2, stat, symlink, depth, root, relative, prune: false };
6357
6511
  const apply = async () => {
6358
6512
  if (depth >= minDepth && await evaluate(entry) && !explicitAction) await output(context2, `${escapeText(display2, "display")}
6359
6513
  `);
@@ -6364,15 +6518,16 @@ function findCommands(execute5, maxDirectoryEntries) {
6364
6518
  if (ancestors.has(physical)) throw new FsError("ELOOP", { path });
6365
6519
  const next = new Set(ancestors).add(physical);
6366
6520
  const children = await readDirectory(context2, path, true);
6367
- for (const child of children) await visit(`${display2.replace(/\/$/u, "")}/${child.name}`, depth + 1, next);
6521
+ for (const child of children) await visit(`${display2.replace(/\/$/u, "")}/${child.name}`, depth + 1, next, root, relative ? `${relative}/${child.name}` : child.name);
6368
6522
  }
6369
6523
  if (depthFirst) await apply();
6370
6524
  } catch (error) {
6525
+ if (formatBudget.exhausted) throw error;
6371
6526
  await diagnostic(context2, error);
6372
6527
  exitCode = 1;
6373
6528
  }
6374
6529
  };
6375
- for (const root of roots) await visit(root, 0, /* @__PURE__ */ new Set());
6530
+ for (const root of roots) await visit(root, 0, /* @__PURE__ */ new Set(), root, "");
6376
6531
  for (const flush of flushes) await flush();
6377
6532
  return { exitCode };
6378
6533
  })];
@@ -10189,7 +10344,7 @@ function unicodeLocale2(context2) {
10189
10344
  return locale.endsWith("utf-8") || locale.endsWith("utf8");
10190
10345
  }
10191
10346
  function quote2(text3, filename = false, unicode = false) {
10192
- const controls = { "\x07": "\\a", "\b": "\\b", " ": "\\t", "\n": "\\n", "\v": "\\v", "\f": "\\f", "\r": "\\r" };
10347
+ const controls2 = { "\x07": "\\a", "\b": "\\b", " ": "\\t", "\n": "\\n", "\v": "\\v", "\f": "\\f", "\r": "\\r" };
10193
10348
  const decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
10194
10349
  const units = [];
10195
10350
  for (let offset = 0; offset < text3.length; ) {
@@ -10244,7 +10399,7 @@ function quote2(text3, filename = false, unicode = false) {
10244
10399
  } else if (!unit2.printable) {
10245
10400
  if (filename && !escaping) result2 += "'$'";
10246
10401
  escaping = true;
10247
- result2 += controls[unit2.text] ?? Array.from(unit2.text, (character) => `\\${character.charCodeAt(0).toString(8).padStart(3, "0")}`).join("");
10402
+ result2 += controls2[unit2.text] ?? Array.from(unit2.text, (character) => `\\${character.charCodeAt(0).toString(8).padStart(3, "0")}`).join("");
10248
10403
  } else {
10249
10404
  if (filename && escaping) result2 += "''";
10250
10405
  escaping = false;
@@ -12790,9 +12945,9 @@ var Converter = class {
12790
12945
  const nul = line.indexOf("\0");
12791
12946
  if (nul >= 0) line = line.slice(0, nul);
12792
12947
  let start = 0;
12793
- let field = 0n;
12948
+ let field2 = 0n;
12794
12949
  while (true) {
12795
- field++;
12950
+ field2++;
12796
12951
  let end = start;
12797
12952
  if (settings17.delimiter !== void 0) {
12798
12953
  while (end < line.length && line[end] !== settings17.delimiter) end++;
@@ -12803,7 +12958,7 @@ var Converter = class {
12803
12958
  backing[end] = 0;
12804
12959
  let text3 = line.slice(start, end);
12805
12960
  await this.tick((settings17.fields?.length ?? 0) + 1);
12806
- if (settings17.fields ? settings17.fields.some(([low, high]) => low <= field && field <= high) : field === 1n) {
12961
+ if (settings17.fields ? settings17.fields.some(([low, high]) => low <= field2 && field2 <= high) : field2 === 1n) {
12807
12962
  if (settings17.suffix && text3.length > settings17.suffix.length) {
12808
12963
  if (text3.endsWith(settings17.suffix)) {
12809
12964
  text3 = text3.slice(0, -settings17.suffix.length);
@@ -12815,7 +12970,7 @@ var Converter = class {
12815
12970
  let skipped = 0;
12816
12971
  while (blank(text3[skipped])) skipped++;
12817
12972
  if (this.autoPadding) {
12818
- settings17.padding = skipped > 0 || field > 1n ? BigInt(text3.length) : 0n;
12973
+ settings17.padding = skipped > 0 || field2 > 1n ? BigInt(text3.length) : 0n;
12819
12974
  if (settings17.developer) await this.output.emit(`setting Auto-Padding to ${settings17.padding} characters
12820
12975
  `, true);
12821
12976
  }
@@ -14514,7 +14669,7 @@ function compare3(left, right, format2, budget) {
14514
14669
  // packages/safe-bash/src/commands/text-programs/awk-syntax.ts
14515
14670
  function decodeString(source2) {
14516
14671
  let result2 = "";
14517
- const controls = { n: "\n", t: " ", r: "\r", b: "\b", f: "\f", v: "\v", a: "\x07", "\\": "\\", '"': '"' };
14672
+ const controls2 = { n: "\n", t: " ", r: "\r", b: "\b", f: "\f", v: "\v", a: "\x07", "\\": "\\", '"': '"' };
14518
14673
  for (let offset = 0; offset < source2.length; offset++) {
14519
14674
  const character = source2[offset];
14520
14675
  if (character !== "\\") {
@@ -14528,7 +14683,7 @@ function decodeString(source2) {
14528
14683
  const following = /^[0-7]{0,2}/u.exec(source2.slice(offset + 1))[0];
14529
14684
  result2 += String.fromCharCode(parseInt(next + following, 8) & 255);
14530
14685
  offset += following.length;
14531
- } else result2 += controls[next] ?? next;
14686
+ } else result2 += controls2[next] ?? next;
14532
14687
  }
14533
14688
  return result2;
14534
14689
  }
@@ -15419,13 +15574,13 @@ var AwkRuntime = class {
15419
15574
  }
15420
15575
  replaceRecord(record4, fields3) {
15421
15576
  let fieldBytes = 0;
15422
- for (const field of fields3) {
15423
- if (field.kind === "string" || field.kind === "numeric") this.budget.check(field.text);
15424
- fieldBytes += textSize(field);
15577
+ for (const field2 of fields3) {
15578
+ if (field2.kind === "string" || field2.kind === "numeric") this.budget.check(field2.text);
15579
+ fieldBytes += textSize(field2);
15425
15580
  }
15426
15581
  const owned = this.retention.replace(this.record.length + this.fieldBytes, record4.length + fieldBytes, () => ({
15427
15582
  record: import_buffer.Buffer.from(record4, "latin1").toString("latin1"),
15428
- fields: fields3.map((field, index) => field === this.fields[index] ? field : ownScalar(field))
15583
+ fields: fields3.map((field2, index) => field2 === this.fields[index] ? field2 : ownScalar(field2))
15429
15584
  }));
15430
15585
  this.record = owned.record;
15431
15586
  this.fields = owned.fields;
@@ -17463,7 +17618,7 @@ function createRgCommand(executor, options3 = {}) {
17463
17618
  try {
17464
17619
  const result2 = await searchFile(context2, args, limits, matcher, printer, target, context2.stdin, args.filename ?? (target.recursive || selection.paths.length > 1));
17465
17620
  found ||= result2.found;
17466
- for (const field of ["searches", "searches_with_match", "bytes_searched", "bytes_printed", "matched_lines", "matches"]) totals[field] += result2.stats[field];
17621
+ for (const field2 of ["searches", "searches_with_match", "bytes_searched", "bytes_printed", "matched_lines", "matches"]) totals[field2] += result2.stats[field2];
17467
17622
  if (args.quiet && found && args.mode !== "json") break;
17468
17623
  } catch (error) {
17469
17624
  if (error instanceof SearchError || error instanceof RegexExecutionError) throw error;
@@ -17980,9 +18135,9 @@ async function reverseNormal(context2, files, columns, maxInputBytes) {
17980
18135
  if (!match) throw new PublicDiagnostic("invalid input: expected hexadecimal address and colon");
17981
18136
  const address = Number.parseInt(match[1], 16);
17982
18137
  if (!Number.isSafeInteger(address) || address !== offset) throw new PublicDiagnostic("invalid input: reverse requires contiguous addresses starting at zero");
17983
- const field = match[2].split(/ {2,}|\t/u, 1)[0];
17984
- if (!/^(?:[0-9a-fA-F]{2})+(?: (?:[0-9a-fA-F]{2})+)*$/u.test(field)) throw new PublicDiagnostic("invalid input: malformed hexadecimal data field");
17985
- const digits = field.replaceAll(" ", "");
18138
+ const field2 = match[2].split(/ {2,}|\t/u, 1)[0];
18139
+ if (!/^(?:[0-9a-fA-F]{2})+(?: (?:[0-9a-fA-F]{2})+)*$/u.test(field2)) throw new PublicDiagnostic("invalid input: malformed hexadecimal data field");
18140
+ const digits = field2.replaceAll(" ", "");
17986
18141
  if (digits.length > columns * 2) throw new PublicDiagnostic("invalid input: data exceeds configured columns");
17987
18142
  const bytes3 = new Uint8Array(digits.length / 2);
17988
18143
  for (let index = 0; index < bytes3.length; index++) bytes3[index] = Number.parseInt(digits.slice(index * 2, index * 2 + 2), 16);
@@ -24961,9 +25116,9 @@ function quoted(text3, style2) {
24961
25116
  }
24962
25117
  return `'${text3.replace(/'/gu, "'\\''")}'`;
24963
25118
  }
24964
- function available(value2, field) {
24965
- if (value2 === void 0) throw new FsError("ENOTSUP", { syscall: "stat", message: `filesystem does not expose ${field}` });
24966
- if (!Number.isFinite(value2)) throw new FsError("EIO", { syscall: "stat", message: `invalid ${field}` });
25119
+ function available(value2, field2) {
25120
+ if (value2 === void 0) throw new FsError("ENOTSUP", { syscall: "stat", message: `filesystem does not expose ${field2}` });
25121
+ if (!Number.isFinite(value2)) throw new FsError("EIO", { syscall: "stat", message: `invalid ${field2}` });
24967
25122
  return value2;
24968
25123
  }
24969
25124
  function timestamp2(milliseconds) {
@@ -26577,7 +26732,7 @@ function unicodeLocale3(context2) {
26577
26732
  return locale.endsWith("utf-8") || locale.endsWith("utf8");
26578
26733
  }
26579
26734
  function quote4(text3, filename = false, unicode = false) {
26580
- const controls = { "\x07": "\\a", "\b": "\\b", " ": "\\t", "\n": "\\n", "\v": "\\v", "\f": "\\f", "\r": "\\r" };
26735
+ const controls2 = { "\x07": "\\a", "\b": "\\b", " ": "\\t", "\n": "\\n", "\v": "\\v", "\f": "\\f", "\r": "\\r" };
26581
26736
  const decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
26582
26737
  const units = [];
26583
26738
  for (let offset = 0; offset < text3.length; ) {
@@ -26631,7 +26786,7 @@ function quote4(text3, filename = false, unicode = false) {
26631
26786
  } else if (!unit2.printable) {
26632
26787
  if (filename && !escaping) result2 += "'$'";
26633
26788
  escaping = true;
26634
- result2 += controls[unit2.text] ?? Array.from(unit2.text, (character) => `\\${character.charCodeAt(0).toString(8).padStart(3, "0")}`).join("");
26789
+ result2 += controls2[unit2.text] ?? Array.from(unit2.text, (character) => `\\${character.charCodeAt(0).toString(8).padStart(3, "0")}`).join("");
26635
26790
  } else {
26636
26791
  if (filename && escaping) result2 += "''";
26637
26792
  escaping = false;
@@ -28653,9 +28808,9 @@ function parse12(context2, budget) {
28653
28808
  let delimiterChoice;
28654
28809
  const apply = (flag, value2) => {
28655
28810
  if (flag === "1" || flag === "2" || flag === "j") {
28656
- const field = number3(value2, "field") - 1;
28657
- if (flag !== "2") options3.fields[0] = field;
28658
- if (flag !== "1") options3.fields[1] = field;
28811
+ const field2 = number3(value2, "field") - 1;
28812
+ if (flag !== "2") options3.fields[0] = field2;
28813
+ if (flag !== "1") options3.fields[1] = field2;
28659
28814
  } else if (flag === "a" || flag === "v") {
28660
28815
  if (value2 !== "1" && value2 !== "2") fail3(`invalid file number: ${value2}`);
28661
28816
  options3.unpaired.add(Number(value2) - 1);
@@ -28791,9 +28946,9 @@ function createJoinCommand(factory = {}) {
28791
28946
  const pair = [left, right], fields3 = [];
28792
28947
  const key = (left ?? right)?.key ?? empty;
28793
28948
  if (Array.isArray(options3.format)) {
28794
- for (const field of options3.format) {
28949
+ for (const field2 of options3.format) {
28795
28950
  await budget.step();
28796
- fields3.push(field.file === 0 ? key : pair[field.file - 1]?.fields[field.index] ?? empty);
28951
+ fields3.push(field2.file === 0 ? key : pair[field2.file - 1]?.fields[field2.index] ?? empty);
28797
28952
  }
28798
28953
  } else {
28799
28954
  fields3.push(key);
@@ -31784,13 +31939,13 @@ function serialized(value2, budget) {
31784
31939
  }
31785
31940
  };
31786
31941
  let first = true;
31787
- for (const [key, field] of Object.entries(value2)) {
31942
+ for (const [key, field2] of Object.entries(value2)) {
31788
31943
  if (!first) add3(1);
31789
31944
  first = false;
31790
31945
  string2(key);
31791
31946
  add3(1);
31792
- if (typeof field === "string") string2(field);
31793
- else if (typeof field === "number") add3(String(field).length);
31947
+ if (typeof field2 === "string") string2(field2);
31948
+ else if (typeof field2 === "number") add3(String(field2).length);
31794
31949
  else throw new TypeError("tree JSON fields must be strings or numbers");
31795
31950
  }
31796
31951
  return JSON.stringify(value2).replace(
@@ -39551,8 +39706,8 @@ var ownedInputs = /* @__PURE__ */ new WeakMap();
39551
39706
  function getoptsInputAllocationSize(argumentsCount) {
39552
39707
  return { bytes: 256 + argumentsCount * 8, slots: argumentsCount + 2 };
39553
39708
  }
39554
- async function createGetoptsInput(args, allocation, controls) {
39555
- const work = new ScanWork(controls);
39709
+ async function createGetoptsInput(args, allocation, controls2) {
39710
+ const work = new ScanWork(controls2);
39556
39711
  if (!Array.isArray(args)) throw new GetoptsError("INVALID_INPUT", "Getopts requires an argument array");
39557
39712
  const length = args.length;
39558
39713
  if (length > work.maxArguments) throw new GetoptsError("ARGUMENT_LIMIT", "Getopts argument limit exceeded");
@@ -40071,11 +40226,11 @@ function stagedFailure(state, reason) {
40071
40226
  throwAdmissionFailure(state);
40072
40227
  throw reason;
40073
40228
  }
40074
- function prepareControls(parent, controls) {
40075
- if (controls === void 0) return Object.freeze([]);
40076
- if (!Array.isArray(controls)) return stagedFailure(parent, new TypeError("Cancellation controls must be an array"));
40229
+ function prepareControls(parent, controls2) {
40230
+ if (controls2 === void 0) return Object.freeze([]);
40231
+ if (!Array.isArray(controls2)) return stagedFailure(parent, new TypeError("Cancellation controls must be an array"));
40077
40232
  const prepared = [];
40078
- for (const input3 of controls) {
40233
+ for (const input3 of controls2) {
40079
40234
  let role;
40080
40235
  let signal;
40081
40236
  try {
@@ -40093,13 +40248,13 @@ function prepareControls(parent, controls) {
40093
40248
  throwAdmissionFailure(parent);
40094
40249
  return Object.freeze(prepared);
40095
40250
  }
40096
- function makePrepared(parent, localSignal, controls, admission) {
40251
+ function makePrepared(parent, localSignal, controls2, admission) {
40097
40252
  const state = {
40098
40253
  parent,
40099
40254
  localSignal,
40100
- controls,
40255
+ controls: controls2,
40101
40256
  admission,
40102
- owned: localSignal !== void 0 || controls.length > 0,
40257
+ owned: localSignal !== void 0 || controls2.length > 0,
40103
40258
  replayError: new Error("Prepared cancellation admission was already activated"),
40104
40259
  activated: false
40105
40260
  };
@@ -40119,7 +40274,7 @@ function throwLocalActivationFailure(state) {
40119
40274
  const failure = localActivationFailure(state);
40120
40275
  if (failure.failed) throw failure.reason;
40121
40276
  }
40122
- function prepareChildCancellation(parent, options3, snapshot, controls) {
40277
+ function prepareChildCancellation(parent, options3, snapshot, controls2) {
40123
40278
  const parentState = requireLink(parent);
40124
40279
  throwAdmissionFailure(parentState);
40125
40280
  let localSignal;
@@ -40141,7 +40296,7 @@ function prepareChildCancellation(parent, options3, snapshot, controls) {
40141
40296
  throwAdmissionFailure(parentState);
40142
40297
  if (localSignal !== void 0 && signalAborted(localSignal)) throw localSignal.reason;
40143
40298
  }
40144
- const preparedControls = prepareControls(parentState, controls);
40299
+ const preparedControls = prepareControls(parentState, controls2);
40145
40300
  if (localSignal === void 0 && preparedControls.length === 0) {
40146
40301
  return makePrepared(parentState, void 0, preparedControls, void 0);
40147
40302
  }
@@ -40214,16 +40369,16 @@ function createRootCancellationLink(input3) {
40214
40369
  const admission = validateSnapshot(input3.admission);
40215
40370
  if (admission.depth !== 0) throw new RangeError("Root cancellation depth must be zero");
40216
40371
  if (input3.callerSignal !== void 0 && !nativeSignal(input3.callerSignal)) throw new TypeError("Root caller signal must be an AbortSignal");
40217
- const controls = input3.controls ?? [];
40218
- if (!Array.isArray(controls)) throw new TypeError("Cancellation controls must be an array");
40219
- for (const control of controls) {
40372
+ const controls2 = input3.controls ?? [];
40373
+ if (!Array.isArray(controls2)) throw new TypeError("Cancellation controls must be an array");
40374
+ for (const control of controls2) {
40220
40375
  if (!control || typeof control !== "object" || control.role !== "budget-control" && control.role !== "pipeline-control" || !nativeSignal(control.signal)) throw new TypeError("Invalid cancellation control origin");
40221
40376
  }
40222
- const required = 1 + Number(input3.callerSignal !== void 0 && !signalAborted(input3.callerSignal)) + controls.filter((control) => !signalAborted(control.signal)).length;
40377
+ const required = 1 + Number(input3.callerSignal !== void 0 && !signalAborted(input3.callerSignal)) + controls2.filter((control) => !signalAborted(control.signal)).length;
40223
40378
  if (admission.resourceLimit < required) throw new CancellationCapacityError();
40224
40379
  const state = initializeState(void 0, admission);
40225
40380
  state.rootCaller = input3.callerSignal === void 0 ? void 0 : Object.freeze({ role: "root-caller", signal: input3.callerSignal, frame: state.boundary });
40226
- state.controls = Object.freeze(controls.map((control) => Object.freeze({
40381
+ state.controls = Object.freeze(controls2.map((control) => Object.freeze({
40227
40382
  role: control.role,
40228
40383
  signal: control.signal,
40229
40384
  frame: state.boundary
@@ -40932,16 +41087,16 @@ var StateMonitor = class {
40932
41087
  this.#getoptsInput = void 0;
40933
41088
  this.#positionalRevision = {};
40934
41089
  }
40935
- changedValue(target, field, key) {
40936
- if (field === "state") {
41090
+ changedValue(target, field2, key) {
41091
+ if (field2 === "state") {
40937
41092
  if (key === "variables") this.values.invalidate();
40938
41093
  if (key === "positional") {
40939
41094
  this.positionals.invalidate();
40940
41095
  this.invalidateGetoptsInput();
40941
41096
  }
40942
- } else if (field === "variables" && (this.raw.variables === target || this.raw.variables === this.#wrapped.get(target))) {
41097
+ } else if (field2 === "variables" && (this.raw.variables === target || this.raw.variables === this.#wrapped.get(target))) {
40943
41098
  this.values.invalidate(String(key));
40944
- } else if (field === "positional" && (this.raw.positional === target || this.raw.positional === this.#wrapped.get(target))) {
41099
+ } else if (field2 === "positional" && (this.raw.positional === target || this.raw.positional === this.#wrapped.get(target))) {
40945
41100
  this.positionals.invalidate();
40946
41101
  this.invalidateGetoptsInput();
40947
41102
  }
@@ -41002,8 +41157,8 @@ var StateMonitor = class {
41002
41157
  *overlayFrames() {
41003
41158
  for (let frame = this.#overlays; frame; frame = frame[overlayNext]) yield frame;
41004
41159
  }
41005
- prepareCollection(value2, field) {
41006
- return this.wrap(value2, field);
41160
+ prepareCollection(value2, field2) {
41161
+ return this.wrap(value2, field2);
41007
41162
  }
41008
41163
  async prepareTypedPublication(name2, owner, signal) {
41009
41164
  owner.reserve({ metadata: 128, work: 7 });
@@ -41059,7 +41214,7 @@ var StateMonitor = class {
41059
41214
  this.epoch = tickets.epoch;
41060
41215
  this.store?.changed(tickets, name2);
41061
41216
  }
41062
- wrap(value2, field) {
41217
+ wrap(value2, field2) {
41063
41218
  const previous = this.#wrapped.get(value2);
41064
41219
  if (previous) return previous;
41065
41220
  if (this.#enrollment || this.#internalEnrollment) {
@@ -41067,7 +41222,7 @@ var StateMonitor = class {
41067
41222
  }
41068
41223
  this.#wrapperCount++;
41069
41224
  const monitor = this;
41070
- const named2 = field === "variables" || field === "exported" || field === "readonlyVariables";
41225
+ const named2 = field2 === "variables" || field2 === "exported" || field2 === "readonlyVariables";
41071
41226
  let proxy;
41072
41227
  if (value2 instanceof Map || value2 instanceof Set) {
41073
41228
  proxy = new Proxy(value2, { get(target, key) {
@@ -41102,8 +41257,8 @@ var StateMonitor = class {
41102
41257
  get(target, key, receiver) {
41103
41258
  const entry = Reflect.get(target, key, receiver);
41104
41259
  if (entry && typeof entry === "object" && key !== "redirectAssignments") {
41105
- if (field === "state" && key === "functions") return monitor.wrap(entry, "functions");
41106
- if (field !== "functions") return monitor.wrap(entry, field === "state" ? String(key) : field);
41260
+ if (field2 === "state" && key === "functions") return monitor.wrap(entry, "functions");
41261
+ if (field2 !== "functions") return monitor.wrap(entry, field2 === "state" ? String(key) : field2);
41107
41262
  }
41108
41263
  return entry;
41109
41264
  },
@@ -41111,7 +41266,7 @@ var StateMonitor = class {
41111
41266
  const name2 = named2 ? String(key) : void 0;
41112
41267
  const tickets = monitor.mutation(name2);
41113
41268
  const result2 = Reflect.set(target, key, entry);
41114
- if (result2) monitor.changedValue(target, field, key);
41269
+ if (result2) monitor.changedValue(target, field2, key);
41115
41270
  monitor.finish(tickets, name2);
41116
41271
  return result2;
41117
41272
  },
@@ -41119,7 +41274,7 @@ var StateMonitor = class {
41119
41274
  const name2 = named2 ? String(key) : void 0;
41120
41275
  const tickets = monitor.mutation(name2);
41121
41276
  const result2 = Reflect.deleteProperty(target, key);
41122
- if (result2) monitor.changedValue(target, field, key);
41277
+ if (result2) monitor.changedValue(target, field2, key);
41123
41278
  monitor.finish(tickets, name2);
41124
41279
  return result2;
41125
41280
  },
@@ -41127,7 +41282,7 @@ var StateMonitor = class {
41127
41282
  const name2 = named2 ? String(key) : void 0;
41128
41283
  const tickets = monitor.mutation(name2);
41129
41284
  const result2 = Reflect.defineProperty(target, key, descriptor2);
41130
- if (result2) monitor.changedValue(target, field, key);
41285
+ if (result2) monitor.changedValue(target, field2, key);
41131
41286
  monitor.finish(tickets, name2);
41132
41287
  return result2;
41133
41288
  }
@@ -41536,6 +41691,8 @@ var Budget25 = class {
41536
41691
  iterations = 0;
41537
41692
  bytes = 0;
41538
41693
  sourceBytes = 0;
41694
+ globstarEntries = 0;
41695
+ globstarStates = 0;
41539
41696
  controller = new AbortController();
41540
41697
  signal;
41541
41698
  #wallClockTimer;
@@ -42587,16 +42744,16 @@ var Runtime = class _Runtime {
42587
42744
  resourceLimit: _Runtime.cancellationResourceLimit(budget, 0, maxDepth, 2)
42588
42745
  };
42589
42746
  }
42590
- static cancellationResourceLimit(budget, depth, maxDepth, controls) {
42747
+ static cancellationResourceLimit(budget, depth, maxDepth, controls2) {
42591
42748
  const remainingCommands = Math.max(0, budget.limits.maxCommands - budget.commands);
42592
42749
  const remainingDepth = Math.max(0, maxDepth - depth);
42593
- return saturatedSum(saturatedSum(4, controls), saturatedSum(remainingCommands, remainingDepth));
42750
+ return saturatedSum(saturatedSum(4, controls2), saturatedSum(remainingCommands, remainingDepth));
42594
42751
  }
42595
- cancellationAdmission(depth, controls = 0) {
42752
+ cancellationAdmission(depth, controls2 = 0) {
42596
42753
  return {
42597
42754
  depth,
42598
42755
  maxDepth: this.cancellationMaxDepth,
42599
- resourceLimit: _Runtime.cancellationResourceLimit(this.budget, depth, this.cancellationMaxDepth, controls)
42756
+ resourceLimit: _Runtime.cancellationResourceLimit(this.budget, depth, this.cancellationMaxDepth, controls2)
42600
42757
  };
42601
42758
  }
42602
42759
  observeRuntimeReturn(rawReturn, frame, downstream = () => void 0) {
@@ -42847,10 +43004,10 @@ var Runtime = class _Runtime {
42847
43004
  await textToken(store.owner, env[key], this.signal);
42848
43005
  publications.set(key, operation2.reserve({ generation: true, version: true, epoch: true, work: 8 }));
42849
43006
  }
42850
- const controls = operation2.reserve({ epoch: true, work: state.exported.size + keys.length + 5 });
43007
+ const controls2 = operation2.reserve({ epoch: true, work: state.exported.size + keys.length + 5 });
42851
43008
  this.signal.throwIfAborted();
42852
43009
  if (stateMonitor(state).epoch !== epoch2) throw new ArrayFailure("stale state snapshot");
42853
- stateMonitor(state).publish(controls, void 0, () => {
43010
+ stateMonitor(state).publish(controls2, void 0, () => {
42854
43011
  for (const key of state.exported) delete state.variables[key];
42855
43012
  state.exported = new Set(keys);
42856
43013
  });
@@ -43170,14 +43327,14 @@ var Runtime = class _Runtime {
43170
43327
  const incoming = pipes[index - 1];
43171
43328
  const outgoing = pipes[index];
43172
43329
  const childDepth = this.cancellationDepth + 1;
43173
- const controls = [
43330
+ const controls2 = [
43174
43331
  { role: "pipeline-control", signal: controllers[index].signal }
43175
43332
  ];
43176
43333
  const prepared = prepareChildCancellation(
43177
43334
  this.cancellation,
43178
43335
  void 0,
43179
- this.cancellationAdmission(childDepth, controls.length),
43180
- controls
43336
+ this.cancellationAdmission(childDepth, controls2.length),
43337
+ controls2
43181
43338
  );
43182
43339
  const owner = new InvocationCancellationOwner(io[invocationScope], prepared, this.cancellationState);
43183
43340
  let boundary;
@@ -44451,6 +44608,7 @@ ${functionDisplay(name2, state.functions.get(name2))}`;
44451
44608
  getopts: { cursor: createGetoptsState(), integer: true },
44452
44609
  directoryStack: { entries: [], bytes: 0 },
44453
44610
  dotglob: false,
44611
+ globstar: false,
44454
44612
  positional: [...args],
44455
44613
  arg0,
44456
44614
  profile: context2.command === "sh" ? "sh" : "bash",
@@ -45360,7 +45518,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45360
45518
  if (index < 0n || index > BigInt(count2)) work.fail("directory stack index out of range");
45361
45519
  return Number(index);
45362
45520
  };
45363
- const field = async (value2) => {
45521
+ const field2 = async (value2) => {
45364
45522
  await work.charge(1);
45365
45523
  return work.scan(value2, "argument");
45366
45524
  };
@@ -45398,11 +45556,11 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45398
45556
  try {
45399
45557
  for (let offset = 0; offset < args.length; offset++) {
45400
45558
  const token = args[offset];
45401
- const bytes3 = await field(token);
45559
+ const bytes3 = await field2(token);
45402
45560
  if (token === "--") {
45403
45561
  if (command7 === "pushd" && selected === void 0 && offset + 1 < args.length) {
45404
45562
  target = args[offset + 1];
45405
- targetBytes = await field(target);
45563
+ targetBytes = await field2(target);
45406
45564
  if (!noCd && offset + 2 < args.length) work.fail("too many arguments");
45407
45565
  }
45408
45566
  break;
@@ -45525,7 +45683,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45525
45683
  else if (flag === "u") unset2 = true;
45526
45684
  else {
45527
45685
  await this.diagnostic(context2, `shopt: ${option.startsWith("--") ? option : `-${flag}`}: unsupported option`);
45528
- await writeDiagnostic(context2.stderr, "shopt: usage: shopt [-pqsu] [--] [dotglob ...]\n");
45686
+ await writeDiagnostic(context2.stderr, "shopt: usage: shopt [-pqsu] [--] [dotglob globstar ...]\n");
45529
45687
  return 2;
45530
45688
  }
45531
45689
  }
@@ -45534,26 +45692,26 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45534
45692
  await this.diagnostic(context2, "shopt: cannot set and unset shell options simultaneously");
45535
45693
  return 1;
45536
45694
  }
45537
- const emit2 = async () => {
45538
- if (!quiet) await writeText(context2.stdout, print ? `shopt -${state.dotglob ? "s" : "u"} dotglob
45539
- ` : `dotglob ${state.dotglob ? "on" : "off"}
45695
+ const emit2 = async (name2) => {
45696
+ if (!quiet) await writeText(context2.stdout, print ? `shopt -${state[name2] ? "s" : "u"} ${name2}
45697
+ ` : `${name2.padEnd(20)} ${state[name2] ? "on" : "off"}
45540
45698
  `);
45541
45699
  };
45542
45700
  if (index === context2.args.length) {
45543
- if ((!set || state.dotglob) && (!unset2 || !state.dotglob)) await emit2();
45701
+ for (const name2 of ["dotglob", "globstar"]) if ((!set || state[name2]) && (!unset2 || !state[name2])) await emit2(name2);
45544
45702
  return 0;
45545
45703
  }
45546
45704
  let status2 = 0;
45547
45705
  for (; index < context2.args.length; index++) {
45548
45706
  this.signal.throwIfAborted();
45549
45707
  const name2 = context2.args[index];
45550
- if (name2 !== "dotglob") {
45551
- await this.diagnostic(context2, `shopt: ${name2}: unsupported shell option name (only dotglob is supported)`);
45708
+ if (name2 !== "dotglob" && name2 !== "globstar") {
45709
+ await this.diagnostic(context2, `shopt: ${name2}: unsupported shell option name (supported: dotglob, globstar)`);
45552
45710
  status2 = 1;
45553
- } else if (set || unset2) state.dotglob = set;
45711
+ } else if (set || unset2) state[name2] = set;
45554
45712
  else {
45555
- await emit2();
45556
- if (!state.dotglob) status2 = 1;
45713
+ await emit2(name2);
45714
+ if (!state[name2]) status2 = 1;
45557
45715
  }
45558
45716
  }
45559
45717
  return status2;
@@ -46130,8 +46288,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46130
46288
  await this.diagnostic(context2, `${names[index]}: readonly variable`);
46131
46289
  return index === names.length - 1 ? 1 : 2;
46132
46290
  }
46133
- const field = fields3[index];
46134
- await this.assignVariable(state, names[index], field ? line.value.slice(field.start, index === names.length - 1 && position < end ? end : field.end) : "");
46291
+ const field2 = fields3[index];
46292
+ await this.assignVariable(state, names[index], field2 ? line.value.slice(field2.start, index === names.length - 1 && position < end ? end : field2.end) : "");
46135
46293
  }
46136
46294
  }
46137
46295
  return line.terminated ? 0 : 1;
@@ -46442,10 +46600,10 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46442
46600
  try {
46443
46601
  const patternFields = await this.word(part.alternate, state, this.parameterOperandIO(part.alternate, state, io), false, true, hereString);
46444
46602
  let patternUnits = 0;
46445
- for (const field of patternFields) {
46446
- const pending = stringCheckpoint(work, field.length + 1);
46603
+ for (const field2 of patternFields) {
46604
+ const pending = stringCheckpoint(work, field2.length + 1);
46447
46605
  if (pending) await pending;
46448
- patternUnits += field.length;
46606
+ patternUnits += field2.length;
46449
46607
  }
46450
46608
  scratch.reserve(patternUnits * 2, 0);
46451
46609
  const pattern = patternFields.join("");
@@ -46597,7 +46755,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46597
46755
  const size = shellValueByteLength(value2);
46598
46756
  if (size > this.budget.limits.maxExpansionBytes - expansionBytes) this.budget.fail("maxExpansionBytes");
46599
46757
  expansionBytes += size;
46600
- const field = fields3.at(-1);
46758
+ const field2 = fields3.at(-1);
46601
46759
  let escapes = 0;
46602
46760
  if (!glob) {
46603
46761
  const special2 = conditionalPattern ? "\\*?[]-^()|+!@" : "\\*?[]-^";
@@ -46606,21 +46764,21 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46606
46764
  scratch?.reserve(32, 0);
46607
46765
  if (owner) owner.reserve({ payload: size + (escapes ? size + escapes : 0), metadata: 64, work: text3.length + 8 });
46608
46766
  if (escapes) {
46609
- scratch?.reserve((field.patterns ? 32 : 32 * (field.fragments.length + 1)) + (text3.length + escapes) * 2, 0);
46610
- field.patterns ??= field.fragments.map(shellValueText);
46611
- field.patterns.push(text3.replace(conditionalPattern ? /[\\*?[\]\-^()|+!@]/gu : /[\\*?[\]\-^]/gu, "\\$&"));
46612
- } else if (field.patterns) {
46767
+ scratch?.reserve((field2.patterns ? 32 : 32 * (field2.fragments.length + 1)) + (text3.length + escapes) * 2, 0);
46768
+ field2.patterns ??= field2.fragments.map(shellValueText);
46769
+ field2.patterns.push(text3.replace(conditionalPattern ? /[\\*?[\]\-^()|+!@]/gu : /[\\*?[\]\-^]/gu, "\\$&"));
46770
+ } else if (field2.patterns) {
46613
46771
  scratch?.reserve(32, 0);
46614
- field.patterns.push(text3);
46772
+ field2.patterns.push(text3);
46615
46773
  }
46616
- if (typeof value2 !== "string" || field.bytes) {
46617
- if (!scratch) io[valueScope]?.reserve(32 * (field.bytes ? 1 : field.fragments.length + 1), field.bytes ? 1 : field.fragments.length + 1);
46774
+ if (typeof value2 !== "string" || field2.bytes) {
46775
+ if (!scratch) io[valueScope]?.reserve(32 * (field2.bytes ? 1 : field2.fragments.length + 1), field2.bytes ? 1 : field2.fragments.length + 1);
46618
46776
  if (typeof value2 !== "string") io[valueScope]?.hold(value2);
46619
- field.bytes = true;
46777
+ field2.bytes = true;
46620
46778
  }
46621
46779
  regexAppend?.(text3, !glob);
46622
- field.fragments.push(value2);
46623
- field.present ||= present;
46780
+ field2.fragments.push(value2);
46781
+ field2.present ||= present;
46624
46782
  };
46625
46783
  const appendSplit = async (value2) => {
46626
46784
  this.budget.cpuCheckpoint();
@@ -46711,17 +46869,17 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46711
46869
  }
46712
46870
  const result2 = [];
46713
46871
  let resultBytes = 0;
46714
- for (const field of fields3) {
46715
- if (!field.present && split4) continue;
46716
- if (scratch && field.fragments.length > 1 && !field.bytes) scratch.reserve(field.fragments.reduce((bytes3, value2) => bytes3 + shellValueText(value2).length * 2, 0), 0);
46717
- const assembled = concatShellValues(field.fragments, io[valueScope]);
46872
+ for (const field2 of fields3) {
46873
+ if (!field2.present && split4) continue;
46874
+ if (scratch && field2.fragments.length > 1 && !field2.bytes) scratch.reserve(field2.fragments.reduce((bytes3, value2) => bytes3 + shellValueText(value2).length * 2, 0), 0);
46875
+ const assembled = concatShellValues(field2.fragments, io[valueScope]);
46718
46876
  const projection = shellValueText(assembled);
46719
- if (field.bytes && field.fragments.length > 1 && !field.patterns) {
46720
- scratch?.reserve(field.fragments.length * 32, 0);
46721
- field.patterns = field.fragments.map(shellValueText);
46877
+ if (field2.bytes && field2.fragments.length > 1 && !field2.patterns) {
46878
+ scratch?.reserve(field2.fragments.length * 32, 0);
46879
+ field2.patterns = field2.fragments.map(shellValueText);
46722
46880
  }
46723
- if (scratch && field.patterns && field.patterns.length > 1) scratch.reserve(field.patterns.reduce((bytes3, text3) => bytes3 + text3.length * 2, 0), 0);
46724
- const fieldPattern = field.patterns ? field.patterns.join("") : projection;
46881
+ if (scratch && field2.patterns && field2.patterns.length > 1) scratch.reserve(field2.patterns.reduce((bytes3, text3) => bytes3 + text3.length * 2, 0), 0);
46882
+ const fieldPattern = field2.patterns ? field2.patterns.join("") : projection;
46725
46883
  const expanded = split4 ? await this.glob(projection, fieldPattern, state) : [pattern ? fieldPattern : projection];
46726
46884
  for (const text3 of expanded) {
46727
46885
  if (result2.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
@@ -46839,8 +46997,195 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46839
46997
  holding.release();
46840
46998
  }
46841
46999
  }
47000
+ async recursiveGlob(value2, pattern, state) {
47001
+ const failWalk = (message3) => {
47002
+ const error = new FsError("EFBIG", { syscall: "glob", message: message3 });
47003
+ this.budget.controller.abort(error);
47004
+ throw error;
47005
+ };
47006
+ const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
47007
+ const scratch = this.budget.values.scope();
47008
+ work.allocation = scratch;
47009
+ try {
47010
+ const segments = [];
47011
+ let start = 0;
47012
+ for (let end = 0; end <= pattern.length; end++) {
47013
+ const pending = stringCheckpoint(work);
47014
+ if (pending) await pending;
47015
+ if (end !== pattern.length && pattern[end] !== "/") continue;
47016
+ if (end > start) {
47017
+ const bytes3 = (await scanString(pattern, work, start, end)).bytes;
47018
+ if (++this.budget.globstarStates > 1e5) failWalk("globstar traversal state limit exceeded");
47019
+ scratch.reserveBytes(bytes3 * 2 + 64);
47020
+ segments.push(pattern.slice(start, end));
47021
+ }
47022
+ start = end + 1;
47023
+ }
47024
+ const make = (parent, suffix2, bytes3, descend, depth) => {
47025
+ const separator = parent.path && parent.path !== "/" ? "/" : "";
47026
+ const size = parent.bytes + separator.length + bytes3;
47027
+ if (size > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
47028
+ if (++this.budget.globstarStates > 1e5) failWalk("globstar traversal state limit exceeded");
47029
+ if (depth > 128) failWalk("globstar directory depth limit exceeded");
47030
+ scratch.reserveBytes(size * 2 + 128);
47031
+ return { path: parent.path + separator + suffix2, bytes: size, descend, depth };
47032
+ };
47033
+ const empty2 = { path: "", bytes: 0, descend: true, depth: 0 };
47034
+ let candidates = [make(empty2, pattern.startsWith("/") ? "/" : "", pattern.startsWith("/") ? 1 : 0, true, 0)];
47035
+ const ignored = (error) => {
47036
+ this.signal.throwIfAborted();
47037
+ return ["ENOENT", "ENOTDIR", "EACCES"].includes(errorCode(error) ?? "");
47038
+ };
47039
+ const read = async (candidate) => {
47040
+ const maxEntries = 1e5 - this.budget.globstarEntries;
47041
+ let entries2;
47042
+ try {
47043
+ entries2 = await interruptible3(this.fs.readdir(pathOf(state, candidate.path || "."), { signal: this.signal, maxEntries }), this.signal);
47044
+ } catch (error) {
47045
+ this.signal.throwIfAborted();
47046
+ if (errorCode(error) === "EFBIG") this.budget.controller.abort(error);
47047
+ throw error;
47048
+ }
47049
+ this.signal.throwIfAborted();
47050
+ if (entries2.length > maxEntries) failWalk("globstar directory entry limit exceeded");
47051
+ this.budget.globstarEntries += entries2.length;
47052
+ return entries2;
47053
+ };
47054
+ let wildcardPrefix = false;
47055
+ for (let index = 0; index < segments.length; index++) {
47056
+ const segment2 = segments[index];
47057
+ const terminal = index === segments.length - 1;
47058
+ const next = /* @__PURE__ */ new Map();
47059
+ const add3 = (candidate) => {
47060
+ const prior = next.get(candidate.path);
47061
+ if (!prior || candidate.descend && !prior.descend) next.set(candidate.path, candidate);
47062
+ };
47063
+ if (segment2 === "**") {
47064
+ const visited = /* @__PURE__ */ new Set();
47065
+ for (const root of candidates) {
47066
+ this.signal.throwIfAborted();
47067
+ try {
47068
+ if ((await interruptible3(this.fs.stat(pathOf(state, root.path || "."), { signal: this.signal }), this.signal)).type !== "directory") continue;
47069
+ } catch (error) {
47070
+ if (ignored(error)) continue;
47071
+ throw error;
47072
+ }
47073
+ if (!terminal || root.path) {
47074
+ add3(terminal && !wildcardPrefix && root.path !== "/" ? make(root, "", 0, root.descend, root.depth) : root);
47075
+ }
47076
+ const queue = root.descend ? [root] : [];
47077
+ while (queue.length) {
47078
+ const directory2 = queue.pop();
47079
+ if (visited.has(directory2.path)) continue;
47080
+ visited.add(directory2.path);
47081
+ let entries2;
47082
+ try {
47083
+ entries2 = await read(directory2);
47084
+ } catch (error) {
47085
+ if (ignored(error)) continue;
47086
+ throw error;
47087
+ }
47088
+ for (const entry of entries2) {
47089
+ const pending = stringCheckpoint(work);
47090
+ if (pending) await pending;
47091
+ if (entry.name === "." || entry.name === ".." || !state.dotglob && entry.name.startsWith(".")) continue;
47092
+ const bytes3 = (await scanString(entry.name, work)).bytes;
47093
+ const child = make(directory2, entry.name, bytes3, entry.type === "directory", directory2.depth + (entry.type === "directory" ? 1 : 0));
47094
+ if (terminal || entry.type === "directory" || entry.type === "symlink" && root.path !== "") add3(child);
47095
+ if (entry.type === "directory") queue.push(child);
47096
+ }
47097
+ }
47098
+ }
47099
+ wildcardPrefix = true;
47100
+ } else if (!/(?:^|[^\\])[*?[]/u.test(segment2)) {
47101
+ const literal = segment2.replace(/\\(.)/gu, "$1");
47102
+ const bytes3 = (await scanString(literal, work)).bytes;
47103
+ for (const candidate of candidates) add3(make(candidate, literal, bytes3, true, candidate.depth));
47104
+ } else {
47105
+ const matches3 = await compilePattern(segment2, work);
47106
+ for (const candidate of candidates) {
47107
+ let entries2;
47108
+ try {
47109
+ entries2 = await read(candidate);
47110
+ } catch (error) {
47111
+ if (ignored(error)) continue;
47112
+ throw error;
47113
+ }
47114
+ for (const entry of entries2) {
47115
+ const pending = stringCheckpoint(work);
47116
+ if (pending) await pending;
47117
+ if (entry.name !== "." && entry.name !== ".." && (state.dotglob || !entry.name.startsWith(".") || segment2.startsWith(".")) && await matches3(entry.name)) {
47118
+ add3(make(candidate, entry.name, (await scanString(entry.name, work)).bytes, true, candidate.depth));
47119
+ }
47120
+ }
47121
+ }
47122
+ wildcardPrefix = true;
47123
+ }
47124
+ candidates = [...next.values()];
47125
+ }
47126
+ const found = [];
47127
+ let outputBytes = 0;
47128
+ for (const candidate of candidates) {
47129
+ this.signal.throwIfAborted();
47130
+ try {
47131
+ const path = pathOf(state, candidate.path);
47132
+ const stat = await interruptible3(value2.endsWith("/") ? this.fs.stat(path, { signal: this.signal }) : this.fs.lstat(path, { signal: this.signal }), this.signal);
47133
+ if (value2.endsWith("/") && stat.type !== "directory") continue;
47134
+ const slash = value2.endsWith("/") && !candidate.path.endsWith("/") ? "/" : "";
47135
+ if (found.length >= this.budget.limits.maxExpansionFields) this.budget.fail("maxExpansionFields");
47136
+ outputBytes += candidate.bytes + slash.length;
47137
+ if (outputBytes > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
47138
+ scratch.reserveBytes(candidate.bytes * 2 + slash.length + 8);
47139
+ found.push(candidate.path + slash);
47140
+ } catch (error) {
47141
+ if (!ignored(error)) throw error;
47142
+ }
47143
+ }
47144
+ const compare6 = async (left, right) => {
47145
+ for (let index = 0; index < Math.min(left.length, right.length); index++) {
47146
+ const pending = stringCheckpoint(work);
47147
+ if (pending) await pending;
47148
+ const difference = left.charCodeAt(index) - right.charCodeAt(index);
47149
+ if (difference) return difference;
47150
+ }
47151
+ return left.length - right.length;
47152
+ };
47153
+ const sift = async (root, end) => {
47154
+ while (root * 2 + 1 < end) {
47155
+ let child = root * 2 + 1;
47156
+ if (child + 1 < end && await compare6(found[child], found[child + 1]) < 0) child++;
47157
+ if (await compare6(found[root], found[child]) >= 0) return;
47158
+ const saved = found[root];
47159
+ found[root] = found[child];
47160
+ found[child] = saved;
47161
+ root = child;
47162
+ }
47163
+ };
47164
+ for (let index = Math.floor(found.length / 2) - 1; index >= 0; index--) await sift(index, found.length);
47165
+ for (let end = found.length - 1; end > 0; end--) {
47166
+ const saved = found[0];
47167
+ found[0] = found[end];
47168
+ found[end] = saved;
47169
+ await sift(0, end);
47170
+ }
47171
+ return found.length ? found : [value2];
47172
+ } finally {
47173
+ scratch.close();
47174
+ }
47175
+ }
46842
47176
  async glob(value2, pattern, state) {
46843
47177
  if (!/(?:^|[^\\])[*?[]/u.test(pattern)) return [value2];
47178
+ if (state.globstar) {
47179
+ const work2 = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
47180
+ let start = 0;
47181
+ for (let end = 0; end <= pattern.length; end++) {
47182
+ const pending = stringCheckpoint(work2);
47183
+ if (pending) await pending;
47184
+ if (end !== pattern.length && pattern[end] !== "/") continue;
47185
+ if (end - start === 2 && pattern[start] === "*" && pattern[start + 1] === "*") return this.recursiveGlob(value2, pattern, state);
47186
+ start = end + 1;
47187
+ }
47188
+ }
46844
47189
  const absolute2 = pattern.startsWith("/");
46845
47190
  const work = { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 4 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
46846
47191
  let candidates = [absolute2 ? "/" : ""];
@@ -47683,6 +48028,7 @@ var Shell = class {
47683
48028
  getopts: { cursor: { index: 0 }, integer: true },
47684
48029
  directoryStack: { entries: [], bytes: 0 },
47685
48030
  dotglob: false,
48031
+ globstar: false,
47686
48032
  status: 0,
47687
48033
  substitutionStatus: 0,
47688
48034
  depth: 0,
@@ -49551,7 +49897,7 @@ function* validDeclaration(content, expectedEncoding) {
49551
49897
  if ((offset - start) % 512) yield (offset - start) % 512;
49552
49898
  return offset - start;
49553
49899
  };
49554
- const field = function* (name2) {
49900
+ const field2 = function* (name2) {
49555
49901
  if (content.slice(offset, offset + name2.length).toLowerCase() !== name2) return void 0;
49556
49902
  offset += name2.length;
49557
49903
  yield name2.length;
@@ -49569,18 +49915,18 @@ function* validDeclaration(content, expectedEncoding) {
49569
49915
  if (offset >= content.length) return void 0;
49570
49916
  return content.slice(start, offset++);
49571
49917
  };
49572
- if (!(yield* whitespace2()) || (yield* field("version")) !== "1.0") return false;
49918
+ if (!(yield* whitespace2()) || (yield* field2("version")) !== "1.0") return false;
49573
49919
  let spacing = yield* whitespace2();
49574
49920
  if (content.slice(offset, offset + 8).toLowerCase() === "encoding") {
49575
49921
  if (!spacing) return false;
49576
- const encoding = yield* field("encoding");
49922
+ const encoding = yield* field2("encoding");
49577
49923
  if (encoding === void 0 || encoding.length > 8 || !["utf-8", "utf-16", "utf-16le", "utf-16be"].includes(encoding.toLowerCase())) return false;
49578
49924
  if (expectedEncoding !== void 0 && encoding.toLowerCase() !== expectedEncoding.toLowerCase()) return false;
49579
49925
  spacing = yield* whitespace2();
49580
49926
  }
49581
49927
  if (content.slice(offset, offset + 10).toLowerCase() === "standalone") {
49582
49928
  if (!spacing) return false;
49583
- const standalone = yield* field("standalone");
49929
+ const standalone = yield* field2("standalone");
49584
49930
  if (standalone === void 0 || standalone.length > 3 || !["yes", "no"].includes(standalone.toLowerCase())) return false;
49585
49931
  yield* whitespace2();
49586
49932
  }
@@ -51436,11 +51782,11 @@ var GuestDiagnostic = class extends PublicDiagnostic {
51436
51782
  function errorInfo(error) {
51437
51783
  if (typeof error === "string") return { name: "Error", code: "", message: error };
51438
51784
  if (typeof error !== "object" || error === null) return { name: "Error", code: "", message: "SafeJS execution failed" };
51439
- const field = (name2) => {
51785
+ const field2 = (name2) => {
51440
51786
  const descriptor2 = Object.getOwnPropertyDescriptor(error, name2);
51441
51787
  return descriptor2 && "value" in descriptor2 && typeof descriptor2.value === "string" ? descriptor2.value : "";
51442
51788
  };
51443
- return { name: field("name"), code: field("code"), message: field("message") || "SafeJS execution failed" };
51789
+ return { name: field2("name"), code: field2("code"), message: field2("message") || "SafeJS execution failed" };
51444
51790
  }
51445
51791
  function statusField(error, name2) {
51446
51792
  if (typeof error !== "object" || error === null) return "";