poe-code 15.0.4 → 15.0.5

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.
Files changed (88) hide show
  1. package/dist/metafile.json +1 -1
  2. package/package.json +8 -2
  3. package/packages/safe-bash/dist/chunks/chunk-2GV4WO7O.js +136 -0
  4. package/packages/safe-bash/dist/chunks/chunk-2GV4WO7O.js.map +7 -0
  5. package/packages/safe-bash/dist/chunks/chunk-54Z5EUCW.js +340 -0
  6. package/packages/safe-bash/dist/chunks/chunk-54Z5EUCW.js.map +7 -0
  7. package/packages/safe-bash/dist/chunks/{chunk-NYHAKXQ7.js → chunk-6MHYEBAJ.js} +16 -140
  8. package/packages/safe-bash/dist/chunks/chunk-6MHYEBAJ.js.map +7 -0
  9. package/packages/safe-bash/dist/chunks/{chunk-5MSOBYRG.js → chunk-IKATLB4I.js} +5 -3
  10. package/packages/safe-bash/dist/chunks/{chunk-5MSOBYRG.js.map → chunk-IKATLB4I.js.map} +1 -1
  11. package/packages/safe-bash/dist/chunks/{chunk-5OCQTFXT.js → chunk-LUJYX5H5.js} +6 -332
  12. package/packages/safe-bash/dist/chunks/{chunk-5OCQTFXT.js.map → chunk-LUJYX5H5.js.map} +4 -4
  13. package/packages/safe-bash/dist/chunks/chunk-UGMUVHIY.js +1603 -0
  14. package/packages/safe-bash/dist/chunks/chunk-UGMUVHIY.js.map +7 -0
  15. package/packages/safe-bash/dist/commands/network/args.d.ts +3 -0
  16. package/packages/safe-bash/dist/commands/network/args.d.ts.map +1 -1
  17. package/packages/safe-bash/dist/commands/network/args.js +1 -1
  18. package/packages/safe-bash/dist/commands/network/args.js.map +1 -1
  19. package/packages/safe-bash/dist/commands/network/body.js +2 -2
  20. package/packages/safe-bash/dist/commands/network/body.js.map +1 -1
  21. package/packages/safe-bash/dist/commands/network/curl.d.ts +12 -2
  22. package/packages/safe-bash/dist/commands/network/curl.d.ts.map +1 -1
  23. package/packages/safe-bash/dist/commands/network/curl.js +46 -27
  24. package/packages/safe-bash/dist/commands/network/curl.js.map +1 -1
  25. package/packages/safe-bash/dist/commands/network/index.browser.js +29 -0
  26. package/packages/safe-bash/dist/commands/network/index.browser.js.map +7 -0
  27. package/packages/safe-bash/dist/commands/network/index.d.ts +1 -10
  28. package/packages/safe-bash/dist/commands/network/index.d.ts.map +1 -1
  29. package/packages/safe-bash/dist/commands/network/index.js +1 -22
  30. package/packages/safe-bash/dist/commands/network/index.js.map +1 -1
  31. package/packages/safe-bash/dist/commands/network/platform.d.ts +4 -0
  32. package/packages/safe-bash/dist/commands/network/platform.d.ts.map +1 -0
  33. package/packages/safe-bash/dist/commands/network/platform.js +4 -0
  34. package/packages/safe-bash/dist/commands/network/platform.js.map +1 -0
  35. package/packages/safe-bash/dist/commands/network/public.d.ts +12 -0
  36. package/packages/safe-bash/dist/commands/network/public.d.ts.map +1 -0
  37. package/packages/safe-bash/dist/commands/network/public.js +27 -0
  38. package/packages/safe-bash/dist/commands/network/public.js.map +1 -0
  39. package/packages/safe-bash/dist/commands/network/shared.js +1 -1
  40. package/packages/safe-bash/dist/commands/network/shared.js.map +1 -1
  41. package/packages/safe-bash/dist/commands/network/wget.d.ts +4 -0
  42. package/packages/safe-bash/dist/commands/network/wget.d.ts.map +1 -0
  43. package/packages/safe-bash/dist/commands/network/wget.js +155 -0
  44. package/packages/safe-bash/dist/commands/network/wget.js.map +1 -0
  45. package/packages/safe-bash/dist/commands/xml/index.browser.js +3 -2
  46. package/packages/safe-bash/dist/commands/yq/index.browser.js +4 -2
  47. package/packages/safe-bash/dist/core.browser.js +1054 -459
  48. package/packages/safe-bash/dist/core.browser.js.map +4 -4
  49. package/packages/safe-bash/dist/core.d.ts +1 -5
  50. package/packages/safe-bash/dist/core.d.ts.map +1 -1
  51. package/packages/safe-bash/dist/core.js +1 -3
  52. package/packages/safe-bash/dist/core.js.map +1 -1
  53. package/packages/safe-bash/dist/shell/arrays/bindings.d.ts +15 -2
  54. package/packages/safe-bash/dist/shell/arrays/bindings.d.ts.map +1 -1
  55. package/packages/safe-bash/dist/shell/arrays/bindings.js +118 -5
  56. package/packages/safe-bash/dist/shell/arrays/bindings.js.map +1 -1
  57. package/packages/safe-bash/dist/shell/arrays/syntax.d.ts +5 -2
  58. package/packages/safe-bash/dist/shell/arrays/syntax.d.ts.map +1 -1
  59. package/packages/safe-bash/dist/shell/arrays/syntax.js +19 -6
  60. package/packages/safe-bash/dist/shell/arrays/syntax.js.map +1 -1
  61. package/packages/safe-bash/dist/shell/display.d.ts.map +1 -1
  62. package/packages/safe-bash/dist/shell/display.js +5 -1
  63. package/packages/safe-bash/dist/shell/display.js.map +1 -1
  64. package/packages/safe-bash/dist/shell/input.d.ts +10 -0
  65. package/packages/safe-bash/dist/shell/input.d.ts.map +1 -1
  66. package/packages/safe-bash/dist/shell/input.js +110 -0
  67. package/packages/safe-bash/dist/shell/input.js.map +1 -1
  68. package/packages/safe-bash/dist/shell/mapfile.d.ts +29 -0
  69. package/packages/safe-bash/dist/shell/mapfile.d.ts.map +1 -0
  70. package/packages/safe-bash/dist/shell/mapfile.js +134 -0
  71. package/packages/safe-bash/dist/shell/mapfile.js.map +1 -0
  72. package/packages/safe-bash/dist/shell/parameter-transforms.d.ts +12 -0
  73. package/packages/safe-bash/dist/shell/parameter-transforms.d.ts.map +1 -0
  74. package/packages/safe-bash/dist/shell/parameter-transforms.js +166 -0
  75. package/packages/safe-bash/dist/shell/parameter-transforms.js.map +1 -0
  76. package/packages/safe-bash/dist/shell/parser.d.ts +12 -0
  77. package/packages/safe-bash/dist/shell/parser.d.ts.map +1 -1
  78. package/packages/safe-bash/dist/shell/parser.js +75 -14
  79. package/packages/safe-bash/dist/shell/parser.js.map +1 -1
  80. package/packages/safe-bash/dist/shell/runtime.d.ts +7 -3
  81. package/packages/safe-bash/dist/shell/runtime.d.ts.map +1 -1
  82. package/packages/safe-bash/dist/shell/runtime.js +440 -63
  83. package/packages/safe-bash/dist/shell/runtime.js.map +1 -1
  84. package/packages/safe-bash/dist/shell/select-menu.d.ts +6 -0
  85. package/packages/safe-bash/dist/shell/select-menu.d.ts.map +1 -0
  86. package/packages/safe-bash/dist/shell/select-menu.js +103 -0
  87. package/packages/safe-bash/dist/shell/select-menu.js.map +1 -0
  88. package/packages/safe-bash/dist/chunks/chunk-NYHAKXQ7.js.map +0 -7
@@ -2,10 +2,9 @@ import {
2
2
  createXmlCommands,
3
3
  defaultXmlQueryLimits,
4
4
  xmlCommands
5
- } from "./chunks/chunk-5MSOBYRG.js";
5
+ } from "./chunks/chunk-IKATLB4I.js";
6
6
  import {
7
7
  Interpreter,
8
- createOutputOperation,
9
8
  createYqCommand,
10
9
  createYqCommands,
11
10
  jsonValues,
@@ -14,14 +13,43 @@ import {
14
13
  rawValues,
15
14
  stringify,
16
15
  yqCommands
17
- } from "./chunks/chunk-NYHAKXQ7.js";
16
+ } from "./chunks/chunk-6MHYEBAJ.js";
18
17
  import {
19
18
  Budget,
19
+ JqError,
20
+ JqLimitError,
21
+ copyObject,
22
+ defaultJqLimits,
23
+ interruptible,
24
+ object,
25
+ put,
26
+ resolveJqLimits,
27
+ truth,
28
+ wellFormed
29
+ } from "./chunks/chunk-54Z5EUCW.js";
30
+ import {
31
+ CurlError,
32
+ bindFileOutputBudget,
33
+ cloudflareWorkerNetworkLimits,
34
+ createCurlCommand,
35
+ createCurlCommands,
36
+ createFetchTransport,
37
+ createNetworkCommands,
38
+ createOriginAuthorizer,
39
+ createWgetCommand,
40
+ curlCommands,
41
+ defaultNetworkLimits,
42
+ networkCommands,
43
+ openFileOutput,
44
+ writeFileOutput
45
+ } from "./chunks/chunk-UGMUVHIY.js";
46
+ import {
47
+ createOutputOperation
48
+ } from "./chunks/chunk-2GV4WO7O.js";
49
+ import {
20
50
  CommandArgumentIdentityError,
21
51
  CommandRegistry,
22
52
  FsError,
23
- JqError,
24
- JqLimitError,
25
53
  PublicDiagnostic,
26
54
  RecordBuffer,
27
55
  UsageError,
@@ -35,11 +63,9 @@ import {
35
63
  collectText,
36
64
  concatShellValues,
37
65
  concatenate,
38
- copyObject,
39
66
  createBytePipe,
40
67
  createCommandArguments,
41
68
  decoder,
42
- defaultJqLimits,
43
69
  define,
44
70
  diagnostic,
45
71
  dirname,
@@ -55,7 +81,6 @@ import {
55
81
  input,
56
82
  inputRequirements,
57
83
  integer,
58
- interruptible,
59
84
  isAbsolutePath,
60
85
  isErrnoCode,
61
86
  isFsError,
@@ -63,7 +88,6 @@ import {
63
88
  joinPath,
64
89
  lines,
65
90
  monotonicNow,
66
- object,
67
91
  options,
68
92
  output,
69
93
  outputFailure,
@@ -71,14 +95,12 @@ import {
71
95
  pipeBytes,
72
96
  predicateRequirements,
73
97
  publicDiagnosticMessage,
74
- put,
75
98
  pwdRequirements,
76
99
  readBytes,
77
100
  registerYieldCheckpoint,
78
101
  relativePath,
79
102
  replaceArgument,
80
103
  requireOperands,
81
- resolveJqLimits,
82
104
  resolvePath,
83
105
  scheduleTurn,
84
106
  shellValueByteLength,
@@ -89,16 +111,14 @@ import {
89
111
  textOutputRequirements,
90
112
  toByteSource,
91
113
  toFsError,
92
- truth,
93
114
  validateExitCode,
94
115
  validatePath,
95
116
  value,
96
- wellFormed,
97
117
  writeBytes,
98
118
  writeDiagnostic,
99
119
  writeText,
100
120
  yieldTurn
101
- } from "./chunks/chunk-5OCQTFXT.js";
121
+ } from "./chunks/chunk-LUJYX5H5.js";
102
122
 
103
123
  // packages/safe-bash/src/core.browser.ts
104
124
  init_platform();
@@ -3442,182 +3462,6 @@ function filesystemCommands(maxDirectoryEntries) {
3442
3462
  // packages/safe-bash/src/commands/streams.ts
3443
3463
  init_platform();
3444
3464
 
3445
- // packages/safe-bash/src/contracts/filesystem-output.ts
3446
- init_platform();
3447
- var filesystemOutputBudgets = /* @__PURE__ */ new WeakMap();
3448
- function bindFileOutputBudget(context2, budget) {
3449
- if (!context2.registerCleanup) throw new TypeError("Shell output budgets require invocation cleanup ownership");
3450
- filesystemOutputBudgets.set(context2.registerCleanup, budget);
3451
- }
3452
- async function writeFileOutput(context2, bytes3, write2) {
3453
- context2.signal.throwIfAborted();
3454
- const budget = context2.registerCleanup && filesystemOutputBudgets.get(context2.registerCleanup);
3455
- let pending;
3456
- const destination2 = { write(chunk) {
3457
- context2.signal.throwIfAborted();
3458
- return pending = (async () => {
3459
- await write2(chunk);
3460
- })();
3461
- } };
3462
- try {
3463
- await (budget?.(destination2) ?? destination2).write(bytes3);
3464
- } catch (error) {
3465
- await pending?.catch(() => {
3466
- });
3467
- context2.signal.throwIfAborted();
3468
- throw error;
3469
- }
3470
- context2.signal.throwIfAborted();
3471
- }
3472
- async function openFileOutput(context2, path, flag, incremental) {
3473
- let pipe;
3474
- let task;
3475
- let completed = false;
3476
- let ended = false;
3477
- let closing = false;
3478
- let failure;
3479
- const consumer = new AbortController();
3480
- let writes = Promise.resolve();
3481
- let acknowledge;
3482
- const acknowledgeWrite = () => {
3483
- const accepted = acknowledge;
3484
- acknowledge = void 0;
3485
- accepted?.();
3486
- };
3487
- let ready;
3488
- const opened = new Promise((resolve) => {
3489
- ready = resolve;
3490
- });
3491
- const destination2 = {
3492
- [outputFailure]: (reason) => operation2.abort(reason),
3493
- async write(chunk) {
3494
- if (closing) throw new FsError("EBADF", { path, syscall: "write" });
3495
- const writing = writes.then(async () => {
3496
- for (let offset = 0; offset < chunk.byteLength; offset += 64 * 1024) {
3497
- const accepted = new Promise((resolve) => {
3498
- acknowledge = resolve;
3499
- });
3500
- await pipe.writable.write(chunk.subarray(offset, offset + 64 * 1024));
3501
- await accepted;
3502
- if (failure) throw failure.reason;
3503
- operation2.signal.throwIfAborted();
3504
- }
3505
- });
3506
- writes = writing.catch(() => {
3507
- });
3508
- await writing;
3509
- }
3510
- };
3511
- const budget = context2.registerCleanup && filesystemOutputBudgets.get(context2.registerCleanup);
3512
- const operation2 = createOutputOperation(context2, budget?.(destination2) ?? destination2);
3513
- operation2.registerCleanup(async () => {
3514
- closing = true;
3515
- if (!completed) {
3516
- void operation2.abort(operation2.signal.aborted ? operation2.signal.reason : new FsError("ECANCELED", { path, syscall: "write" }));
3517
- await pipe?.abort(operation2.signal.reason);
3518
- }
3519
- await task?.catch(() => {
3520
- });
3521
- await writes;
3522
- });
3523
- try {
3524
- pipe = createBytePipe({ highWaterMark: 1, signal: operation2.signal });
3525
- let reading = false;
3526
- const source2 = {
3527
- [Symbol.asyncIterator]() {
3528
- return (async function* () {
3529
- reading = true;
3530
- ready();
3531
- for await (const chunk of pipe.readable) {
3532
- yield chunk;
3533
- acknowledgeWrite();
3534
- }
3535
- operation2.signal.throwIfAborted();
3536
- ended = true;
3537
- })();
3538
- }
3539
- };
3540
- task = (async () => {
3541
- const { fs } = context2;
3542
- const signal = operation2.signal;
3543
- signal.throwIfAborted();
3544
- const capabilities = await fs.capabilitiesFor?.(path, { signal }) ?? fs.capabilities;
3545
- if (capabilities.readOnly === true) throw new FsError("EROFS", { path, syscall: "write" });
3546
- try {
3547
- await fs.access(path, 2, { signal });
3548
- } catch (error) {
3549
- signal.throwIfAborted();
3550
- if (!(error instanceof FsError) || error.code !== "ENOENT" && error.code !== "ENOTSUP") throw error;
3551
- }
3552
- signal.throwIfAborted();
3553
- const streaming = flag === "a" ? capabilities.streamingAppend ?? capabilities.streamingWrite : capabilities.streamingWrite;
3554
- if ((!incremental || capabilities.descriptorWriteStream === true) && streaming !== false && fs.writeStream) {
3555
- try {
3556
- await fs.writeStream(path, source2, { flag, signal });
3557
- if (!ended) throw new FsError("EIO", { path, message: "Streaming writer returned before consuming output" });
3558
- return;
3559
- } catch (error) {
3560
- signal.throwIfAborted();
3561
- if (reading || !(error instanceof FsError) || error.code !== "ENOTSUP") throw error;
3562
- }
3563
- }
3564
- if (flag === "w" && capabilities.write === false) throw new FsError("ENOTSUP", { path, syscall: "writeFile" });
3565
- if ((!incremental || flag === "a") && capabilities.append === false) throw new FsError("ENOTSUP", { path, syscall: "appendFile" });
3566
- const sink = incremental ? await incremental() : await (async () => {
3567
- if (flag === "a") await fs.appendFile(path, new Uint8Array(), { signal });
3568
- else await fs.writeFile(path, new Uint8Array(), { flag, signal });
3569
- return { write: (chunk) => fs.appendFile(path, chunk, { signal }) };
3570
- })();
3571
- for await (const chunk of source2) {
3572
- signal.throwIfAborted();
3573
- await sink.write(chunk);
3574
- }
3575
- })();
3576
- void task.then(acknowledgeWrite, (error) => {
3577
- failure = { reason: error };
3578
- acknowledgeWrite();
3579
- if (!operation2.signal.aborted) consumer.abort(error);
3580
- void operation2.abort(error).catch(() => {
3581
- });
3582
- });
3583
- await Promise.race([opened, task]);
3584
- operation2.signal.throwIfAborted();
3585
- const write2 = async (chunk) => {
3586
- try {
3587
- await operation2.output.write(chunk);
3588
- } catch (error) {
3589
- throw failure ? failure.reason : error;
3590
- }
3591
- };
3592
- return {
3593
- signal: operation2.signal,
3594
- sink: {
3595
- [outputFailure]: destination2[outputFailure],
3596
- ownedOutput: { consumerClosed: consumer.signal, write: write2 },
3597
- write: write2
3598
- },
3599
- async finish() {
3600
- closing = true;
3601
- try {
3602
- await writes;
3603
- await pipe.close();
3604
- await task;
3605
- operation2.signal.throwIfAborted();
3606
- completed = true;
3607
- } catch (error) {
3608
- throw failure ? failure.reason : error;
3609
- } finally {
3610
- await operation2.close();
3611
- }
3612
- },
3613
- abort: (reason) => operation2.abort(reason)
3614
- };
3615
- } catch (error) {
3616
- await operation2.abort(error);
3617
- throw error;
3618
- }
3619
- }
3620
-
3621
3465
  // packages/safe-bash/src/commands/tail-follow.ts
3622
3466
  init_platform();
3623
3467
  var tailFollowScheduler = {
@@ -33508,8 +33352,8 @@ async function entities(text3, budget) {
33508
33352
  const name2 = match[1];
33509
33353
  if (name2[0] !== "#") result2.append(Object.hasOwn(named, name2) ? named[name2] : match[0]);
33510
33354
  else {
33511
- const hexadecimal = name2[1]?.toLowerCase() === "x";
33512
- const value2 = Number.parseInt(name2.slice(hexadecimal ? 2 : 1), hexadecimal ? 16 : 10);
33355
+ const hexadecimal2 = name2[1]?.toLowerCase() === "x";
33356
+ const value2 = Number.parseInt(name2.slice(hexadecimal2 ? 2 : 1), hexadecimal2 ? 16 : 10);
33513
33357
  result2.append(value2 === 0 || value2 > 1114111 || value2 >= 55296 && value2 <= 57343 ? "\uFFFD" : String.fromCodePoint(value2));
33514
33358
  }
33515
33359
  offset += match[0].length;
@@ -37498,12 +37342,23 @@ function literalIndex(source2, offset, budget = new ParseBudget()) {
37498
37342
  return { decimal: decimal4 };
37499
37343
  }
37500
37344
  function numericIndex(index) {
37345
+ if (index.source !== void 0) {
37346
+ try {
37347
+ return numericIndex(literalIndex(index.source, 0));
37348
+ } catch {
37349
+ return void 0;
37350
+ }
37351
+ }
37501
37352
  if (index.decimal.length > 10 || index.decimal.length === 10 && index.decimal > "2147483647") return void 0;
37502
37353
  return Number(index.decimal);
37503
37354
  }
37504
- function arraySelector(source2, offset, budget = new ParseBudget()) {
37355
+ function stringIndex(source2, budget, word) {
37356
+ budget.admit(2);
37357
+ return { decimal: source2, source: source2, ...word ? { word } : {} };
37358
+ }
37359
+ function arraySelector(source2, offset, budget = new ParseBudget(), word) {
37505
37360
  budget.admit();
37506
- return source2 === "@" || source2 === "*" ? { kind: "members", separator: source2 } : { kind: "element", index: literalIndex(source2, offset, budget) };
37361
+ return source2 === "@" || source2 === "*" ? { kind: "members", separator: source2 } : { kind: "element", index: word ? stringIndex(source2, budget, word) : literalIndex(source2, offset, budget) };
37507
37362
  }
37508
37363
  function setArraySelector(part, selector) {
37509
37364
  selectors.set(part, selector);
@@ -37543,21 +37398,22 @@ function removePrefix(word, length, budget) {
37543
37398
  if (length !== 0) throw new ShellSyntaxError("Invalid indexed-array assignment", word.offset);
37544
37399
  return { offset: word.offset, parts };
37545
37400
  }
37546
- function elementAssignment(word, budget = new ParseBudget()) {
37401
+ function elementAssignment(word, budget = new ParseBudget(), parseWord, subscriptEnd) {
37547
37402
  const source2 = word.spelling;
37548
37403
  const first = word.parts[0];
37549
37404
  if (source2 === void 0 || first?.kind !== "text" || first.quoted) return void 0;
37550
37405
  const name2 = /^([a-zA-Z_][a-zA-Z_0-9]*)\[/u.exec(source2)?.[1];
37551
37406
  if (!name2) return void 0;
37552
- const end = source2.indexOf("]", name2.length + 1);
37407
+ const end = subscriptEnd ? subscriptEnd(source2, name2.length + 1) : source2.indexOf("]", name2.length + 1);
37553
37408
  if (end < 0 || !/^(?:\+?=)/u.test(source2.slice(end + 1))) {
37554
37409
  if (source2.includes("=")) throw new ShellSyntaxError("Invalid indexed-array assignment", word.offset);
37555
37410
  return void 0;
37556
37411
  }
37557
37412
  budget.admit();
37558
- const index = literalIndex(source2.slice(name2.length + 1, end), word.offset + name2.length + 1, budget);
37413
+ const keySource = source2.slice(name2.length + 1, end);
37414
+ const index = parseWord ? stringIndex(keySource, budget, parseWord(keySource)) : literalIndex(keySource, word.offset + name2.length + 1, budget);
37559
37415
  const append = source2[end + 1] === "+";
37560
- const value2 = removePrefix(word, name2.length + index.decimal.length + (append ? 4 : 3), budget);
37416
+ const value2 = parseWord ? parseWord(source2.slice(end + (append ? 3 : 2))) : removePrefix(word, name2.length + index.decimal.length + (append ? 4 : 3), budget);
37561
37417
  return { kind: "element", name: name2, index, append, value: value2 };
37562
37418
  }
37563
37419
  function compoundHead(word, budget = new ParseBudget()) {
@@ -38126,7 +37982,8 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38126
37982
  } else if (!literal && (inner === "$" || inner === "`")) {
38127
37983
  this.expansion(parts, true);
38128
37984
  const part = parts.at(-1);
38129
- nameListing ||= part.kind === "variable" && part.prefixNames === "@";
37985
+ const selector = getArraySelector(part);
37986
+ nameListing ||= part.kind === "variable" && (part.prefixNames === "@" || !!part.transform && (part.name === "@" || selector?.kind === "members" && selector.separator === "@"));
38130
37987
  } else if (inner === "\\" && /[$`"\\\n]/u.test(this.source[this.position + 1] ?? "")) {
38131
37988
  const escaped3 = this.source[this.position + 1];
38132
37989
  if (escaped3 !== "\n") text3(escaped3, true, false, this.position, this.position + 2);
@@ -38315,7 +38172,7 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38315
38172
  if (!name2) this.error("Unsupported parameter expansion");
38316
38173
  this.position += name2.length;
38317
38174
  let prefixNames;
38318
- if (listing) {
38175
+ if (listing && this.source[this.position] !== "[") {
38319
38176
  const separator = this.source[this.position];
38320
38177
  if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2) || separator !== "*" && separator !== "@" || this.source[this.position + 1] !== "}") this.error("Unsupported indirect parameter expansion");
38321
38178
  prefixNames = separator;
@@ -38325,11 +38182,20 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38325
38182
  if (this.source[this.position] === "[") {
38326
38183
  if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error("Unsupported indexed-array parameter");
38327
38184
  const start = ++this.position;
38328
- const end = this.source.indexOf("]", start);
38329
- if (end < 0) this.error("Unterminated indexed-array subscript");
38330
- selector = arraySelector(this.source.slice(start, end), start, this.budget);
38185
+ const keyWord = this.word("]");
38186
+ const end = this.position;
38187
+ if (this.source[end] !== "]") this.error("Unterminated indexed-array subscript");
38188
+ selector = arraySelector(this.source.slice(start, end), start, this.budget, keyWord);
38331
38189
  this.position = end + 1;
38332
- if (this.source[this.position] !== "}") this.error("Unsupported indexed-array operator");
38190
+ if (this.source[this.position] !== "}" && this.source[this.position] !== "@") this.error("Unsupported indexed-array operator");
38191
+ }
38192
+ if (listing && selector?.kind === "element") this.error("Unsupported indirect parameter expansion");
38193
+ let transform2;
38194
+ if (this.source[this.position] === "@") {
38195
+ const operation2 = this.source[this.position + 1];
38196
+ if (length || prefixNames || operation2 !== "Q" && operation2 !== "E" || this.source[this.position + 2] !== "}") this.error("Unsupported parameter transform");
38197
+ transform2 = operation2;
38198
+ this.position += 2;
38333
38199
  }
38334
38200
  const operator = /^(?::[-=+?]|##|%%|\/\/|\/[#%]?|[-=+?#%])/u.exec(this.source.slice(this.position))?.[0];
38335
38201
  let alternate;
@@ -38373,7 +38239,8 @@ shell: command substitution: line ${line}: \`${sourceLine}'
38373
38239
  parts.push({ kind: "failed-parameter", source: this.source.slice(parameterStart, this.position), line, quoted: quoted2 });
38374
38240
  } else {
38375
38241
  this.position++;
38376
- const part = { kind: "variable", name: name2, quoted: quoted2, line, ...prefixNames ? { prefixNames } : {}, ...length ? { length } : {}, ...operator ? { operator, alternate } : {}, ...replacement ? { replacement } : {}, ...substring ? { substring } : {} };
38242
+ const part = { kind: "variable", name: name2, quoted: quoted2, line, ...prefixNames ? { prefixNames } : {}, ...transform2 ? { transform: transform2 } : {}, ...length ? { length } : {}, ...operator ? { operator, alternate } : {}, ...replacement ? { replacement } : {}, ...substring ? { substring } : {} };
38243
+ if (listing && selector) part.keys = true;
38377
38244
  if (selector) setArraySelector(part, selector);
38378
38245
  parts.push(part);
38379
38246
  }
@@ -38642,10 +38509,44 @@ var Parser4 = class {
38642
38509
  const body = this.nonemptyScript(/* @__PURE__ */ new Set(["done"]));
38643
38510
  this.expect("done", true);
38644
38511
  command7 = { kind, condition, body, redirects: [] };
38645
- } else if (this.is("for")) {
38512
+ } else if (this.is("for") && this.peek().value === "(" && this.lexer.source.startsWith("((", this.peek().offset)) {
38646
38513
  this.advance();
38514
+ const start = this.current.offset + 2;
38515
+ let partStart = start;
38516
+ let depth = 0;
38517
+ let end = start;
38518
+ this.budget.admit(4);
38519
+ const sources2 = [];
38520
+ for (; end < this.lexer.source.length; end++) {
38521
+ this.budget.admit();
38522
+ const character = this.lexer.source[end];
38523
+ if (character === "(") depth++;
38524
+ else if (character === ")") {
38525
+ if (!depth && this.lexer.source[end + 1] === ")") break;
38526
+ if (--depth < 0) this.error("Unterminated arithmetic for", true);
38527
+ } else if (character === ";" && !depth) {
38528
+ if (sources2.length === 2) this.error("Arithmetic for requires three expressions");
38529
+ sources2.push(this.lexer.source.slice(partStart, end));
38530
+ partStart = end + 1;
38531
+ }
38532
+ }
38533
+ if (end === this.lexer.source.length) this.error("Unterminated arithmetic for", true);
38534
+ if (sources2.length !== 2) this.error("Arithmetic for requires three expressions");
38535
+ sources2.push(this.lexer.source.slice(partStart, end));
38536
+ const expressions = sources2.map((source2) => source2.trim() ? prepareArithmetic(source2, this.budget) : void 0);
38537
+ this.lexer.position = end + 2;
38538
+ this.lookahead = void 0;
38539
+ this.current = this.lexer.next();
38540
+ if (this.is(";")) this.advance();
38541
+ this.newlines();
38542
+ this.expect("do", true);
38543
+ const body = this.nonemptyScript(/* @__PURE__ */ new Set(["done"]));
38544
+ this.expect("done", true);
38545
+ command7 = { kind: "arithmetic-for", expressions, body, redirects: [] };
38546
+ } else if (this.is("for") || this.is("select")) {
38547
+ const kind = this.advance().value;
38647
38548
  const name2 = this.advance().value;
38648
- if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error("Invalid for variable");
38549
+ if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error(`Invalid ${kind} variable`);
38649
38550
  this.newlines();
38650
38551
  let words;
38651
38552
  if (this.is("in")) {
@@ -38654,12 +38555,12 @@ var Parser4 = class {
38654
38555
  while (this.current.kind === "word") words.push(this.advance().word);
38655
38556
  }
38656
38557
  if (this.is(";") || this.is("\n")) this.advance();
38657
- else if (words) this.error("Expected for separator", true);
38558
+ else if (words) this.error(`Expected ${kind} separator`, true);
38658
38559
  this.newlines();
38659
38560
  this.expect("do", true);
38660
38561
  const body = this.nonemptyScript(/* @__PURE__ */ new Set(["done"]));
38661
38562
  this.expect("done", true);
38662
- command7 = { kind: "for", name: name2, ...words ? { words } : {}, body, redirects: [] };
38563
+ command7 = { kind, name: name2, ...words ? { words } : {}, body, redirects: [] };
38663
38564
  } else if (this.is("function")) {
38664
38565
  this.advance();
38665
38566
  if (this.current.kind !== "word" || !/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(this.current.value)) this.error("Invalid function name");
@@ -38677,7 +38578,7 @@ var Parser4 = class {
38677
38578
  this.expect("(");
38678
38579
  this.expect(")");
38679
38580
  this.newlines();
38680
- if (!["{", "(", "if", "case", "while", "until", "for", "[["].includes(this.current.value)) this.error("Expected function body");
38581
+ if (!["{", "(", "if", "case", "while", "until", "for", "select", "[["].includes(this.current.value)) this.error("Expected function body");
38681
38582
  command7 = { kind: "function", name: name2, body: this.command(), redirects: [] };
38682
38583
  } else {
38683
38584
  if (["!", "then", "else", "elif", "fi", "do", "done", "}", "case", "esac", "select", "function", "[[", "]]"].includes(this.current.value)) this.error(`Unexpected or unsupported keyword ${this.current.value}`);
@@ -38714,7 +38615,12 @@ var Parser4 = class {
38714
38615
  word = { offset: word.offset, parts: word.parts, spelling: this.lexer.source.slice(word.offset, end) };
38715
38616
  setArrayAssignment(word, { kind: "compound", ...head, entries: entries2 });
38716
38617
  } else {
38717
- const assignment = words.every((previous) => getArrayAssignment(previous) || scalarAssignmentName(previous)) ? elementAssignment(word, this.budget) : void 0;
38618
+ const assignment = words.every((previous) => getArrayAssignment(previous) || scalarAssignmentName(previous)) ? elementAssignment(word, this.budget, (source2) => parseArraySubscript(source2, this.budget, this.lexer.byteLocale, this.lexer.depth), (source2, start) => {
38619
+ const lexer = new Lexer2(this.budget, source2, this.lexer.depth, [], 0, this.lexer.byteLocale);
38620
+ lexer.position = start;
38621
+ lexer.word("]");
38622
+ return lexer.source[lexer.position] === "]" ? lexer.position : -1;
38623
+ }) : void 0;
38718
38624
  if (assignment) setArrayAssignment(word, assignment);
38719
38625
  }
38720
38626
  words.push(word);
@@ -38756,6 +38662,10 @@ function parseShell(source2, depth = 0, options3 = {}) {
38756
38662
  budget.admit();
38757
38663
  return { ...script, ...warnings.length ? { warnings } : {} };
38758
38664
  }
38665
+ function parseArraySubscript(source2, budget, byteLocale2 = false, depth = 0) {
38666
+ const lexer = new Lexer2(budget, source2, depth, [], 0, byteLocale2);
38667
+ return lexer.word("\0");
38668
+ }
38759
38669
  function parseBraceWord(source2, opaque, budget) {
38760
38670
  budget.admit(source2.length + 1);
38761
38671
  const lexer = new Lexer2(budget, source2, 0);
@@ -39532,6 +39442,94 @@ function evaluatePositionalArithmetic(program, options3, evaluate) {
39532
39442
  }
39533
39443
  }
39534
39444
 
39445
+ // packages/safe-bash/src/shell/select-menu.ts
39446
+ init_platform();
39447
+ async function selectMenu(values, columns, byteLocale2, sink, work, allocation) {
39448
+ allocation.reserve(64 + values.length * 32, 0);
39449
+ const items = [];
39450
+ let maximum = 0;
39451
+ for (const value2 of values) {
39452
+ const bytes3 = shellValueBytes(value2, allocation);
39453
+ allocation.reserve(bytes3.length * 2 + 64, 0);
39454
+ const decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
39455
+ let text3 = "";
39456
+ for (let offset = 0; offset < bytes3.length; offset += 1024) {
39457
+ const end = Math.min(offset + 1024, bytes3.length);
39458
+ const pending = stringCheckpoint(work, end - offset);
39459
+ if (pending) await pending;
39460
+ if (text3 !== void 0) try {
39461
+ text3 += decoder2.decode(bytes3.subarray(offset, end), { stream: end < bytes3.length });
39462
+ } catch (error) {
39463
+ if (!(error instanceof TypeError) || "code" in error && error.code !== "ERR_ENCODING_INVALID_ENCODED_DATA") throw error;
39464
+ text3 = void 0;
39465
+ }
39466
+ }
39467
+ let width = 0;
39468
+ if (text3 !== void 0) for (const character of text3) {
39469
+ const pending = stringCheckpoint(work);
39470
+ if (pending) await pending;
39471
+ const point = character.codePointAt(0);
39472
+ if (byteLocale2 && point >= 128) {
39473
+ width = 0;
39474
+ break;
39475
+ }
39476
+ if (point < 32 || point === 127) {
39477
+ width = bytes3.length;
39478
+ break;
39479
+ }
39480
+ if (/[\p{Mn}\p{Me}\p{Cf}]/u.test(character)) continue;
39481
+ width += point >= 4352 && (point <= 4447 || point === 9001 || point === 9002 || point >= 11904 && point <= 42191 && point !== 12351 || point >= 44032 && point <= 55203 || point >= 63744 && point <= 64255 || point >= 65040 && point <= 65049 || point >= 65072 && point <= 65135 || point >= 65280 && point <= 65376 || point >= 65504 && point <= 65510 || point >= 127744 && point <= 129791 || point >= 131072 && point <= 262141) ? 2 : 1;
39482
+ }
39483
+ maximum = Math.max(maximum, byteLocale2 ? bytes3.length : width);
39484
+ items.push({ bytes: bytes3, width });
39485
+ }
39486
+ let screen = 0;
39487
+ if (columns) {
39488
+ let started = false;
39489
+ for (const character of columns) {
39490
+ const pending = stringCheckpoint(work);
39491
+ if (pending) await pending;
39492
+ if (!started && " \r\n\v\f".includes(character)) continue;
39493
+ if (!started && character === "+") {
39494
+ started = true;
39495
+ continue;
39496
+ }
39497
+ if (character < "0" || character > "9") break;
39498
+ started = true;
39499
+ screen = Math.min(2147483647, screen * 10 + Number(character));
39500
+ }
39501
+ }
39502
+ screen ||= 80;
39503
+ const digits = String(values.length).length;
39504
+ const cell2 = maximum + digits + 4;
39505
+ let rows2 = Math.ceil(values.length / Math.max(1, Math.floor(screen / cell2)));
39506
+ if (rows2 === 1) rows2 = values.length;
39507
+ for (let row = 0; row < rows2; row++) {
39508
+ let position = 0;
39509
+ for (let index = row; index < items.length; index += rows2) {
39510
+ const pending = stringCheckpoint(work);
39511
+ if (pending) await pending;
39512
+ const item = items[index];
39513
+ const indexWidth = position ? digits : String(rows2).length;
39514
+ await writeText(sink, `${String(index + 1).padStart(indexWidth)}) `);
39515
+ await sink.write(item.bytes);
39516
+ if (index + rows2 < items.length) {
39517
+ let from = position + indexWidth + 2 + item.width;
39518
+ const to = position + cell2;
39519
+ while (from < to) {
39520
+ const pending2 = stringCheckpoint(work);
39521
+ if (pending2) await pending2;
39522
+ const tab = Math.floor(to / 8) > Math.floor(from / 8);
39523
+ await writeText(sink, tab ? " " : " ");
39524
+ from += tab ? 8 - from % 8 : 1;
39525
+ }
39526
+ position += cell2;
39527
+ }
39528
+ }
39529
+ await writeText(sink, "\n");
39530
+ }
39531
+ }
39532
+
39535
39533
  // packages/safe-bash/src/shell/locale.ts
39536
39534
  init_platform();
39537
39535
  function byteLocale(variables) {
@@ -39558,6 +39556,12 @@ function commandText(command7, indent) {
39558
39556
  case "arithmetic":
39559
39557
  text3 = `(( ${command7.source} ))`;
39560
39558
  break;
39559
+ case "arithmetic-for":
39560
+ text3 = `for (( ${command7.expressions.map((expression) => expression?.source ?? "").join("; ")} ));
39561
+ do
39562
+ ${nested}${scriptText(command7.body, nested)};
39563
+ ${indent}done`;
39564
+ break;
39561
39565
  case "conditional":
39562
39566
  text3 = `[[${command7.source}]]`;
39563
39567
  break;
@@ -39590,7 +39594,8 @@ ${nested}${scriptText(command7.body, nested)};
39590
39594
  ${indent}done`;
39591
39595
  break;
39592
39596
  case "for":
39593
- text3 = `for ${command7.name}${command7.words ? ` in ${command7.words.map(spelling).join(" ")}` : ""};
39597
+ case "select":
39598
+ text3 = `${command7.kind} ${command7.name}${command7.words ? ` in ${command7.words.map(spelling).join(" ")}` : ""};
39594
39599
  do
39595
39600
  ${nested}${scriptText(command7.body, nested)};
39596
39601
  ${indent}done`;
@@ -40742,14 +40747,16 @@ var controlNames = /* @__PURE__ */ new Set([
40742
40747
  "LC_CTYPE"
40743
40748
  ]);
40744
40749
  var OwnedText = class {
40745
- constructor(value2, bytes3, admission) {
40750
+ constructor(value2, bytes3, admission, rawValue) {
40746
40751
  this.value = value2;
40747
40752
  this.bytes = bytes3;
40748
40753
  this.admission = admission;
40754
+ this.rawValue = rawValue;
40749
40755
  }
40750
40756
  value;
40751
40757
  bytes;
40752
40758
  admission;
40759
+ rawValue;
40753
40760
  references = 1;
40754
40761
  retain() {
40755
40762
  if (this.references === Number.MAX_SAFE_INTEGER) throw new ArrayFailure("reference capacity is not representable");
@@ -40775,27 +40782,110 @@ async function textToken(owner, value2, signal) {
40775
40782
  const admission = owner.reserve({ payload: bytes3, metadata: 32, work: 4 });
40776
40783
  return new OwnedText(value2, bytes3, admission);
40777
40784
  }
40785
+ async function valueToken(owner, value2, signal) {
40786
+ if (typeof value2 === "string") return textToken(owner, value2, signal);
40787
+ const bytes3 = shellValueByteLength(value2);
40788
+ const temporary = owner.reserve({ payload: bytes3 * 3, metadata: 64, work: 4 });
40789
+ try {
40790
+ const input3 = shellValueBytes(value2);
40791
+ const decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
40792
+ let text3 = "";
40793
+ for (let offset = 0; offset < bytes3; offset += 1024) {
40794
+ const end = Math.min(bytes3, offset + 1024);
40795
+ owner.reserve({ work: end - offset }).release();
40796
+ await owner.ledger.checkpoint(signal, end - offset);
40797
+ if (text3 !== void 0) try {
40798
+ text3 += decoder2.decode(input3.subarray(offset, end), { stream: end < bytes3 });
40799
+ } catch (error) {
40800
+ if (!(error instanceof TypeError) || "code" in error && error.code !== "ERR_ENCODING_INVALID_ENCODED_DATA") throw error;
40801
+ text3 = void 0;
40802
+ }
40803
+ }
40804
+ if (text3 !== void 0) return await textToken(owner, text3, signal);
40805
+ const admission = owner.reserve({ payload: bytes3 * 4, metadata: 128, work: 4 });
40806
+ try {
40807
+ const raw = shellValueFromBytes(input3);
40808
+ return new OwnedText(shellValueText(raw), bytes3, admission, raw);
40809
+ } catch (error) {
40810
+ admission.release();
40811
+ throw error;
40812
+ }
40813
+ } finally {
40814
+ temporary.release();
40815
+ }
40816
+ }
40778
40817
  var IndexedBinding = class _IndexedBinding {
40779
- constructor(owner) {
40818
+ constructor(owner, associative = false) {
40780
40819
  this.owner = owner;
40820
+ this.associative = associative;
40781
40821
  }
40782
40822
  owner;
40823
+ associative;
40783
40824
  values = /* @__PURE__ */ new Map();
40825
+ keys = /* @__PURE__ */ new Map();
40826
+ keyByIndex = /* @__PURE__ */ new Map();
40784
40827
  maximum = -1;
40785
40828
  generation = 0;
40786
40829
  version = 0;
40787
40830
  references = 1;
40788
40831
  assigned = false;
40789
- static create(parent) {
40832
+ static create(parent, associative = false) {
40790
40833
  const owner = ArrayOwner.create(parent.ledger, parent);
40791
40834
  try {
40792
40835
  owner.reserve({ wrappers: 1, metadata: 128, work: 7 });
40793
- return new _IndexedBinding(owner);
40836
+ return new _IndexedBinding(owner, associative);
40794
40837
  } catch (error) {
40795
40838
  void owner.close();
40796
40839
  throw error;
40797
40840
  }
40798
40841
  }
40842
+ async keyIdentity(value2, owner, signal) {
40843
+ const length = shellValueByteLength(value2);
40844
+ if (!length) throw new ArrayFailure("bad array subscript");
40845
+ const admission = owner.reserve({ payload: length * 5, metadata: 64 + length * 16, work: length + 2 });
40846
+ try {
40847
+ const bytes3 = shellValueBytes(value2);
40848
+ const parts = [];
40849
+ for (const byte of bytes3) {
40850
+ parts.push(byte.toString(16).padStart(2, "0"));
40851
+ await owner.ledger.checkpoint(signal);
40852
+ }
40853
+ return parts.join("");
40854
+ } finally {
40855
+ admission.release();
40856
+ }
40857
+ }
40858
+ async keyIndex(value2, owner, signal, create = false) {
40859
+ const identity2 = await this.keyIdentity(value2, owner, signal);
40860
+ const existing2 = this.keys.get(identity2);
40861
+ if (existing2 || !create) return existing2?.index;
40862
+ const index = this.maximum + 1;
40863
+ const admission = this.owner.reserve({ metadata: 128 + identity2.length * 2, work: 8 });
40864
+ let text3;
40865
+ try {
40866
+ text3 = await valueToken(this.owner, value2, signal);
40867
+ } catch (error) {
40868
+ admission.release();
40869
+ throw error;
40870
+ }
40871
+ const entry = { index, text: text3, admission };
40872
+ admission.cleanup = () => {
40873
+ if (this.keys.get(identity2) === entry) {
40874
+ this.keys.delete(identity2);
40875
+ this.keyByIndex.delete(index);
40876
+ }
40877
+ text3.release();
40878
+ };
40879
+ this.keys.set(identity2, entry);
40880
+ this.keyByIndex.set(index, identity2);
40881
+ this.maximum = index;
40882
+ return index;
40883
+ }
40884
+ remove(index) {
40885
+ this.values.get(index)?.slot.release();
40886
+ const identity2 = this.keyByIndex.get(index);
40887
+ if (identity2 !== void 0) this.keys.get(identity2)?.admission.release();
40888
+ }
40799
40889
  get(index) {
40800
40890
  return this.values.get(index)?.text.value;
40801
40891
  }
@@ -40822,13 +40912,30 @@ var IndexedBinding = class _IndexedBinding {
40822
40912
  previous?.slot.release();
40823
40913
  }
40824
40914
  async copy(signal) {
40825
- const copy2 = _IndexedBinding.create(this.owner.parent);
40915
+ const copy2 = _IndexedBinding.create(this.owner.parent, this.associative);
40826
40916
  copy2.assigned = this.assigned;
40827
40917
  this.retain();
40828
40918
  try {
40919
+ for (const [identity2, entry] of this.keys) {
40920
+ const admission = copy2.owner.reserve({ metadata: 128 + identity2.length * 2, work: identity2.length + 8 });
40921
+ copy2.owner.parent.adopt(entry.text.admission);
40922
+ const text3 = entry.text.retain();
40923
+ const cloned = { index: entry.index, text: text3, admission };
40924
+ admission.cleanup = () => {
40925
+ if (copy2.keys.get(identity2) === cloned) {
40926
+ copy2.keys.delete(identity2);
40927
+ copy2.keyByIndex.delete(entry.index);
40928
+ }
40929
+ text3.release();
40930
+ };
40931
+ copy2.keys.set(identity2, cloned);
40932
+ copy2.keyByIndex.set(entry.index, identity2);
40933
+ await copy2.owner.ledger.checkpoint(signal, identity2.length + 8);
40934
+ }
40829
40935
  for (const [index, element] of this.values) {
40830
40936
  copy2.owner.reserve({ work: 2 }).release();
40831
40937
  const slot = copy2.owner.reserve({ slots: 1, metadata: 32, work: 5 });
40938
+ copy2.owner.parent.adopt(element.text.admission);
40832
40939
  const text3 = element.text.retain();
40833
40940
  const cloned = { text: text3, slot };
40834
40941
  slot.cleanup = () => {
@@ -41011,6 +41118,116 @@ var BindingStore = class _BindingStore {
41011
41118
  }
41012
41119
  };
41013
41120
 
41121
+ // packages/safe-bash/src/shell/mapfile.ts
41122
+ init_platform();
41123
+ var MapfileUsageError = class extends Error {
41124
+ constructor(message3, status2) {
41125
+ super(message3);
41126
+ this.status = status2;
41127
+ }
41128
+ status;
41129
+ };
41130
+ async function mapfileOptions(context2, work, allocation) {
41131
+ const options3 = { name: "MAPFILE", strip: false, delimiter: 10, count: 0, skip: 0, origin: 0, preserve: false, callback: void 0, quantum: 5e3 };
41132
+ const args = getCommandArguments(context2);
41133
+ let cursor = 0;
41134
+ const numeric4 = async (text3, maximum) => {
41135
+ let value2 = 0;
41136
+ let index = 0;
41137
+ const whitespace2 = (code) => code === 32 || code >= 9 && code <= 13;
41138
+ while (index < text3.length && whitespace2(text3.charCodeAt(index))) {
41139
+ const pending = stringCheckpoint(work);
41140
+ if (pending) await pending;
41141
+ index++;
41142
+ }
41143
+ const negative = text3[index] === "-";
41144
+ if (negative || text3[index] === "+") index++;
41145
+ let digits = 0;
41146
+ for (; index < text3.length; index++) {
41147
+ const pending = stringCheckpoint(work);
41148
+ if (pending) await pending;
41149
+ const digit3 = text3.charCodeAt(index) - 48;
41150
+ if (digit3 < 0 || digit3 > 9) break;
41151
+ if (value2 > Math.floor((maximum - digit3) / 10)) throw new MapfileUsageError(`${text3}: invalid number`, 1);
41152
+ value2 = value2 * 10 + digit3;
41153
+ digits++;
41154
+ }
41155
+ for (; index < text3.length; index++) {
41156
+ const pending = stringCheckpoint(work);
41157
+ if (pending) await pending;
41158
+ if (!whitespace2(text3.charCodeAt(index))) throw new MapfileUsageError(`${text3}: invalid number`, 1);
41159
+ }
41160
+ if (!digits || negative && value2 !== 0) throw new MapfileUsageError(`${text3}: invalid number`, 1);
41161
+ return value2;
41162
+ };
41163
+ while (cursor < context2.args.length) {
41164
+ const option = context2.args[cursor];
41165
+ if (option === "--") {
41166
+ cursor++;
41167
+ break;
41168
+ }
41169
+ if (!option.startsWith("-") || option === "-") break;
41170
+ cursor++;
41171
+ for (let index = 1; index < option.length; index++) {
41172
+ const pending = stringCheckpoint(work);
41173
+ if (pending) await pending;
41174
+ const flag = option[index];
41175
+ if (flag === "t") {
41176
+ options3.strip = true;
41177
+ continue;
41178
+ }
41179
+ if (!"dnsOCc".includes(flag)) throw new MapfileUsageError(`-${flag}: invalid option`, 2);
41180
+ const attached = index + 1 < option.length;
41181
+ const operandIndex = attached ? cursor - 1 : cursor++;
41182
+ const operand = attached ? option.slice(index + 1) : context2.args[operandIndex];
41183
+ if (operand === void 0) throw new MapfileUsageError(`-${flag}: option requires an argument`, 2);
41184
+ if (flag === "d") {
41185
+ const bytes3 = shellValueBytes(args.values[operandIndex], allocation);
41186
+ options3.delimiter = bytes3[attached ? index + 1 : 0] ?? 0;
41187
+ } else if (flag === "C") options3.callback = operand;
41188
+ else {
41189
+ const value2 = await numeric4(operand, flag === "O" ? 2147483647 : Number.MAX_SAFE_INTEGER);
41190
+ if (flag === "c") {
41191
+ if (!value2) throw new MapfileUsageError("0: invalid callback quantum", 1);
41192
+ options3.quantum = value2;
41193
+ } else if (flag === "n") options3.count = value2;
41194
+ else if (flag === "s") options3.skip = value2;
41195
+ else {
41196
+ options3.origin = value2;
41197
+ options3.preserve = true;
41198
+ }
41199
+ }
41200
+ break;
41201
+ }
41202
+ }
41203
+ options3.name = context2.args[cursor] ?? "MAPFILE";
41204
+ if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(options3.name)) throw new MapfileUsageError(`${options3.name}: invalid identifier`, 1);
41205
+ return options3;
41206
+ }
41207
+ async function collectMapfile(options3, input3, hooks) {
41208
+ let skipped = 0;
41209
+ let written = 0;
41210
+ while (!options3.count || written < options3.count) {
41211
+ hooks.loop();
41212
+ const allocation = hooks.allocation();
41213
+ try {
41214
+ const record4 = await input3.mapfileRecord(options3.delimiter, options3.strip, allocation);
41215
+ if (!record4.present) break;
41216
+ if (skipped < options3.skip) {
41217
+ skipped++;
41218
+ continue;
41219
+ }
41220
+ const index = options3.origin + written;
41221
+ if (index > 2147483647) throw new MapfileUsageError("array index exceeds 2147483647", 1);
41222
+ if (options3.callback !== void 0 && (written + 1) % options3.quantum === 0) await hooks.callback(options3.callback, index, record4.value);
41223
+ await hooks.write(index, record4.value);
41224
+ written++;
41225
+ } finally {
41226
+ allocation.close();
41227
+ }
41228
+ }
41229
+ }
41230
+
41014
41231
  // packages/safe-bash/src/shell/arrays/state.ts
41015
41232
  init_platform();
41016
41233
  var sessions = /* @__PURE__ */ new WeakMap();
@@ -41609,6 +41826,138 @@ function* pathTargets(name2, path, limits, signal, fail4) {
41609
41826
  }
41610
41827
  }
41611
41828
 
41829
+ // packages/safe-bash/src/shell/parameter-transforms.ts
41830
+ init_platform();
41831
+ function hexadecimal(byte) {
41832
+ return byte >= 48 && byte <= 57 ? byte - 48 : byte >= 65 && byte <= 70 ? byte - 55 : byte >= 97 && byte <= 102 ? byte - 87 : -1;
41833
+ }
41834
+ function utf8Unit(bytes3, offset) {
41835
+ const first = bytes3[offset];
41836
+ if (first < 128) return { point: first, size: 1 };
41837
+ const size = first >= 194 && first <= 223 ? 2 : first >= 224 && first <= 239 ? 3 : first >= 240 && first <= 244 ? 4 : 0;
41838
+ if (!size || offset + size > bytes3.length) return { point: -1, size: 1 };
41839
+ let point = first & 127 >> size;
41840
+ for (let index = 1; index < size; index++) {
41841
+ const byte = bytes3[offset + index];
41842
+ if (byte < 128 || byte > 191) return { point: -1, size: 1 };
41843
+ point = point * 64 + (byte & 63);
41844
+ }
41845
+ if (point < (size === 2 ? 128 : size === 3 ? 2048 : 65536) || point > 1114111 || point >= 55296 && point <= 57343) return { point: -1, size: 1 };
41846
+ return { point, size };
41847
+ }
41848
+ var controlEscapes = { 7: 97, 8: 98, 9: 116, 10: 110, 11: 118, 12: 102, 13: 114, 27: 69 };
41849
+ var decodedEscapes = { 97: 7, 98: 8, 116: 9, 110: 10, 118: 11, 102: 12, 114: 13, 101: 27, 69: 27, 92: 92, 39: 39, 34: 34, 63: 63 };
41850
+ async function transformParameter(value2, operator, options3) {
41851
+ const { work, allocation, maximumBytes } = options3;
41852
+ work.signal.throwIfAborted();
41853
+ if (typeof value2 === "string") {
41854
+ if (value2.length > maximumBytes) work.exhausted();
41855
+ if ((await scanString(value2, work)).bytes > maximumBytes) work.exhausted();
41856
+ } else if (shellValueByteLength(value2) > maximumBytes) work.exhausted();
41857
+ const input3 = shellValueBytes(value2, allocation);
41858
+ let ansi = false;
41859
+ if (operator === "Q") {
41860
+ for (let offset = 0; offset < input3.length; ) {
41861
+ const pending = stringCheckpoint(work);
41862
+ if (pending) await pending;
41863
+ const unit2 = options3.byteLocale ? { point: input3[offset], size: 1 } : utf8Unit(input3, offset);
41864
+ const printable = unit2.point >= 32 && unit2.point < 127 || !options3.byteLocale && unit2.point >= 128 && !/[\p{Cc}\p{Cf}\p{Cn}]/u.test(String.fromCodePoint(unit2.point));
41865
+ if (!printable) ansi = true;
41866
+ offset += unit2.size;
41867
+ }
41868
+ }
41869
+ let output2 = void 0;
41870
+ let size = 0;
41871
+ const emit2 = (byte) => {
41872
+ if (size >= maximumBytes) work.exhausted();
41873
+ if (output2) output2[size] = byte;
41874
+ size++;
41875
+ };
41876
+ const ascii2 = (text3) => {
41877
+ for (let index = 0; index < text3.length; index++) emit2(text3.charCodeAt(index));
41878
+ };
41879
+ const scan = async () => {
41880
+ size = 0;
41881
+ if (operator === "Q") {
41882
+ ascii2(ansi ? "$'" : "'");
41883
+ for (let offset = 0; offset < input3.length; ) {
41884
+ const pending = stringCheckpoint(work);
41885
+ if (pending) await pending;
41886
+ const unit2 = options3.byteLocale ? { point: input3[offset], size: 1 } : utf8Unit(input3, offset);
41887
+ const printable = unit2.point >= 32 && unit2.point < 127 || !options3.byteLocale && unit2.point >= 128 && !/[\p{Cc}\p{Cf}\p{Cn}]/u.test(String.fromCodePoint(unit2.point));
41888
+ if (ansi && !printable) {
41889
+ if (unit2.size === 1 && controlEscapes[input3[offset]] !== void 0) {
41890
+ emit2(92);
41891
+ emit2(controlEscapes[input3[offset]]);
41892
+ } else for (let index = 0; index < unit2.size; index++) ascii2("\\" + input3[offset + index].toString(8).padStart(3, "0"));
41893
+ } else if (unit2.point === 39) ascii2(ansi ? "\\'" : "'\\''");
41894
+ else if (ansi && unit2.point === 92) ascii2("\\\\");
41895
+ else for (let index = 0; index < unit2.size; index++) emit2(input3[offset + index]);
41896
+ offset += unit2.size;
41897
+ }
41898
+ emit2(39);
41899
+ return;
41900
+ }
41901
+ for (let offset = 0; offset < input3.length; ) {
41902
+ const pending = stringCheckpoint(work);
41903
+ if (pending) await pending;
41904
+ let byte = input3[offset++];
41905
+ if (byte === 92 && offset < input3.length) {
41906
+ const escape = input3[offset++];
41907
+ if (decodedEscapes[escape] !== void 0) byte = decodedEscapes[escape];
41908
+ else if (escape >= 48 && escape <= 55) {
41909
+ byte = escape - 48;
41910
+ for (let count2 = 1; count2 < 3 && offset < input3.length && input3[offset] >= 48 && input3[offset] <= 55; count2++) byte = byte * 8 + input3[offset++] - 48;
41911
+ byte &= 255;
41912
+ } else if (escape === 120 || escape === 117 || escape === 85) {
41913
+ const maximum = escape === 120 ? 2 : escape === 117 ? 4 : 8;
41914
+ let point = 0;
41915
+ let count2 = 0;
41916
+ while (count2 < maximum && offset < input3.length && hexadecimal(input3[offset]) >= 0) {
41917
+ point = point * 16 + hexadecimal(input3[offset++]);
41918
+ count2++;
41919
+ }
41920
+ if (!count2) {
41921
+ emit2(92);
41922
+ emit2(escape);
41923
+ continue;
41924
+ }
41925
+ if (escape === 120) byte = point;
41926
+ else {
41927
+ if (!point || point >= 2147483648) return;
41928
+ if (options3.byteLocale && point >= 55296 && point <= 57343) ascii2(`\\u${point.toString(16).toUpperCase().padStart(4, "0")}`);
41929
+ else {
41930
+ const width = point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : point < 2097152 ? 4 : point < 67108864 ? 5 : 6;
41931
+ if (width === 1) emit2(point);
41932
+ else {
41933
+ const divisor = 64 ** (width - 1);
41934
+ emit2(256 - 2 ** (8 - width) + Math.floor(point / divisor));
41935
+ for (let shift = width - 2; shift >= 0; shift--) emit2(128 + Math.floor(point / 64 ** shift) % 64);
41936
+ }
41937
+ }
41938
+ continue;
41939
+ }
41940
+ } else if (escape === 99 && offset < input3.length) {
41941
+ const control = input3[offset++];
41942
+ if (control === 92 && input3[offset] === 92) offset++;
41943
+ byte = control === 63 ? 127 : control & 31;
41944
+ } else {
41945
+ emit2(92);
41946
+ byte = escape;
41947
+ }
41948
+ }
41949
+ if (!byte) return;
41950
+ emit2(byte);
41951
+ }
41952
+ };
41953
+ await scan();
41954
+ allocation.reserve(size + 64, 1);
41955
+ output2 = new Uint8Array(size);
41956
+ await scan();
41957
+ work.signal.throwIfAborted();
41958
+ return shellValueFromBytes(output2, allocation);
41959
+ }
41960
+
41612
41961
  // packages/safe-bash/src/shell/runtime.ts
41613
41962
  var defaultLimits = {
41614
41963
  maxParseUnits: defaultMaxParseUnits,
@@ -41640,6 +41989,9 @@ var shellBuiltinNames = /* @__PURE__ */ new Set([
41640
41989
  "local",
41641
41990
  "unset",
41642
41991
  "read",
41992
+ "declare",
41993
+ "mapfile",
41994
+ "readarray",
41643
41995
  "exit",
41644
41996
  "return",
41645
41997
  "break",
@@ -42638,6 +42990,7 @@ var InvocationCancellationOwner = class {
42638
42990
  this.#failures.push(...result2.failures);
42639
42991
  }
42640
42992
  };
42993
+ var mapfileCallbackStates = /* @__PURE__ */ new WeakSet();
42641
42994
  var Runtime = class _Runtime {
42642
42995
  constructor(fs, commands, middleware, budget, signal = budget.signal, fileWrites = /* @__PURE__ */ new Map(), outputFiles = /* @__PURE__ */ new Map(), commandSignal = signal, cancellation, cancellationState, cancellationOwner, cancellationDepth, cancellationMaxDepth, outcomeFrame = void 0, inputProfile = fs) {
42643
42996
  this.fs = fs;
@@ -42949,6 +43302,18 @@ var Runtime = class _Runtime {
42949
43302
  this.signal.throwIfAborted();
42950
43303
  if (error instanceof NounsetFailure || error instanceof Flow2 || error instanceof ShellLimitError || error instanceof ShellSyntaxError) throw error;
42951
43304
  }
43305
+ arithmeticValue(program, state, io) {
43306
+ return evaluatePositionalArithmetic(program, {
43307
+ parseBudget: this.budget.parsing,
43308
+ positional: state.positional,
43309
+ arg0: state.arg0 ?? "virtual-bash",
43310
+ owner: arrayStore(state)?.owner,
43311
+ maximumBytes: this.budget.limits.maxExpansionBytes,
43312
+ checkpoint: () => this.signal.throwIfAborted(),
43313
+ requireParameter: (name2, value2) => this.requireParameter(value2, name2, state, io),
43314
+ limit: () => this.budget.fail("maxExpansionBytes")
43315
+ }, (prepared) => evaluateArithmetic(prepared, this.arithmeticVariables(state, io.diagnosticLine), this.budget.parsing));
43316
+ }
42952
43317
  arithmeticVariables(state, line) {
42953
43318
  return new Proxy(state.variables, {
42954
43319
  get: (target, key) => {
@@ -42966,7 +43331,7 @@ var Runtime = class _Runtime {
42966
43331
  }
42967
43332
  variable(state, name2) {
42968
43333
  const binding = arrayStore(state)?.get(name2);
42969
- return binding ? binding.get(0) : state.variables[name2];
43334
+ return binding ? binding.get(binding.associative ? binding.keys.get("30")?.index ?? -1 : 0) : state.variables[name2];
42970
43335
  }
42971
43336
  requireParameter(value2, name2, state, io, line) {
42972
43337
  if (state.nounset && value2 === void 0) throw new NounsetFailure(`${name2}: unbound variable`, io.diagnosticLine ?? line);
@@ -42976,7 +43341,7 @@ var Runtime = class _Runtime {
42976
43341
  this.writeVariable(state, name2, value2, origin);
42977
43342
  return;
42978
43343
  }
42979
- await this.arrayZero(state, name2, async () => shellValueText(value2));
43344
+ await this.arrayZero(state, name2, async () => value2);
42980
43345
  }
42981
43346
  async prepareVariable(state, name2, saved, scalarLegacy = false) {
42982
43347
  const store = requireArrays(state);
@@ -43102,7 +43467,7 @@ var Runtime = class _Runtime {
43102
43467
  if (key !== index && key > maximum) maximum = key;
43103
43468
  await operation2.ledger.checkpoint(this.signal, 2);
43104
43469
  }
43105
- if (typeof index === "number") staged.values.get(index)?.slot.release();
43470
+ if (typeof index === "number") staged.remove(index);
43106
43471
  staged.maximum = maximum;
43107
43472
  }
43108
43473
  this.signal.throwIfAborted();
@@ -43133,6 +43498,7 @@ var Runtime = class _Runtime {
43133
43498
  const store = requireArrays(state);
43134
43499
  const operation2 = ArrayOwner.create(store.owner.ledger, store.owner);
43135
43500
  const holding = store.owner.hold();
43501
+ const valueAllocation = this.budget.values.scope();
43136
43502
  let staged;
43137
43503
  try {
43138
43504
  const watch = await store.watch(name2, operation2, this.signal);
@@ -43149,10 +43515,12 @@ var Runtime = class _Runtime {
43149
43515
  const current = store.get(name2);
43150
43516
  if (!current) throw new ArrayFailure("stale binding");
43151
43517
  staged = await current.copy(this.signal);
43152
- const value2 = append ? await this.arrayJoin(operation2, [current.get(0) ?? "", expanded], "") : expanded;
43153
- const token = await textToken(staged.owner, value2, this.signal);
43518
+ const index = staged.associative ? await staged.keyIndex("0", operation2, this.signal, true) : 0;
43519
+ const previous = current.values.get(index)?.text.rawValue ?? current.get(index) ?? "";
43520
+ const value2 = !append ? expanded : typeof previous === "string" && typeof expanded === "string" ? await this.arrayJoin(operation2, [previous, expanded], "") : concatShellValues([previous, expanded], valueAllocation);
43521
+ const token = await valueToken(staged.owner, value2, this.signal);
43154
43522
  try {
43155
- staged.insert(0, token);
43523
+ staged.insert(index, token);
43156
43524
  } catch (error) {
43157
43525
  token.release();
43158
43526
  throw error;
@@ -43178,6 +43546,7 @@ var Runtime = class _Runtime {
43178
43546
  await staged?.release();
43179
43547
  await operation2.close();
43180
43548
  } finally {
43549
+ valueAllocation.close();
43181
43550
  holding.release();
43182
43551
  }
43183
43552
  }
@@ -43196,10 +43565,33 @@ var Runtime = class _Runtime {
43196
43565
  await owner.ledger.checkpoint(this.signal);
43197
43566
  return result2;
43198
43567
  }
43568
+ async arrayIndex(binding, index, state, io, owner, create = false) {
43569
+ if (!binding?.associative) {
43570
+ const selected = index.source === void 0 ? index : literalIndex(index.source, 0, this.budget.parsing);
43571
+ const number5 = numericIndex(selected);
43572
+ if (number5 === void 0) throw new ArrayFailure("index outside 0..2147483647");
43573
+ return number5;
43574
+ }
43575
+ const word = index.word ?? parseArraySubscript(index.source ?? index.decimal, this.budget.parsing, byteLocale(state.variables), state.depth);
43576
+ const fields3 = await this.valueWord(word, state, io, false);
43577
+ const value2 = fields3.length === 1 ? fields3[0] : concatShellValues(fields3, io[valueScope]);
43578
+ if (shellValueByteLength(value2) === 0) {
43579
+ await this.diagnostic(io, "associative array: bad array subscript");
43580
+ if (create) throw completedExit(1);
43581
+ return void 0;
43582
+ }
43583
+ return binding.keyIndex(value2, owner, this.signal, create);
43584
+ }
43199
43585
  async arrayAssignment(assignment, state, io) {
43200
43586
  const name2 = assignment.name;
43201
43587
  this.signal.throwIfAborted();
43202
- if (state.readonlyVariables?.has(name2)) throw new ArrayFailure("readonly binding");
43588
+ if (state.readonlyVariables?.has(name2)) {
43589
+ if (arrayStore(state)?.get(name2)?.associative) {
43590
+ await this.diagnostic(io, `${name2}: readonly variable`);
43591
+ throw completedExit(1);
43592
+ }
43593
+ throw new ArrayFailure("readonly binding");
43594
+ }
43203
43595
  if (controlNames.has(name2)) throw new ArrayFailure("control binding cannot be indexed");
43204
43596
  if (state.exported.has(name2)) throw new ArrayFailure("exported binding cannot be indexed");
43205
43597
  const store = requireArrays(state);
@@ -43209,11 +43601,12 @@ var Runtime = class _Runtime {
43209
43601
  try {
43210
43602
  const watch = await store.watch(name2, operation2, this.signal);
43211
43603
  const current = store.get(name2);
43604
+ if (current?.associative && assignment.kind === "compound" && assignment.entries.length) throw new ArrayFailure("nonempty associative compound assignment is unsupported");
43212
43605
  const initialMaximum = current?.maximum ?? (state.variables[name2] === void 0 ? -1 : 0);
43213
43606
  let planned = assignment.append && assignment.kind === "compound" ? initialMaximum + 1 : 0;
43214
43607
  if (assignment.kind === "element") {
43215
43608
  operation2.reserve({ work: assignment.index.decimal.length + 1 }).release();
43216
- if (numericIndex(assignment.index) === void 0) throw new ArrayFailure("index outside 0..2147483647");
43609
+ if (!current?.associative && numericIndex(literalIndex(assignment.index.source ?? assignment.index.decimal, 0, this.budget.parsing)) === void 0) throw new ArrayFailure("index outside 0..2147483647");
43217
43610
  } else for (const entry of assignment.entries) {
43218
43611
  operation2.reserve({ work: entry.value.parts.length + (entry.index?.decimal.length ?? 0) + 2 }).release();
43219
43612
  if (entry.index) {
@@ -43239,9 +43632,9 @@ var Runtime = class _Runtime {
43239
43632
  const tickets = operation2.reserve({ generation: true, version: true, epoch: true, work: 8 });
43240
43633
  const prepared = await store.prepareName(name2, operation2, this.signal);
43241
43634
  const preserve = assignment.kind === "element" || assignment.append;
43242
- staged = preserve && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner);
43635
+ staged = preserve && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner, current?.associative);
43243
43636
  if (preserve && !current && state.variables[name2] !== void 0) {
43244
- const token = await textToken(staged.owner, state.variables[name2], this.signal);
43637
+ const token = await valueToken(staged.owner, stateMonitor(state)?.values.get(name2, state.variables[name2]) ?? state.variables[name2], this.signal);
43245
43638
  try {
43246
43639
  staged.insert(0, token);
43247
43640
  } catch (error) {
@@ -43253,7 +43646,7 @@ var Runtime = class _Runtime {
43253
43646
  let cursor = assignment.append && assignment.kind === "compound" ? initialMaximum + 1 : 0;
43254
43647
  const insert = async (index, value2) => {
43255
43648
  if (index > 2147483647) throw new ArrayFailure("index outside 0..2147483647");
43256
- const token = await textToken(staged.owner, value2, this.signal);
43649
+ const token = await valueToken(staged.owner, value2, this.signal);
43257
43650
  try {
43258
43651
  staged.insert(index, token);
43259
43652
  } catch (error) {
@@ -43262,11 +43655,12 @@ var Runtime = class _Runtime {
43262
43655
  }
43263
43656
  writes++;
43264
43657
  };
43658
+ const join = async (values) => values.every((value2) => typeof value2 === "string") ? this.arrayJoin(operation2, values, "") : concatShellValues(values, io[valueScope]);
43265
43659
  if (assignment.kind === "element") {
43266
- const index = numericIndex(assignment.index);
43267
- const fields3 = await this.word(assignment.value, state, io, false);
43268
- let value2 = await this.arrayJoin(operation2, fields3, "");
43269
- if (assignment.append) value2 = await this.arrayJoin(operation2, [staged.get(index) ?? "", value2], "");
43660
+ const index = await this.arrayIndex(staged, assignment.index, state, io, operation2, true);
43661
+ const fields3 = await this.valueWord(assignment.value, state, io, false);
43662
+ let value2 = await join(fields3);
43663
+ if (assignment.append) value2 = await join([staged.values.get(index)?.text.rawValue ?? staged.get(index) ?? "", value2]);
43270
43664
  await insert(index, value2);
43271
43665
  } else for (const entry of assignment.entries) {
43272
43666
  const original = compoundEntryWords.get(entry);
@@ -43277,16 +43671,16 @@ var Runtime = class _Runtime {
43277
43671
  expandedEntry = true;
43278
43672
  const values = await this.valueWord(expanded, state, io, true, false, false, false, void 0, false);
43279
43673
  for (const value2 of values) {
43280
- await insert(cursor, shellValueText(value2));
43674
+ await insert(cursor, value2);
43281
43675
  cursor++;
43282
43676
  }
43283
43677
  }
43284
43678
  if (expandedEntry) continue;
43285
43679
  }
43286
- const fields3 = await this.word(entry.value, state, io, entry.index === void 0);
43680
+ const fields3 = await this.valueWord(entry.value, state, io, entry.index === void 0);
43287
43681
  if (entry.index) {
43288
43682
  const index = numericIndex(entry.index);
43289
- await insert(index, await this.arrayJoin(operation2, fields3, ""));
43683
+ await insert(index, await join(fields3));
43290
43684
  cursor = index + 1;
43291
43685
  } else for (const value2 of fields3) {
43292
43686
  await insert(cursor, value2);
@@ -43649,16 +44043,7 @@ var Runtime = class _Runtime {
43649
44043
  }
43650
44044
  if (command7.kind === "arithmetic") {
43651
44045
  try {
43652
- return Number(evaluatePositionalArithmetic(command7.expression, {
43653
- parseBudget: this.budget.parsing,
43654
- positional: state.positional,
43655
- arg0: state.arg0 ?? "virtual-bash",
43656
- owner: arrayStore(state)?.owner,
43657
- maximumBytes: this.budget.limits.maxExpansionBytes,
43658
- checkpoint: () => this.signal.throwIfAborted(),
43659
- requireParameter: (name2, value2) => this.requireParameter(value2, name2, state, io),
43660
- limit: () => this.budget.fail("maxExpansionBytes")
43661
- }, (prepared) => evaluateArithmetic(prepared, this.arithmeticVariables(state, io.diagnosticLine), this.budget.parsing)) === 0n);
44046
+ return Number(this.arithmeticValue(command7.expression, state, io) === 0n);
43662
44047
  } catch (error) {
43663
44048
  this.rethrowArithmeticControl(error);
43664
44049
  throw new PublicDiagnostic(`((: ${message2(error, this.budget.onInternalError)}`);
@@ -43717,6 +44102,87 @@ var Runtime = class _Runtime {
43717
44102
  status3 = result2.status;
43718
44103
  if (result2.stop) break;
43719
44104
  }
44105
+ } else if (command7.kind === "arithmetic-for") {
44106
+ const evaluate = async (program) => {
44107
+ if (!program) return 1n;
44108
+ try {
44109
+ return this.arithmeticValue(program, state, io);
44110
+ } catch (error) {
44111
+ this.rethrowArithmeticControl(error);
44112
+ await this.diagnostic(io, `((: ${message2(error, this.budget.onInternalError)}`);
44113
+ return void 0;
44114
+ }
44115
+ };
44116
+ if (await evaluate(command7.expressions[0]) === void 0) return 1;
44117
+ while (true) {
44118
+ this.budget.loop();
44119
+ await yieldTurn(this.signal);
44120
+ const condition = await evaluate(command7.expressions[1]);
44121
+ if (condition === void 0) return 1;
44122
+ if (condition === 0n) break;
44123
+ const result2 = await this.loopBody(command7.body, state, io);
44124
+ status3 = result2.status;
44125
+ if (result2.stop) break;
44126
+ if (await evaluate(command7.expressions[2]) === void 0) return 1;
44127
+ }
44128
+ } else if (command7.kind === "select") {
44129
+ const values = command7.words ? await this.valueWords(command7.words, state, io) : this.positionalValues(state);
44130
+ if (!values.length) return 0;
44131
+ const input3 = io.stdin instanceof ShellInput ? io.stdin : new ShellInput(io.stdin, this.budget, this.signal);
44132
+ const work = { remaining: this.budget.limits.maxExpansionBytes * 8, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
44133
+ let showMenu = true;
44134
+ while (true) {
44135
+ this.budget.loop();
44136
+ if (showMenu) await selectMenu(values, state.variables.COLUMNS, byteLocale(state.variables), io.stderr, work, allocation);
44137
+ const prompt = stateMonitor(state)?.values.get("PS3", state.variables.PS3 ?? "#? ") ?? state.variables.PS3 ?? "#? ";
44138
+ await io.stderr.write(shellValueBytes(prompt, allocation));
44139
+ const line = await input3.selectLine(allocation);
44140
+ if (state.readonlyVariables?.has("REPLY")) {
44141
+ await this.diagnostic(io, "REPLY: readonly variable");
44142
+ await writeText(io.stdout, "\n");
44143
+ return 1;
44144
+ }
44145
+ this.writeVariable(state, "REPLY", line.value);
44146
+ if (!line.terminated) {
44147
+ await writeText(io.stdout, "\n");
44148
+ return 1;
44149
+ }
44150
+ const bytes3 = shellValueBytes(line.value, allocation);
44151
+ if (!bytes3.length) {
44152
+ showMenu = true;
44153
+ continue;
44154
+ }
44155
+ let choice = 0;
44156
+ let phase = "start";
44157
+ let valid = true;
44158
+ let negative = false;
44159
+ let digits = false;
44160
+ for (const byte of bytes3) {
44161
+ const pending = stringCheckpoint(work);
44162
+ if (pending) await pending;
44163
+ if (byte === 32 || byte >= 9 && byte <= 13) {
44164
+ if (phase === "digits") phase = "tail";
44165
+ continue;
44166
+ }
44167
+ if (phase === "start" && (byte === 43 || byte === 45)) {
44168
+ negative = byte === 45;
44169
+ phase = "digits";
44170
+ continue;
44171
+ }
44172
+ if (phase === "tail" || byte < 48 || byte > 57) {
44173
+ valid = false;
44174
+ continue;
44175
+ }
44176
+ phase = "digits";
44177
+ digits = true;
44178
+ choice = Math.min(values.length + 1, choice * 10 + byte - 48);
44179
+ }
44180
+ await this.assignVariable(state, command7.name, valid && digits && !negative && choice >= 1 && choice <= values.length ? values[choice - 1] : "");
44181
+ const result2 = await this.loopBody(command7.body, state, io);
44182
+ status3 = result2.status;
44183
+ if (result2.stop) break;
44184
+ showMenu = shellValueByteLength(stateMonitor(state)?.values.get("REPLY", state.variables.REPLY ?? "") ?? state.variables.REPLY ?? "") === 0;
44185
+ }
43720
44186
  } else {
43721
44187
  while (true) {
43722
44188
  this.budget.loop();
@@ -43815,6 +44281,7 @@ var Runtime = class _Runtime {
43815
44281
  async document(document, state, io, line = document.endLine) {
43816
44282
  this.signal.throwIfAborted();
43817
44283
  let value2 = "";
44284
+ let fragments;
43818
44285
  let size = 0;
43819
44286
  let words = 0;
43820
44287
  const warnings = [];
@@ -43824,16 +44291,25 @@ var Runtime = class _Runtime {
43824
44291
  for (const warning of warnings.splice(0)) await writeDiagnostic(io.stderr, `shell: warning: ${warning}
43825
44292
  `);
43826
44293
  if (++words % 128 === 0) await yieldTurn(this.signal);
43827
- const part = (await this.word(word, state, { ...io, nameExpansionContext: "document" }, false)).join("");
43828
- size += import_buffer.Buffer.byteLength(part);
44294
+ const part = concatShellValues(await this.valueWord(word, state, { ...io, nameExpansionContext: "document" }, false), io[valueScope]);
44295
+ size += shellValueByteLength(part);
43829
44296
  if (size > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
43830
- value2 += part;
44297
+ if (!fragments && typeof part === "string") value2 += part;
44298
+ else {
44299
+ if (!fragments) {
44300
+ io[valueScope]?.reserve(64 + value2.length * 2, 0);
44301
+ fragments = [value2];
44302
+ value2 = "";
44303
+ }
44304
+ io[valueScope]?.reserve(32 + (typeof part === "string" ? part.length * 2 : 0), 0);
44305
+ fragments.push(part);
44306
+ }
43831
44307
  }
43832
44308
  } finally {
43833
44309
  for (const warning of warnings.splice(0)) await writeDiagnostic(io.stderr, `shell: warning: ${warning}
43834
44310
  `);
43835
44311
  }
43836
- return value2;
44312
+ return fragments ? concatShellValues(fragments, io[valueScope]) : value2;
43837
44313
  }
43838
44314
  async redirect(redirects, state, io, inputs2, outputs, isolatedInlineInput = false, persistMoves = false, fileShortcut = false, line) {
43839
44315
  this.signal.throwIfAborted();
@@ -43862,6 +44338,7 @@ var Runtime = class _Runtime {
43862
44338
  const stdinIsDefault = descriptor2?.input ? descriptor2.stdinIsDefault : false;
43863
44339
  return {
43864
44340
  [invocationScope]: io[invocationScope],
44341
+ ...io[valueScope] === void 0 ? {} : { [valueScope]: io[valueScope] },
43865
44342
  ...io.execution === void 0 ? {} : { execution: io.execution },
43866
44343
  ...io.diagnosticLine === void 0 ? {} : { diagnosticLine: io.diagnosticLine },
43867
44344
  ...io.diagnosticOffset === void 0 ? {} : { diagnosticOffset: io.diagnosticOffset },
@@ -43882,7 +44359,7 @@ var Runtime = class _Runtime {
43882
44359
  const hereString = redirect.operator === "<<<";
43883
44360
  let value2;
43884
44361
  try {
43885
- value2 = redirect.document ? await this.document(redirect.document, state, currentIO(), line) : (await this.word(redirect.target, state, currentIO(), false, false, hereString)).join("");
44362
+ value2 = redirect.document ? await this.document(redirect.document, state, currentIO(), line) : concatShellValues(await this.valueWord(redirect.target, state, currentIO(), false, false, hereString), io[valueScope]);
43886
44363
  } catch (error) {
43887
44364
  if (error instanceof NounsetFailure) throw error;
43888
44365
  if (error instanceof ParameterExpansionFailure && !isolatedInlineInput) throw error;
@@ -43891,10 +44368,10 @@ var Runtime = class _Runtime {
43891
44368
  throw error;
43892
44369
  }
43893
44370
  if (hereString) {
43894
- if (import_buffer.Buffer.byteLength(value2) >= this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
43895
- value2 += "\n";
44371
+ if (shellValueByteLength(value2) >= this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
44372
+ value2 = concatShellValues([value2, "\n"], io[valueScope]);
43896
44373
  }
43897
- const input3 = new ShellInput(toByteSource(value2), this.budget, this.signal);
44374
+ const input3 = new ShellInput(toByteSource(typeof value2 === "string" ? value2 : shellValueBytes(value2, io[valueScope])), this.budget, this.signal);
43898
44375
  inputs2.add(input3);
43899
44376
  descriptors.set(redirect.descriptor, { input: input3, stdinIsDefault: false });
43900
44377
  continue;
@@ -44094,8 +44571,8 @@ var Runtime = class _Runtime {
44094
44571
  throw new ArrayFailure("indexed binding cannot be a command prefix");
44095
44572
  }
44096
44573
  await this.arrayZero(state, assignment.name, async () => {
44097
- const fields3 = await this.word(assignment.value, state, io, false);
44098
- return this.arrayJoin(requireArrays(state).owner, fields3, "");
44574
+ const fields3 = await this.valueWord(assignment.value, state, io, false);
44575
+ return fields3.every((value3) => typeof value3 === "string") ? this.arrayJoin(requireArrays(state).owner, fields3, "") : concatShellValues(fields3, io[valueScope]);
44099
44576
  }, assignment.append);
44100
44577
  continue;
44101
44578
  }
@@ -44241,6 +44718,7 @@ var Runtime = class _Runtime {
44241
44718
  }
44242
44719
  async dispatchScoped(name2, values, state, io, assignments2, bypassFunctions) {
44243
44720
  const { [invocationScope]: scope, ...publicIO } = io;
44721
+ Reflect.deleteProperty(publicIO, valueScope);
44244
44722
  const allocation = this.budget.values.scope();
44245
44723
  scope.register(() => allocation.close());
44246
44724
  const argumentValues = this.admitArguments(values, allocation);
@@ -44289,7 +44767,13 @@ var Runtime = class _Runtime {
44289
44767
  scope.assertOpen();
44290
44768
  const forwardedValues = getCommandArguments(forwarded);
44291
44769
  const admitted = forwardedValues === argumentValues ? argumentValues : this.admitArguments(forwardedValues.values, allocation);
44292
- const context3 = { ...forwarded, args: admitted.args, argumentValues: admitted, [invocationScope]: scope };
44770
+ const context3 = {
44771
+ ...forwarded,
44772
+ args: admitted.args,
44773
+ argumentValues: admitted,
44774
+ [invocationScope]: scope,
44775
+ ...io[valueScope] === void 0 ? {} : { [valueScope]: io[valueScope] }
44776
+ };
44293
44777
  const previous = /* @__PURE__ */ new Map();
44294
44778
  const cwd = state.cwd;
44295
44779
  const directoryStackCwdPublication = state.directoryStackCwdPublication;
@@ -44407,6 +44891,8 @@ var Runtime = class _Runtime {
44407
44891
  functionRestoration?.close();
44408
44892
  throw error;
44409
44893
  }
44894
+ const callerLoopDepth = state.loopDepth;
44895
+ if (mapfileCallbackStates.has(state)) state.loopDepth = 0;
44410
44896
  try {
44411
44897
  return { exitCode: await this.command(body, state, { ...io, ...context3, scriptName: body.sourceName ?? io.scriptName ?? "shell" }) };
44412
44898
  } catch (error) {
@@ -44420,6 +44906,7 @@ var Runtime = class _Runtime {
44420
44906
  savedPositionals.close();
44421
44907
  state.positionalSetVersion = positionalSetVersion;
44422
44908
  state.functionDepth--;
44909
+ state.loopDepth = callerLoopDepth;
44423
44910
  state.depth--;
44424
44911
  state.locals.pop();
44425
44912
  };
@@ -44886,6 +45373,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
44886
45373
  return invocation2;
44887
45374
  }
44888
45375
  };
45376
+ Reflect.deleteProperty(context2, invocationScope);
45377
+ Reflect.deleteProperty(context2, valueScope);
44889
45378
  bindCommandIO(context2);
44890
45379
  bindFileOutputBudget(context2, (sink) => this.budget.sink(sink, runtime.signal));
44891
45380
  if (argumentValues.values.every((value2) => typeof value2 === "string")) Reflect.deleteProperty(context2, "argumentValues");
@@ -45889,12 +46378,120 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45889
46378
  allocation.close();
45890
46379
  }
45891
46380
  }
46381
+ async mapfileBuiltin(context2, state) {
46382
+ const allocation = this.budget.values.scope();
46383
+ const work = { remaining: this.budget.limits.maxExpansionBytes * 8, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
46384
+ let pinned;
46385
+ let releaseHolding;
46386
+ try {
46387
+ const options3 = await mapfileOptions(context2, work, allocation);
46388
+ if (arrayStore(state)?.get(options3.name)?.associative) throw new MapfileUsageError(`${options3.name}: not an indexed array`, 1);
46389
+ if (state.readonlyVariables?.has(options3.name)) throw new MapfileUsageError(`${options3.name}: readonly variable`, 1);
46390
+ if (controlNames.has(options3.name) || state.exported.has(options3.name)) throw new ArrayFailure("control or exported binding cannot be indexed");
46391
+ const store = requireArrays(state);
46392
+ const holding = store.owner.hold();
46393
+ releaseHolding = () => holding.release();
46394
+ if (!options3.preserve || !store.get(options3.name)) await this.arrayAssignment({ kind: "compound", name: options3.name, append: options3.preserve, entries: [] }, state, context2);
46395
+ const entry = store.bindings.get(options3.name);
46396
+ allocation.reserve(128 + import_buffer.Buffer.byteLength(options3.name) * 2, 0);
46397
+ pinned = entry.binding.retain();
46398
+ const input3 = context2.stdin instanceof ShellInput ? context2.stdin : new ShellInput(context2.stdin, this.budget, this.signal);
46399
+ let pendingFlow;
46400
+ await collectMapfile(options3, input3, {
46401
+ allocation: () => this.budget.values.scope(),
46402
+ loop: () => this.budget.loop(),
46403
+ write: async (index, value2) => {
46404
+ if (pinned !== entry.binding) {
46405
+ const previous = pinned;
46406
+ pinned = entry.binding.retain();
46407
+ await previous.release();
46408
+ }
46409
+ const operation2 = ArrayOwner.create(store.owner.ledger, store.owner);
46410
+ let staged;
46411
+ try {
46412
+ const current = pinned;
46413
+ const attached = store.bindings.get(options3.name) === entry;
46414
+ const watch = attached ? await store.watch(options3.name, operation2, this.signal) : void 0;
46415
+ const supersede = attached ? await stateMonitor(state).prepareTypedPublication(options3.name, operation2, this.signal) : void 0;
46416
+ if (attached) await this.prepareArrayObservers(state, operation2);
46417
+ const tickets = operation2.reserve({ generation: true, version: true, epoch: true, work: 8 });
46418
+ staged = current.references > (attached ? 2 : 1) ? await current.copy(this.signal) : current.retain();
46419
+ const token = await valueToken(staged.owner, value2, this.signal);
46420
+ try {
46421
+ this.signal.throwIfAborted();
46422
+ if (watch && !watch.valid()) throw new ArrayFailure("stale binding");
46423
+ staged.insert(index, token);
46424
+ } catch (error) {
46425
+ token.release();
46426
+ throw error;
46427
+ }
46428
+ if (attached) {
46429
+ let released;
46430
+ stateMonitor(state).publish(tickets, options3.name, () => {
46431
+ supersede();
46432
+ released = store.publish(options3.name, staged, tickets);
46433
+ });
46434
+ staged = void 0;
46435
+ await released;
46436
+ } else {
46437
+ const previous = pinned;
46438
+ pinned = staged;
46439
+ entry.binding = staged;
46440
+ staged = void 0;
46441
+ await previous.release();
46442
+ }
46443
+ } finally {
46444
+ try {
46445
+ await staged?.release();
46446
+ } finally {
46447
+ await operation2.close();
46448
+ }
46449
+ }
46450
+ },
46451
+ callback: async (source2, index, value2) => {
46452
+ if (pendingFlow) return;
46453
+ const callbackAllocation = this.budget.values.scope();
46454
+ const nested = mapfileCallbackStates.has(state);
46455
+ try {
46456
+ const quoted2 = shellValueText(await transformParameter(value2, "Q", { maximumBytes: this.budget.limits.maxExpansionBytes, byteLocale: byteLocale(state.variables), work, allocation: callbackAllocation }));
46457
+ if (import_buffer.Buffer.byteLength(source2) + import_buffer.Buffer.byteLength(quoted2) + String(index).length + 2 > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
46458
+ mapfileCallbackStates.add(state);
46459
+ await this.evalBuiltin({ ...context2, args: [source2, String(index), quoted2] }, state, context2, false);
46460
+ } catch (error) {
46461
+ if (error instanceof Flow2 && (error.kind === "break" || error.kind === "continue")) pendingFlow = error;
46462
+ else throw error;
46463
+ } finally {
46464
+ if (!nested) mapfileCallbackStates.delete(state);
46465
+ callbackAllocation.close();
46466
+ }
46467
+ }
46468
+ });
46469
+ if (pendingFlow) throw pendingFlow;
46470
+ return 0;
46471
+ } catch (error) {
46472
+ this.signal.throwIfAborted();
46473
+ if (!(error instanceof MapfileUsageError)) throw error;
46474
+ await this.diagnostic(context2, `${context2.command}: ${error.message}`);
46475
+ return error.status;
46476
+ } finally {
46477
+ try {
46478
+ await pinned?.release();
46479
+ } finally {
46480
+ try {
46481
+ releaseHolding?.();
46482
+ } finally {
46483
+ allocation.close();
46484
+ }
46485
+ }
46486
+ }
46487
+ }
45892
46488
  async builtin(context2, state, assignments2, diagnose, suppressSpecial = false) {
45893
46489
  const { command: command7, args, stdout, stderr } = context2;
45894
46490
  if (command7 === ":" || command7 === "true") return 0;
45895
46491
  if (command7 === "false") return 1;
45896
46492
  if (command7 === "shopt") return this.shoptBuiltin(context2, state);
45897
46493
  if (command7 === "let") return this.letBuiltin(context2, state);
46494
+ if (command7 === "mapfile" || command7 === "readarray") return this.mapfileBuiltin(context2, state);
45898
46495
  if (command7 === "getopts") return this.getoptsBuiltin(context2, state);
45899
46496
  if (command7 === "pushd" || command7 === "dirs" || command7 === "popd") return this.directoryStackBuiltin(context2, state, diagnose);
45900
46497
  if (command7 === "pwd") {
@@ -45959,9 +46556,16 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
45959
46556
  this.replacePositionals(state, this.positionalValues(state).slice(count2));
45960
46557
  return 0;
45961
46558
  }
45962
- if (command7 === "export" || command7 === "local" || command7 === "readonly") {
46559
+ if (command7 === "export" || command7 === "local" || command7 === "readonly" || command7 === "declare") {
46560
+ const associativeDeclaration = command7 === "declare";
45963
46561
  const declarationArgs = [...args];
45964
- let indexedLocal = false;
46562
+ let indexedLocal = associativeDeclaration;
46563
+ if (associativeDeclaration) {
46564
+ if (declarationArgs.shift() !== "-A" || !declarationArgs.length) {
46565
+ await this.diagnostic(context2, "declare: only -A NAME is supported");
46566
+ return 2;
46567
+ }
46568
+ }
45965
46569
  if (command7 === "local") {
45966
46570
  const options3 = localDeclarationOptions(declarationArgs, this.signal);
45967
46571
  if (options3.error !== void 0) {
@@ -46024,11 +46628,11 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46024
46628
  status2 = 1;
46025
46629
  continue;
46026
46630
  }
46027
- if (command7 === "local" && indexedLocal) {
46631
+ if ((command7 === "local" || associativeDeclaration) && indexedLocal) {
46028
46632
  if (controlNames.has(name2)) throw new ArrayFailure("control binding cannot be indexed");
46029
46633
  if (state.exported.has(name2)) throw new ArrayFailure("exported binding cannot be indexed");
46030
- const existingLocal = locals.get(name2);
46031
- const saved = existingLocal ? void 0 : assignments2.get(name2) ?? saveVariable(state, name2);
46634
+ const existingLocal = locals?.get(name2);
46635
+ const saved = !locals || existingLocal ? void 0 : assignments2.get(name2) ?? saveVariable(state, name2);
46032
46636
  let operation2;
46033
46637
  let holding;
46034
46638
  let shadow;
@@ -46053,12 +46657,14 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46053
46657
  const tickets = operation2.reserve({ generation: true, version: true, epoch: true, work: 8 });
46054
46658
  const prepared = await store.prepareName(name2, operation2, this.signal);
46055
46659
  const current = store.get(name2);
46056
- shadow = !saved && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner);
46660
+ if (!saved && current && current.associative !== associativeDeclaration) throw new ArrayFailure("cannot convert array kind");
46661
+ shadow = !saved && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner, associativeDeclaration);
46057
46662
  const value2 = match[2] ?? (!saved && !current && Object.hasOwn(state.variables, name2) ? state.variables[name2] : void 0);
46058
46663
  if (value2 !== void 0) {
46059
- const token = await textToken(shadow.owner, value2, this.signal);
46664
+ const retained = associativeDeclaration && match[2] === void 0 ? stateMonitor(state).values.get(name2, value2) : value2;
46665
+ const token = await valueToken(shadow.owner, retained, this.signal);
46060
46666
  try {
46061
- shadow.insert(0, token);
46667
+ shadow.insert(associativeDeclaration ? await shadow.keyIndex("0", operation2, this.signal, true) : 0, token);
46062
46668
  } catch (error) {
46063
46669
  token.release();
46064
46670
  throw error;
@@ -46206,7 +46812,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46206
46812
  }
46207
46813
  if (command7 === "unset") {
46208
46814
  let status2 = 0;
46209
- for (const name2 of args) {
46815
+ for (let argument2 = 0; argument2 < args.length; argument2++) {
46816
+ const name2 = args[argument2];
46210
46817
  const selected = /^([a-zA-Z_][a-zA-Z_0-9]*)\[(.*)\]$/su.exec(name2);
46211
46818
  if (selected) {
46212
46819
  const base = selected[1];
@@ -46216,7 +46823,12 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46216
46823
  status2 = 1;
46217
46824
  continue;
46218
46825
  }
46219
- if (selector === "@" || selector === "*") await this.unsetIndexed(state, base, "members");
46826
+ const binding = arrayStore(state)?.get(base);
46827
+ if (binding?.associative) {
46828
+ const original = getCommandArguments(context2).values[argument2];
46829
+ const index = typeof original === "string" ? await this.arrayIndex(binding, { decimal: selector, source: selector }, state, context2, binding.owner) : await binding.keyIndex(shellValueFromBytes(shellValueBytes(original, context2[valueScope]).subarray(base.length + 1, shellValueByteLength(original) - 1), context2[valueScope]), binding.owner, this.signal);
46830
+ if (index !== void 0) await this.unsetIndexed(state, base, index);
46831
+ } else if (selector === "@" || selector === "*") await this.unsetIndexed(state, base, "members");
46220
46832
  else {
46221
46833
  let index;
46222
46834
  try {
@@ -46447,6 +47059,31 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46447
47059
  }
46448
47060
  }
46449
47061
  async valuePart(part, state, io, hereString = false) {
47062
+ if (part.kind === "variable" && part.transform) {
47063
+ const selector2 = getArraySelector(part);
47064
+ if (selector2?.kind === "members" || part.name === "@" || part.name === "*") {
47065
+ const members = selector2 ? await this.arrayMembers(part.name, state, io, part.keys) : this.positionalValues(state);
47066
+ const ifs = state.variables.IFS ?? " ";
47067
+ const separator = ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
47068
+ const fragments = [];
47069
+ let bytes3 = 0;
47070
+ for (const member2 of members) {
47071
+ const value3 = await this.transformValue(member2, part.transform, state, io);
47072
+ bytes3 += shellValueByteLength(value3) + (fragments.length ? import_buffer.Buffer.byteLength(separator) : 0);
47073
+ if (bytes3 > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
47074
+ io[valueScope]?.reserve(32, 0);
47075
+ if (fragments.length) fragments.push(separator);
47076
+ fragments.push(value3);
47077
+ }
47078
+ return concatShellValues(fragments, io[valueScope]);
47079
+ }
47080
+ const base = { ...part };
47081
+ delete base.transform;
47082
+ copyArraySelector(part, base);
47083
+ const existing2 = selector2?.kind === "element" ? arrayStore(state)?.get(part.name)?.get(numericIndex(selector2.index) ?? -1) ?? (numericIndex(selector2.index) === 0 ? this.variable(state, part.name) : void 0) : /^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(part.name) ? this.variable(state, part.name) : /^[1-9][0-9]*$/u.test(part.name) ? state.positional[Number(part.name) - 1] : "";
47084
+ const value2 = await this.valuePart(base, state, io, hereString);
47085
+ return existing2 === void 0 ? "" : this.transformValue(value2, part.transform, state, io);
47086
+ }
46450
47087
  if (part.kind === "variable" && part.prefixNames) {
46451
47088
  const ifs = state.variables.IFS ?? " ";
46452
47089
  const separator = io.nameExpansionContext === "document" || io.nameExpansionContext === "conditional" && part.prefixNames === "@" ? " " : ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
@@ -46465,10 +47102,22 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46465
47102
  const binding = part.kind === "variable" ? arrayStore(state)?.get(part.name) : void 0;
46466
47103
  const holding = binding ? requireArrays(state).owner.hold() : void 0;
46467
47104
  const selector = getArraySelector(part);
46468
- const index = selector?.kind === "element" ? numericIndex(selector.index) : 0;
47105
+ if (selector?.kind === "element" && binding?.associative) {
47106
+ try {
47107
+ const index2 = await this.arrayIndex(binding, selector.index, state, io, binding.owner);
47108
+ const token2 = index2 === void 0 ? void 0 : binding.values.get(index2)?.text;
47109
+ this.requireParameter(token2?.value, part.kind === "variable" ? part.name : "", state, io);
47110
+ if (part.kind === "variable" && part.length) return this.parameterLength(token2?.value ?? "");
47111
+ return token2?.rawValue ? shellValueFromBytes(shellValueBytes(token2.rawValue, io[valueScope]), io[valueScope]) : token2?.value ?? "";
47112
+ } finally {
47113
+ holding?.release();
47114
+ }
47115
+ }
47116
+ const index = selector?.kind === "element" ? numericIndex(selector.index) : binding?.associative ? binding.keys.get("30")?.index : 0;
46469
47117
  const token = index === void 0 || selector?.kind === "members" ? void 0 : binding?.values.get(index)?.text;
46470
47118
  token?.retain();
46471
47119
  try {
47120
+ if (token?.rawValue && part.kind === "variable" && !part.length && !part.operator && !part.substring) return shellValueFromBytes(shellValueBytes(token.rawValue, io[valueScope]), io[valueScope]);
46472
47121
  const value2 = await this.partValue(part, state, io, hereString);
46473
47122
  if (binding) await textToken(requireArrays(state).owner, shellValueText(value2), this.signal);
46474
47123
  return value2;
@@ -46483,6 +47132,19 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46483
47132
  if (state.depth + parameterDepth > 64) throw new ShellSyntaxError("Syntax nesting exceeds 64", word.offset);
46484
47133
  return { ...io, parameterDepth };
46485
47134
  }
47135
+ async transformValue(value2, operator, state, io) {
47136
+ const allocation = io[valueScope] ?? this.budget.values.scope();
47137
+ try {
47138
+ return await transformParameter(value2, operator, {
47139
+ maximumBytes: this.budget.limits.maxExpansionBytes,
47140
+ byteLocale: byteLocale(state.variables),
47141
+ allocation,
47142
+ work: { remaining: Math.min(Number.MAX_SAFE_INTEGER, this.budget.limits.maxExpansionBytes * 8 + 1024), signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") }
47143
+ });
47144
+ } finally {
47145
+ if (!io[valueScope]) allocation.close();
47146
+ }
47147
+ }
46486
47148
  async partValue(part, state, io, hereString) {
46487
47149
  this.signal.throwIfAborted();
46488
47150
  if (part.kind === "compound-substitution-eof") {
@@ -46573,8 +47235,11 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46573
47235
  return part.length ? this.parameterLength(value3 ?? "") : value3 ?? "";
46574
47236
  }
46575
47237
  if (part.length) return String(binding?.values.size ?? (state.variables[part.name] === void 0 ? 0 : 1));
46576
- const values = await this.arrayMembers(part.name, state);
46577
- return this.arrayJoin(store.owner, values, Array.from(state.variables.IFS ?? " ")[0] ?? "");
47238
+ const values = await this.arrayMembers(part.name, state, io, part.keys);
47239
+ const separator = Array.from(state.variables.IFS ?? " ")[0] ?? "";
47240
+ if (values.every((value3) => typeof value3 === "string")) return this.arrayJoin(store.owner, values, separator);
47241
+ io[valueScope]?.reserve(values.length * 32 + 64, 0);
47242
+ return concatShellValues(values.flatMap((value3, index) => index ? [separator, value3] : [value3]), io[valueScope]);
46578
47243
  }
46579
47244
  let value2 = part.name === "?" ? String(state.status) : part.name === "-" ? `${state.errexit ? "e" : ""}${state.nounset ? "u" : ""}${state.braceexpand !== false ? "B" : ""}` : part.name === "#" ? String(state.positional.length) : part.name === "@" || part.name === "*" ? state.positional.join(hereString && (part.name === "@" || !part.quoted) ? " " : Array.from(state.variables.IFS ?? " ")[0] ?? "") : /^0+$/u.test(part.name) ? state.arg0 ?? "virtual-bash" : /^\d+$/u.test(part.name) ? state.positional[Number(part.name) - 1] : this.variable(state, part.name);
46580
47245
  let retained = value2;
@@ -46852,7 +47517,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46852
47517
  return fields3;
46853
47518
  }
46854
47519
  const arrayOwned = word.parts.some((part) => part.kind === "variable" && !part.prefixNames && (getArraySelector(part) !== void 0 || arrayStore(state)?.get(part.name) !== void 0));
46855
- const prefixOwned = word.parts.some((part) => part.kind === "variable" && part.prefixNames === "@");
47520
+ const prefixOwned = word.parts.some((part) => part.kind === "variable" && (part.prefixNames === "@" || part.transform && part.name === "@"));
46856
47521
  const owner = arrayOwned ? requireArrays(state).owner : void 0;
46857
47522
  const holding = owner?.hold();
46858
47523
  const scratch = !owner && split4 && state.variables.IFS !== "" && word.parts.some((part) => !part.quoted && part.kind !== "text") ? this.budget.values.scope() : void 0;
@@ -46982,19 +47647,25 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
46982
47647
  emptyNameGroups ??= /* @__PURE__ */ new Set();
46983
47648
  emptyNameGroups.add(quoteGroup);
46984
47649
  }
46985
- } else if (part.kind === "variable" && selector?.kind === "members" && !part.length && split4 && (!part.quoted || selector.separator === "@")) {
46986
- const members = await this.arrayMembers(part.name, state);
47650
+ } else if (part.kind === "variable" && split4 && (selector?.kind === "members" && !part.length && (!part.quoted || selector.separator === "@") || part.transform && part.name === "@")) {
47651
+ const members = selector?.kind === "members" ? await this.arrayMembers(part.name, state, io, part.keys) : this.positionalValues(state);
46987
47652
  for (let position = 0; position < members.length; position++) {
46988
47653
  if (position > 0) addField();
46989
- const value2 = members[position];
46990
- if (part.quoted || state.variables.IFS === "") append(value2, !part.quoted, part.quoted || value2.length > 0);
47654
+ const original = members[position];
47655
+ const value2 = part.transform ? await this.transformValue(original, part.transform, state, partIO) : original;
47656
+ if (part.quoted || state.variables.IFS === "") append(value2, !part.quoted, part.quoted || shellValueByteLength(value2) > 0);
46991
47657
  else await appendSplit(value2);
46992
47658
  }
47659
+ if (part.transform && members.length === 0 && quoteGroup) {
47660
+ io[valueScope]?.reserve(32, 0);
47661
+ emptyNameGroups ??= /* @__PURE__ */ new Set();
47662
+ emptyNameGroups.add(quoteGroup);
47663
+ }
46993
47664
  } else if (part.kind === "text" && !splitText) {
46994
47665
  let value2 = invokedValues.get(part) ?? part.byteValue ?? part.value;
46995
47666
  if (typeof value2 === "string" && index === 0 && !part.quoted && /^~(?:\/|$)/u.test(value2)) value2 = (state.variables.HOME ?? "~") + value2.slice(1);
46996
47667
  append(value2, !part.quoted, quotedPresence || shellValueByteLength(value2) > 0);
46997
- } else if (part.kind === "variable" && part.name === "@" && part.quoted && !part.operator && split4) {
47668
+ } else if (part.kind === "variable" && part.name === "@" && part.quoted && !part.operator && !part.transform && split4) {
46998
47669
  for (let position = 0; position < state.positional.length; position++) {
46999
47670
  if (position > 0) addField();
47000
47671
  append(stateMonitor(state)?.positionals.get(String(position), state.positional[position]) ?? state.positional[position], false, true);
@@ -47119,7 +47790,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
47119
47790
  for (const value2 of values) if (typeof value2 !== "string") allocation.hold(value2);
47120
47791
  return createCommandArguments(values, allocation);
47121
47792
  }
47122
- async arrayMembers(name2, state) {
47793
+ async arrayMembers(name2, state, io, keys = false) {
47123
47794
  const store = requireArrays(state);
47124
47795
  const holding = store.owner.hold();
47125
47796
  try {
@@ -47130,7 +47801,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
47130
47801
  if (value2 === void 0) return [];
47131
47802
  store.owner.reserve({ metadata: 32, allocatedSlots: 1, work: 3 });
47132
47803
  await textToken(store.owner, value2, this.signal);
47133
- return [value2];
47804
+ return [keys ? "0" : value2];
47134
47805
  }
47135
47806
  binding.retain();
47136
47807
  try {
@@ -47138,8 +47809,9 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
47138
47809
  const values = [];
47139
47810
  for (const index of indices) {
47140
47811
  store.owner.reserve({ metadata: 32, allocatedSlots: 1, work: 4 });
47141
- const value2 = binding.get(index);
47142
- await textToken(store.owner, value2, this.signal);
47812
+ const token = keys ? binding.associative ? binding.keys.get(binding.keyByIndex.get(index)).text : await textToken(store.owner, String(index), this.signal) : binding.values.get(index).text;
47813
+ const value2 = token.rawValue === void 0 ? token.value : shellValueFromBytes(shellValueBytes(token.rawValue, io[valueScope]), io[valueScope]);
47814
+ if (typeof value2 === "string") await textToken(store.owner, value2, this.signal);
47143
47815
  values.push(value2);
47144
47816
  await store.owner.ledger.checkpoint(this.signal);
47145
47817
  }
@@ -47768,6 +48440,97 @@ var ShellInput = class _ShellInput {
47768
48440
  line(raw, options3) {
47769
48441
  return this.#cursor.consume(this.signal, () => options3 ? this.readBounded(raw, options3) : this.readLine(raw));
47770
48442
  }
48443
+ /** Select uses read's escape rules without projecting raw REPLY bytes to text. */
48444
+ selectLine(allocation) {
48445
+ return this.#cursor.consume(this.signal, async () => {
48446
+ allocation.reserve(64, 0);
48447
+ const parts = [];
48448
+ let escaping = false;
48449
+ let length = 0;
48450
+ let pulls = 0;
48451
+ while (true) {
48452
+ if (++pulls % 128 === 0) await yieldTurn(this.signal);
48453
+ const result2 = await this.#cursor.take(this.signal);
48454
+ if (result2.done) return { value: concatShellValues(parts, allocation), terminated: false };
48455
+ const chunk = result2.value;
48456
+ for (let offset = 0; offset < chunk.length; ) {
48457
+ await yieldTurn(this.signal);
48458
+ const end = Math.min(offset + 1024, chunk.length);
48459
+ allocation.reserve(end - offset + 64, 0);
48460
+ const output2 = new Uint8Array(end - offset);
48461
+ let used = 0;
48462
+ let terminated = false;
48463
+ while (offset < end) {
48464
+ const byte = chunk[offset++];
48465
+ this.#cursor.position++;
48466
+ if (++length > this.budget.limits.maxOutputBytes) this.budget.fail("maxOutputBytes");
48467
+ if (byte === 0) continue;
48468
+ if (escaping) {
48469
+ escaping = false;
48470
+ if (byte !== 10) output2[used++] = byte;
48471
+ } else if (byte === 92) escaping = true;
48472
+ else if (byte === 10) {
48473
+ terminated = true;
48474
+ break;
48475
+ } else output2[used++] = byte;
48476
+ }
48477
+ if (used) {
48478
+ allocation.reserve(32, 0);
48479
+ parts.push(shellValueFromBytes(output2.subarray(0, used), allocation));
48480
+ }
48481
+ if (terminated) {
48482
+ if (offset < chunk.length) this.#cursor.remainder = chunk.subarray(offset);
48483
+ return { value: concatShellValues(parts, allocation), terminated: true };
48484
+ }
48485
+ }
48486
+ }
48487
+ });
48488
+ }
48489
+ mapfileRecord(delimiter, strip, allocation) {
48490
+ return this.#cursor.consume(this.signal, async () => {
48491
+ this.#cursor.admitBoundedRead();
48492
+ allocation.reserve(64, 0);
48493
+ const parts = [];
48494
+ let length = 0;
48495
+ let truncated = false;
48496
+ let pulls = 0;
48497
+ while (true) {
48498
+ if (++pulls % 128 === 0) await yieldTurn(this.signal);
48499
+ const result2 = await this.#cursor.take(this.signal);
48500
+ if (result2.done) return { value: concatShellValues(parts, allocation), present: length > 0 };
48501
+ const chunk = result2.value;
48502
+ for (let offset = 0; offset < chunk.length; ) {
48503
+ await yieldTurn(this.signal);
48504
+ if (length >= this.budget.limits.maxOutputBytes) this.budget.fail("maxOutputBytes");
48505
+ const end = Math.min(offset + 1024, chunk.length, offset + this.budget.limits.maxOutputBytes - length);
48506
+ allocation.reserve(end - offset + 64, 0);
48507
+ const output2 = new Uint8Array(end - offset);
48508
+ let used = 0;
48509
+ let terminated = false;
48510
+ while (offset < end) {
48511
+ const byte = chunk[offset++];
48512
+ this.#cursor.position++;
48513
+ if (++length > this.budget.limits.maxOutputBytes) this.budget.fail("maxOutputBytes");
48514
+ if (byte === delimiter) {
48515
+ if (!strip && byte !== 0 && !truncated) output2[used++] = byte;
48516
+ terminated = true;
48517
+ break;
48518
+ }
48519
+ if (byte === 0) truncated = true;
48520
+ if (!truncated) output2[used++] = byte;
48521
+ }
48522
+ if (used) {
48523
+ allocation.reserve(32, 0);
48524
+ parts.push(shellValueFromBytes(output2.subarray(0, used), allocation));
48525
+ }
48526
+ if (terminated) {
48527
+ if (offset < chunk.length) this.#cursor.remainder = chunk.subarray(offset);
48528
+ return { value: concatShellValues(parts, allocation), present: true };
48529
+ }
48530
+ }
48531
+ }
48532
+ });
48533
+ }
47771
48534
  async readBounded(raw, options3) {
47772
48535
  const text3 = new ReadText();
47773
48536
  let characters = 0;
@@ -49994,15 +50757,15 @@ function* entities2(text3) {
49994
50757
  const predefined = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'" };
49995
50758
  if (Object.hasOwn(predefined, entity)) result2 += predefined[entity];
49996
50759
  else {
49997
- const hexadecimal = entity.startsWith("#x");
49998
- const digits = entity.slice(hexadecimal ? 2 : 1);
50760
+ const hexadecimal2 = entity.startsWith("#x");
50761
+ const digits = entity.slice(hexadecimal2 ? 2 : 1);
49999
50762
  if (!entity.startsWith("#") || !digits.length) invalid("undeclared entity");
50000
50763
  let point = 0;
50001
50764
  for (let index = 0; index < digits.length; index++) {
50002
50765
  const code = digits.charCodeAt(index);
50003
- const digit3 = code >= 48 && code <= 57 ? code - 48 : hexadecimal && code >= 65 && code <= 70 ? code - 55 : hexadecimal && code >= 97 && code <= 102 ? code - 87 : -1;
50766
+ const digit3 = code >= 48 && code <= 57 ? code - 48 : hexadecimal2 && code >= 65 && code <= 70 ? code - 55 : hexadecimal2 && code >= 97 && code <= 102 ? code - 87 : -1;
50004
50767
  if (digit3 < 0) invalid("undeclared entity");
50005
- point = point * (hexadecimal ? 16 : 10) + digit3;
50768
+ point = point * (hexadecimal2 ? 16 : 10) + digit3;
50006
50769
  if (point > 1114111) invalid("invalid character reference");
50007
50770
  if ((index + 1) % 512 === 0) yield 512;
50008
50771
  }
@@ -52082,182 +52845,6 @@ function safeJsCommands(options3 = {}) {
52082
52845
  } };
52083
52846
  }
52084
52847
 
52085
- // packages/safe-bash/src/commands/network/fetch-transport.ts
52086
- init_platform();
52087
-
52088
- // packages/safe-bash/src/commands/network/types.ts
52089
- init_platform();
52090
- var defaultNetworkLimits = Object.freeze({
52091
- maxUploadBytes: 64 * 1024 * 1024,
52092
- maxDownloadBytes: 64 * 1024 * 1024,
52093
- maxBufferBytes: 8 * 1024 * 1024,
52094
- maxHeaderBytes: 64 * 1024,
52095
- maxRedirects: 10,
52096
- maxRetries: 5,
52097
- maxUrls: 32,
52098
- maxTimeMs: 12e4,
52099
- maxTotalTimeMs: 12e4
52100
- });
52101
- var cloudflareWorkerNetworkLimits = Object.freeze({
52102
- maxUploadBytes: 4 * 1024 * 1024,
52103
- maxDownloadBytes: 4 * 1024 * 1024,
52104
- maxBufferBytes: 1024 * 1024,
52105
- maxHeaderBytes: 32 * 1024,
52106
- maxRedirects: 2,
52107
- maxRetries: 1,
52108
- maxUrls: 8,
52109
- maxTimeMs: 1e4,
52110
- maxTotalTimeMs: 1e4
52111
- });
52112
- var CurlError = class extends Error {
52113
- constructor(exitCode, message3) {
52114
- super(message3);
52115
- this.exitCode = exitCode;
52116
- this.name = "CurlError";
52117
- }
52118
- exitCode;
52119
- };
52120
-
52121
- // packages/safe-bash/src/commands/network/fetch-transport.ts
52122
- function requestBody(source2, signal) {
52123
- if (!source2) return void 0;
52124
- const iterator = source2[Symbol.asyncIterator]();
52125
- return new ReadableStream({
52126
- async pull(controller) {
52127
- try {
52128
- signal.throwIfAborted();
52129
- const next = await iterator.next();
52130
- if (next.done) controller.close();
52131
- else controller.enqueue(next.value);
52132
- } catch (error) {
52133
- controller.error(error);
52134
- }
52135
- },
52136
- async cancel(reason) {
52137
- await iterator.return?.(reason);
52138
- }
52139
- });
52140
- }
52141
- function createFetchTransport(options3 = {}) {
52142
- const fetchRequest = options3.fetch ?? globalThis.fetch;
52143
- if (typeof fetchRequest !== "function") throw new TypeError("Fetch is unavailable");
52144
- return async (input3) => {
52145
- input3.signal.throwIfAborted();
52146
- const url = new URL(input3.url);
52147
- if (url.protocol !== "http:" && url.protocol !== "https:") throw new CurlError(1, "Unsupported protocol");
52148
- if (input3.denyPrivateNetworks === true) throw new CurlError(7, "Fetch transport cannot enforce private-network denial");
52149
- const stopped = new AbortController();
52150
- const signal = AbortSignal.any([input3.signal, stopped.signal]);
52151
- const body = requestBody(input3.body, signal);
52152
- const headers = new Headers();
52153
- for (const [name2, value2] of input3.headers) headers.append(name2, value2);
52154
- const request = new Request(url, {
52155
- method: input3.method,
52156
- headers,
52157
- body,
52158
- credentials: "omit",
52159
- redirect: "manual",
52160
- signal,
52161
- ...body ? { duplex: "half" } : {}
52162
- });
52163
- let response;
52164
- const dispose = async () => {
52165
- stopped.abort();
52166
- if (response?.body) await response.body.cancel().catch(() => void 0);
52167
- };
52168
- input3.registerCleanup?.(dispose);
52169
- response = await fetchRequest(request);
52170
- const reader = response.body?.getReader();
52171
- const responseBody = reader ? (async function* () {
52172
- try {
52173
- while (true) {
52174
- input3.signal.throwIfAborted();
52175
- const next = await reader.read();
52176
- if (next.done) return;
52177
- yield next.value;
52178
- }
52179
- } finally {
52180
- reader.releaseLock();
52181
- }
52182
- })() : (async function* () {
52183
- })();
52184
- return {
52185
- status: response.status,
52186
- statusText: response.statusText,
52187
- headers: [...response.headers.entries()],
52188
- body: responseBody,
52189
- dispose
52190
- };
52191
- };
52192
- }
52193
-
52194
- // packages/safe-bash/src/commands/network/authorizer.ts
52195
- init_platform();
52196
-
52197
- // packages/safe-bash/src/commands/network/private-address.ts
52198
- init_platform();
52199
- function privateIPv4(first, second) {
52200
- return first === 10 || first === 127 || first === 0 || first === 169 && second === 254 || first === 192 && second === 168 || first === 172 && second >= 16 && second <= 31 || first === 100 && second >= 64 && second <= 127 || first === 198 && second >= 18 && second <= 19 || first >= 224;
52201
- }
52202
- function privateHostname(input3) {
52203
- const hostname = input3.toLowerCase().replace(/\.$/u, "").replace(/^\[|\]$/gu, "");
52204
- if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "::1") return true;
52205
- if (hostname.includes(":")) {
52206
- const [prefix3, suffix2] = hostname.split("::");
52207
- const leading = prefix3 ? prefix3.split(":") : [];
52208
- const trailing = suffix2 ? suffix2.split(":") : [];
52209
- const hextets = new Array(8).fill(0);
52210
- for (let index = 0; index < leading.length; index++) hextets[index] = Number.parseInt(leading[index], 16);
52211
- for (let index = 0; index < trailing.length; index++) hextets[8 - trailing.length + index] = Number.parseInt(trailing[index], 16);
52212
- if (hextets.every((value2) => value2 === 0)) return true;
52213
- const mappedIPv4 = hextets.slice(0, 5).every((value2) => value2 === 0) && hextets[5] === 65535;
52214
- const translatedIPv4 = hextets.slice(0, 4).every((value2) => value2 === 0) && hextets[4] === 65535 && hextets[5] === 0;
52215
- const nat64IPv4 = hextets[0] === 100 && hextets[1] === 65435 && hextets.slice(2, 6).every((value2) => value2 === 0);
52216
- const compatibleIPv4 = hextets.slice(0, 6).every((value2) => value2 === 0);
52217
- if (mappedIPv4 || translatedIPv4 || nat64IPv4 || compatibleIPv4) {
52218
- return privateIPv4(hextets[6] >>> 8, hextets[6] & 255);
52219
- }
52220
- if (hextets[0] === 8194) return privateIPv4(hextets[1] >>> 8, hextets[1] & 255);
52221
- return (hextets[0] & 65024) === 64512 || (hextets[0] & 65472) === 65152 || (hextets[0] & 65472) === 65216 || (hextets[0] & 65280) === 65280 || hextets[0] === 100 && hextets[1] === 65435 && hextets[2] === 1;
52222
- }
52223
- const parts = hostname.split(".");
52224
- if (parts.length !== 4 || parts.some((part) => !part || Array.from(part).some((character) => character < "0" || character > "9"))) return false;
52225
- const octets = parts.map(Number);
52226
- if (octets.some((value2) => value2 < 0 || value2 > 255)) return false;
52227
- const [first, second] = octets;
52228
- return privateIPv4(first, second);
52229
- }
52230
-
52231
- // packages/safe-bash/src/commands/network/authorizer.ts
52232
- function createOriginAuthorizer(allowlist = "*", options3 = {}) {
52233
- const denyPrivateNetworks = options3.denyPrivateNetworks === true;
52234
- const origins = /* @__PURE__ */ new Set();
52235
- const hosts = /* @__PURE__ */ new Set();
52236
- for (const entry of allowlist === "*" ? [] : allowlist) {
52237
- const value2 = entry.trim();
52238
- if (!value2) throw new TypeError("Origin allowlist entries must not be empty");
52239
- if (value2.includes("://")) {
52240
- const url = new URL(value2);
52241
- if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) {
52242
- throw new TypeError(`Origin allowlist entry must be an origin: ${entry}`);
52243
- }
52244
- origins.add(url.origin);
52245
- } else {
52246
- if (value2.includes("/") || value2.includes("@")) throw new TypeError(`Invalid hostname allowlist entry: ${entry}`);
52247
- hosts.add(value2.toLowerCase().replace(/\.$/u, ""));
52248
- }
52249
- }
52250
- return (request) => {
52251
- const url = new URL(request.url);
52252
- const hostname = url.hostname.toLowerCase().replace(/\.$/u, "");
52253
- if (denyPrivateNetworks) {
52254
- request.requirePrivateNetworkDeny?.();
52255
- if (privateHostname(hostname)) return false;
52256
- }
52257
- return allowlist === "*" || origins.has(url.origin) || hosts.has(hostname);
52258
- };
52259
- }
52260
-
52261
52848
  // packages/safe-bash/src/commands/grep-aliases/index.ts
52262
52849
  init_platform();
52263
52850
  function createGrepAliasCommands(options3 = {}) {
@@ -52327,6 +52914,7 @@ export {
52327
52914
  ACCESS_MODES,
52328
52915
  CommandArgumentIdentityError,
52329
52916
  CommandRegistry,
52917
+ CurlError,
52330
52918
  DEFAULT_ARCHIVE_LIMITS,
52331
52919
  EreLedger,
52332
52920
  EreProfileLimitError,
@@ -52368,6 +52956,8 @@ export {
52368
52956
  createColumnCommand,
52369
52957
  createColumnCommands,
52370
52958
  createCommandArguments,
52959
+ createCurlCommand,
52960
+ createCurlCommands,
52371
52961
  createDiffPatchCommands,
52372
52962
  createDuCommand,
52373
52963
  createDuCommands,
@@ -52382,6 +52972,7 @@ export {
52382
52972
  createMemoryFileSystem2 as createMemoryFileSystem,
52383
52973
  createMetadataCommands,
52384
52974
  createMountFileSystem2 as createMountFileSystem,
52975
+ createNetworkCommands,
52385
52976
  createOriginAuthorizer,
52386
52977
  createOutputOperation,
52387
52978
  createOverlayFileSystem2 as createOverlayFileSystem,
@@ -52401,13 +52992,16 @@ export {
52401
52992
  createTimeoutCommands,
52402
52993
  createTreeCommand,
52403
52994
  createTreeCommands,
52995
+ createWgetCommand,
52404
52996
  createWhichCommand,
52405
52997
  createWhichCommands,
52406
52998
  createXmlCommands,
52407
52999
  createYqCommand,
52408
53000
  createYqCommands,
53001
+ curlCommands,
52409
53002
  defaultJqLimits,
52410
53003
  defaultMemoryFileSystemLimits2 as defaultMemoryFileSystemLimits,
53004
+ defaultNetworkLimits,
52411
53005
  defaultSafeJsLimits,
52412
53006
  defaultXmlQueryLimits,
52413
53007
  diffPatchCommands,
@@ -52430,6 +53024,7 @@ export {
52430
53024
  makeSafeJsShellModule,
52431
53025
  matchEre,
52432
53026
  metadataCommands,
53027
+ networkCommands,
52433
53028
  normalizePath2 as normalizePath,
52434
53029
  outputFailure,
52435
53030
  parseShell,