@poe-platform/safe-bash 0.1.442 → 0.1.443

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 (167) hide show
  1. package/dist/safe-bash/browser.js +111 -69
  2. package/dist/safe-bash/browser.js.map +4 -4
  3. package/dist/safe-bash/commands/archive/index.d.ts.map +1 -1
  4. package/dist/safe-bash/commands/archive/index.js +2 -1
  5. package/dist/safe-bash/commands/archive/index.js.map +1 -1
  6. package/dist/safe-bash/commands/archive/internal.d.ts.map +1 -1
  7. package/dist/safe-bash/commands/archive/internal.js +2 -1
  8. package/dist/safe-bash/commands/archive/internal.js.map +1 -1
  9. package/dist/safe-bash/commands/archive/stream.d.ts.map +1 -1
  10. package/dist/safe-bash/commands/archive/stream.js +11 -4
  11. package/dist/safe-bash/commands/archive/stream.js.map +1 -1
  12. package/dist/safe-bash/commands/bytes/checksums/index.d.ts.map +1 -1
  13. package/dist/safe-bash/commands/bytes/checksums/index.js +7 -6
  14. package/dist/safe-bash/commands/bytes/checksums/index.js.map +1 -1
  15. package/dist/safe-bash/commands/bytes/compression/errors.d.ts +2 -0
  16. package/dist/safe-bash/commands/bytes/compression/errors.d.ts.map +1 -0
  17. package/dist/safe-bash/commands/bytes/compression/errors.js +19 -0
  18. package/dist/safe-bash/commands/bytes/compression/errors.js.map +1 -0
  19. package/dist/safe-bash/commands/bytes/compression/files.d.ts.map +1 -1
  20. package/dist/safe-bash/commands/bytes/compression/files.js +5 -2
  21. package/dist/safe-bash/commands/bytes/compression/files.js.map +1 -1
  22. package/dist/safe-bash/commands/bytes/compression/gunzip.d.ts.map +1 -1
  23. package/dist/safe-bash/commands/bytes/compression/gunzip.js +20 -12
  24. package/dist/safe-bash/commands/bytes/compression/gunzip.js.map +1 -1
  25. package/dist/safe-bash/commands/bytes/compression/index.d.ts.map +1 -1
  26. package/dist/safe-bash/commands/bytes/compression/index.js +2 -1
  27. package/dist/safe-bash/commands/bytes/compression/index.js.map +1 -1
  28. package/dist/safe-bash/commands/bytes/compression/stream.d.ts.map +1 -1
  29. package/dist/safe-bash/commands/bytes/compression/stream.js +3 -1
  30. package/dist/safe-bash/commands/bytes/compression/stream.js.map +1 -1
  31. package/dist/safe-bash/commands/bytes/encoding/base.d.ts.map +1 -1
  32. package/dist/safe-bash/commands/bytes/encoding/base.js +3 -2
  33. package/dist/safe-bash/commands/bytes/encoding/base.js.map +1 -1
  34. package/dist/safe-bash/commands/bytes/encoding/shared.d.ts.map +1 -1
  35. package/dist/safe-bash/commands/bytes/encoding/shared.js +3 -2
  36. package/dist/safe-bash/commands/bytes/encoding/shared.js.map +1 -1
  37. package/dist/safe-bash/commands/bytes/encoding/xxd.d.ts.map +1 -1
  38. package/dist/safe-bash/commands/bytes/encoding/xxd.js +8 -7
  39. package/dist/safe-bash/commands/bytes/encoding/xxd.js.map +1 -1
  40. package/dist/safe-bash/commands/column/internal.d.ts.map +1 -1
  41. package/dist/safe-bash/commands/column/internal.js +2 -1
  42. package/dist/safe-bash/commands/column/internal.js.map +1 -1
  43. package/dist/safe-bash/commands/diff-patch/patch-gnu-paths.d.ts.map +1 -1
  44. package/dist/safe-bash/commands/diff-patch/patch-gnu-paths.js +2 -1
  45. package/dist/safe-bash/commands/diff-patch/patch-gnu-paths.js.map +1 -1
  46. package/dist/safe-bash/commands/diff-patch/patch.d.ts.map +1 -1
  47. package/dist/safe-bash/commands/diff-patch/patch.js +3 -2
  48. package/dist/safe-bash/commands/diff-patch/patch.js.map +1 -1
  49. package/dist/safe-bash/commands/diff-patch/shared.d.ts +2 -1
  50. package/dist/safe-bash/commands/diff-patch/shared.d.ts.map +1 -1
  51. package/dist/safe-bash/commands/diff-patch/shared.js +3 -2
  52. package/dist/safe-bash/commands/diff-patch/shared.js.map +1 -1
  53. package/dist/safe-bash/commands/du/budget.d.ts.map +1 -1
  54. package/dist/safe-bash/commands/du/budget.js +3 -1
  55. package/dist/safe-bash/commands/du/budget.js.map +1 -1
  56. package/dist/safe-bash/commands/du/du.d.ts.map +1 -1
  57. package/dist/safe-bash/commands/du/du.js +8 -7
  58. package/dist/safe-bash/commands/du/du.js.map +1 -1
  59. package/dist/safe-bash/commands/du/format.d.ts +2 -1
  60. package/dist/safe-bash/commands/du/format.d.ts.map +1 -1
  61. package/dist/safe-bash/commands/du/format.js +2 -1
  62. package/dist/safe-bash/commands/du/format.js.map +1 -1
  63. package/dist/safe-bash/commands/expr/command.d.ts.map +1 -1
  64. package/dist/safe-bash/commands/expr/command.js +3 -1
  65. package/dist/safe-bash/commands/expr/command.js.map +1 -1
  66. package/dist/safe-bash/commands/find.d.ts.map +1 -1
  67. package/dist/safe-bash/commands/find.js +2 -1
  68. package/dist/safe-bash/commands/find.js.map +1 -1
  69. package/dist/safe-bash/commands/html-to-markdown/index.d.ts.map +1 -1
  70. package/dist/safe-bash/commands/html-to-markdown/index.js +2 -1
  71. package/dist/safe-bash/commands/html-to-markdown/index.js.map +1 -1
  72. package/dist/safe-bash/commands/index.d.ts.map +1 -1
  73. package/dist/safe-bash/commands/index.js +2 -1
  74. package/dist/safe-bash/commands/index.js.map +1 -1
  75. package/dist/safe-bash/commands/internal.d.ts +2 -1
  76. package/dist/safe-bash/commands/internal.d.ts.map +1 -1
  77. package/dist/safe-bash/commands/internal.js +3 -2
  78. package/dist/safe-bash/commands/internal.js.map +1 -1
  79. package/dist/safe-bash/commands/move.d.ts.map +1 -1
  80. package/dist/safe-bash/commands/move.js +2 -1
  81. package/dist/safe-bash/commands/move.js.map +1 -1
  82. package/dist/safe-bash/commands/regex-execution/bounded-provider.d.ts.map +1 -1
  83. package/dist/safe-bash/commands/regex-execution/bounded-provider.js +14 -3
  84. package/dist/safe-bash/commands/regex-execution/bounded-provider.js.map +1 -1
  85. package/dist/safe-bash/commands/regex-execution/matching.d.ts.map +1 -1
  86. package/dist/safe-bash/commands/regex-execution/matching.js +12 -5
  87. package/dist/safe-bash/commands/regex-execution/matching.js.map +1 -1
  88. package/dist/safe-bash/commands/regex-execution/portable.d.ts.map +1 -1
  89. package/dist/safe-bash/commands/regex-execution/portable.js +1 -1
  90. package/dist/safe-bash/commands/regex-execution/portable.js.map +1 -1
  91. package/dist/safe-bash/commands/regex-execution/protocol.d.ts +3 -2
  92. package/dist/safe-bash/commands/regex-execution/protocol.d.ts.map +1 -1
  93. package/dist/safe-bash/commands/regex-execution/protocol.js +4 -3
  94. package/dist/safe-bash/commands/regex-execution/protocol.js.map +1 -1
  95. package/dist/safe-bash/commands/regex-execution/worker.js +6 -3
  96. package/dist/safe-bash/commands/regex-execution/worker.js.map +1 -1
  97. package/dist/safe-bash/commands/safejs/index.d.ts.map +1 -1
  98. package/dist/safe-bash/commands/safejs/index.js +24 -7
  99. package/dist/safe-bash/commands/safejs/index.js.map +1 -1
  100. package/dist/safe-bash/commands/search/options.d.ts +2 -1
  101. package/dist/safe-bash/commands/search/options.d.ts.map +1 -1
  102. package/dist/safe-bash/commands/search/options.js +2 -1
  103. package/dist/safe-bash/commands/search/options.js.map +1 -1
  104. package/dist/safe-bash/commands/search/shared.d.ts.map +1 -1
  105. package/dist/safe-bash/commands/search/shared.js +2 -1
  106. package/dist/safe-bash/commands/search/shared.js.map +1 -1
  107. package/dist/safe-bash/commands/split/names.d.ts.map +1 -1
  108. package/dist/safe-bash/commands/split/names.js +3 -2
  109. package/dist/safe-bash/commands/split/names.js.map +1 -1
  110. package/dist/safe-bash/commands/split/options.d.ts.map +1 -1
  111. package/dist/safe-bash/commands/split/options.js +17 -16
  112. package/dist/safe-bash/commands/split/options.js.map +1 -1
  113. package/dist/safe-bash/commands/split/split.d.ts.map +1 -1
  114. package/dist/safe-bash/commands/split/split.js +2 -1
  115. package/dist/safe-bash/commands/split/split.js.map +1 -1
  116. package/dist/safe-bash/commands/standard.d.ts.map +1 -1
  117. package/dist/safe-bash/commands/standard.js +2 -1
  118. package/dist/safe-bash/commands/standard.js.map +1 -1
  119. package/dist/safe-bash/commands/stream-format/rev.d.ts.map +1 -1
  120. package/dist/safe-bash/commands/stream-format/rev.js +2 -1
  121. package/dist/safe-bash/commands/stream-format/rev.js.map +1 -1
  122. package/dist/safe-bash/commands/table-text/internal.d.ts.map +1 -1
  123. package/dist/safe-bash/commands/table-text/internal.js +3 -2
  124. package/dist/safe-bash/commands/table-text/internal.js.map +1 -1
  125. package/dist/safe-bash/commands/tail-follow.d.ts.map +1 -1
  126. package/dist/safe-bash/commands/tail-follow.js +4 -3
  127. package/dist/safe-bash/commands/tail-follow.js.map +1 -1
  128. package/dist/safe-bash/commands/text-programs/shared.d.ts +2 -1
  129. package/dist/safe-bash/commands/text-programs/shared.d.ts.map +1 -1
  130. package/dist/safe-bash/commands/text-programs/shared.js +3 -2
  131. package/dist/safe-bash/commands/text-programs/shared.js.map +1 -1
  132. package/dist/safe-bash/commands/text.d.ts.map +1 -1
  133. package/dist/safe-bash/commands/text.js +2 -1
  134. package/dist/safe-bash/commands/text.js.map +1 -1
  135. package/dist/safe-bash/commands/tree/io.d.ts.map +1 -1
  136. package/dist/safe-bash/commands/tree/io.js +2 -4
  137. package/dist/safe-bash/commands/tree/io.js.map +1 -1
  138. package/dist/safe-bash/contracts/command.d.ts +5 -0
  139. package/dist/safe-bash/contracts/command.d.ts.map +1 -1
  140. package/dist/safe-bash/contracts/command.js +6 -1
  141. package/dist/safe-bash/contracts/command.js.map +1 -1
  142. package/dist/safe-bash/diagnostics.d.ts +5 -0
  143. package/dist/safe-bash/diagnostics.d.ts.map +1 -0
  144. package/dist/safe-bash/diagnostics.js +22 -0
  145. package/dist/safe-bash/diagnostics.js.map +1 -0
  146. package/dist/safe-bash/plugins/composition.d.ts.map +1 -1
  147. package/dist/safe-bash/plugins/composition.js +2 -1
  148. package/dist/safe-bash/plugins/composition.js.map +1 -1
  149. package/dist/safe-bash/portable.js +238 -150
  150. package/dist/safe-bash/portable.js.map +4 -4
  151. package/dist/safe-bash/shell/arithmetic.d.ts.map +1 -1
  152. package/dist/safe-bash/shell/arithmetic.js +10 -9
  153. package/dist/safe-bash/shell/arithmetic.js.map +1 -1
  154. package/dist/safe-bash/shell/input.d.ts.map +1 -1
  155. package/dist/safe-bash/shell/input.js +2 -1
  156. package/dist/safe-bash/shell/input.js.map +1 -1
  157. package/dist/safe-bash/shell/runtime.d.ts +3 -1
  158. package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
  159. package/dist/safe-bash/shell/runtime.js +52 -38
  160. package/dist/safe-bash/shell/runtime.js.map +1 -1
  161. package/dist/safe-bash/shell/shell.d.ts.map +1 -1
  162. package/dist/safe-bash/shell/shell.js +5 -1
  163. package/dist/safe-bash/shell/shell.js.map +1 -1
  164. package/dist/safe-bash/shell/types.d.ts +3 -1
  165. package/dist/safe-bash/shell/types.d.ts.map +1 -1
  166. package/dist/safe-bash/shell/types.js.map +1 -1
  167. package/package.json +2 -2
@@ -2026,6 +2026,11 @@ function encodeValues(values, output2) {
2026
2026
 
2027
2027
  // packages/safe-bash/src/contracts/command.ts
2028
2028
  var argumentCarriers = /* @__PURE__ */ new WeakSet();
2029
+ var CommandArgumentIdentityError = class extends TypeError {
2030
+ constructor() {
2031
+ super("Command argument identity does not match its carrier");
2032
+ }
2033
+ };
2029
2034
  function argumentAllocation(allocation) {
2030
2035
  const reservations = [];
2031
2036
  const tracked = allocation && {
@@ -2175,7 +2180,7 @@ function getCommandArguments(context) {
2175
2180
  const carrier = context.argumentValues;
2176
2181
  if (carrier === void 0) return createCommandArguments(context.args);
2177
2182
  if (!argumentCarriers.has(carrier)) throw new TypeError("Expected owned command arguments");
2178
- if (carrier.args !== context.args) throw new TypeError("Command argument identity does not match its carrier");
2183
+ if (carrier.args !== context.args) throw new CommandArgumentIdentityError();
2179
2184
  return carrier;
2180
2185
  }
2181
2186
  var CommandRegistry = class {
@@ -2687,6 +2692,24 @@ async function writeDiagnostic(sink, value2, signal) {
2687
2692
  // packages/safe-bash/src/commands/internal.ts
2688
2693
  init_platform();
2689
2694
 
2695
+ // packages/safe-bash/src/diagnostics.ts
2696
+ init_platform();
2697
+ var PublicDiagnostic = class extends Error {
2698
+ };
2699
+ function publicDiagnosticMessage(error, onInternalError) {
2700
+ if (error instanceof FsError || error instanceof CommandArgumentIdentityError) return error.message;
2701
+ if (error instanceof PublicDiagnostic && !Object.hasOwn(error, "cause")) return error.message;
2702
+ const original = error instanceof PublicDiagnostic ? error.cause : error;
2703
+ const detail = error instanceof PublicDiagnostic ? error.message : "internal error";
2704
+ try {
2705
+ const pending = onInternalError?.(original);
2706
+ if (pending !== void 0) void Promise.resolve(pending).catch(() => void 0);
2707
+ } catch {
2708
+ return detail;
2709
+ }
2710
+ return detail;
2711
+ }
2712
+
2690
2713
  // packages/safe-bash/src/commands/portable-requirements.ts
2691
2714
  init_platform();
2692
2715
  var inputRequirements = [
@@ -2774,7 +2797,7 @@ var RecordBuffer = class {
2774
2797
  var encoder3 = new TextEncoder();
2775
2798
  var decoder2 = new TextDecoder();
2776
2799
  var bufferLimit = 32 * 1024 * 1024;
2777
- var UsageError = class extends Error {
2800
+ var UsageError = class extends PublicDiagnostic {
2778
2801
  };
2779
2802
  function options(args, short, long = {}, stopAtOperand = false, onOperand) {
2780
2803
  const flags = /* @__PURE__ */ new Set();
@@ -2855,7 +2878,7 @@ async function output(context, text) {
2855
2878
  }
2856
2879
  async function diagnostic(context, error) {
2857
2880
  context.signal.throwIfAborted();
2858
- await writeDiagnostic(context.stderr, `${context.command}: ${error instanceof Error ? error.message : String(error)}
2881
+ await writeDiagnostic(context.stderr, `${context.command}: ${publicDiagnosticMessage(error, context.onInternalError)}
2859
2882
  `, context.signal);
2860
2883
  }
2861
2884
  function define(name2, handler, failureCode = 1) {
@@ -3497,7 +3520,7 @@ async function moveAcrossDevices(context, source, target, noClobber, budget) {
3497
3520
  } catch (error) {
3498
3521
  context.signal.throwIfAborted();
3499
3522
  if (codeOf(error) !== "ENOTSUP" && codeOf(error) !== "EOPNOTSUPP") throw error;
3500
- await diagnostic(context, new Error(`cannot preserve timestamps for '${entry.target}': operation not supported; retaining copied data`));
3523
+ await diagnostic(context, new PublicDiagnostic(`cannot preserve timestamps for '${entry.target}': operation not supported; retaining copied data`));
3501
3524
  }
3502
3525
  }
3503
3526
  }
@@ -4529,7 +4552,7 @@ var FollowSession = class {
4529
4552
  if ("reason" in outcome) reject(outcome.reason);
4530
4553
  else resolve(outcome.value);
4531
4554
  };
4532
- const cancel = () => finish({ reason: this.operation.signal.aborted ? this.operation.signal.reason : new Error("Tail follow is closed") });
4555
+ const cancel = () => finish({ reason: this.operation.signal.aborted ? this.operation.signal.reason : new PublicDiagnostic("Tail follow is closed") });
4533
4556
  this.waiting.add(cancel);
4534
4557
  this.operation.signal.addEventListener("abort", cancel, { once: true });
4535
4558
  pending?.then((value2) => finish({ value: value2 }), (reason) => finish({ reason }));
@@ -4733,7 +4756,7 @@ async function followTail(caller, selection, cap, select, scheduler = tailFollow
4733
4756
  entry.offset = 0;
4734
4757
  if (!initial) {
4735
4758
  const message2 = replaced ? "has been replaced; following new file" : entry.error === "ENOENT" ? "has appeared; following new file" : "has become accessible";
4736
- await diagnostic(context, new Error(`'${entry.name}' ${message2}`));
4759
+ await diagnostic(context, new PublicDiagnostic(`'${entry.name}' ${message2}`));
4737
4760
  }
4738
4761
  entry.error = void 0;
4739
4762
  return stat;
@@ -4796,7 +4819,7 @@ async function followTail(caller, selection, cap, select, scheduler = tailFollow
4796
4819
  }
4797
4820
  if (!stat) continue;
4798
4821
  if (stat.size < entry.offset) {
4799
- await diagnostic(context, new Error(`${entry.name}: file truncated`));
4822
+ await diagnostic(context, new PublicDiagnostic(`${entry.name}: file truncated`));
4800
4823
  entry.offset = 0;
4801
4824
  }
4802
4825
  if (stat.size > entry.offset) round.push({ entry, end: stat.size });
@@ -5735,7 +5758,7 @@ function textCommands() {
5735
5758
  }
5736
5759
  return (async () => {
5737
5760
  if (records.length && (await compare(records.at(-1), bytes2) > 0 || parsed.flags.has("u") && await keyCompare(records.at(-1), bytes2) === 0)) {
5738
- await diagnostic(context, new Error(`disorder at record ${records.length + 1}`));
5761
+ await diagnostic(context, new PublicDiagnostic(`disorder at record ${records.length + 1}`));
5739
5762
  return false;
5740
5763
  }
5741
5764
  records.push(bytes2);
@@ -6719,16 +6742,16 @@ var precedence = {
6719
6742
  function integer2(text) {
6720
6743
  if (/^0[xX][\da-fA-F]+$/u.test(text)) return BigInt(text);
6721
6744
  if (/^0[0-7]+$/u.test(text)) return BigInt(`0o${text.slice(1)}`);
6722
- if (/^0\d+$/u.test(text)) throw new Error("Invalid octal constant");
6745
+ if (/^0\d+$/u.test(text)) throw new PublicDiagnostic("Invalid octal constant");
6723
6746
  if (/^\d+$/u.test(text)) return BigInt(text);
6724
6747
  const match = /^(\d+)#([\da-zA-Z@_]+)$/u.exec(text);
6725
- if (!match) throw new Error("Invalid arithmetic constant");
6748
+ if (!match) throw new PublicDiagnostic("Invalid arithmetic constant");
6726
6749
  const base = Number(match[1]);
6727
- if (base < 2 || base > 64) throw new Error("Invalid arithmetic base");
6750
+ if (base < 2 || base > 64) throw new PublicDiagnostic("Invalid arithmetic base");
6728
6751
  let value2 = 0n;
6729
6752
  for (const character of match[2]) {
6730
6753
  const digit2 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@_".indexOf(base <= 36 ? character.toLowerCase() : character);
6731
- if (digit2 >= base || digit2 < 0) throw new Error("Digit exceeds arithmetic base");
6754
+ if (digit2 >= base || digit2 < 0) throw new PublicDiagnostic("Digit exceeds arithmetic base");
6732
6755
  value2 = BigInt.asIntN(64, value2 * BigInt(base) + BigInt(digit2));
6733
6756
  }
6734
6757
  return value2;
@@ -6880,7 +6903,7 @@ function evaluateArithmetic(program, variables, budget = new ParseBudget()) {
6880
6903
  case ">=":
6881
6904
  return BigInt(left >= right);
6882
6905
  default:
6883
- throw new Error(`Unsupported arithmetic operator ${operator}`);
6906
+ throw new PublicDiagnostic(`Unsupported arithmetic operator ${operator}`);
6884
6907
  }
6885
6908
  };
6886
6909
  try {
@@ -6890,11 +6913,11 @@ function evaluateArithmetic(program, variables, budget = new ParseBudget()) {
6890
6913
  while (pending.length) {
6891
6914
  const frame = pending.pop();
6892
6915
  if (frame.kind === "evaluate") {
6893
- if (++steps > 1e4) throw new Error("Arithmetic operation limit exceeded");
6916
+ if (++steps > 1e4) throw new PublicDiagnostic("Arithmetic operation limit exceeded");
6894
6917
  const node = frame.node;
6895
6918
  if (node.kind === "literal") value2 = node.value;
6896
6919
  else if (node.kind === "name") {
6897
- if (visiting.has(node.name) || visiting.size >= 64) throw new Error("Arithmetic variable recursion");
6920
+ if (visiting.has(node.name) || visiting.size >= 64) throw new PublicDiagnostic("Arithmetic variable recursion");
6898
6921
  visiting.add(node.name);
6899
6922
  pending.push({ kind: "variable", name: node.name }, { kind: "evaluate", node: parseArithmetic(variables[node.name] ?? "0", 0, budget) });
6900
6923
  } else if (node.kind === "conditional") {
@@ -6940,11 +6963,11 @@ function evaluateArithmetic(program, variables, budget = new ParseBudget()) {
6940
6963
  }
6941
6964
  return value2;
6942
6965
  } catch (error) {
6943
- if (error instanceof ArithmeticFailure) throw new Error(`${program.source.trimStart()}: ${error.message} (error token is "${program.source.slice(error.offset)}")`);
6966
+ if (error instanceof ArithmeticFailure) throw new PublicDiagnostic(`${program.source.trimStart()}: ${error.message} (error token is "${program.source.slice(error.offset)}")`);
6944
6967
  if (error instanceof ShellSyntaxError) {
6945
6968
  const offset = error.offset >= program.source.trimEnd().length ? Math.max(0, program.source.trimEnd().length - 1) : error.offset;
6946
6969
  const reason = error.reason === "Invalid arithmetic operand" ? "arithmetic syntax error: operand expected" : "arithmetic syntax error in expression";
6947
- throw new Error(`${program.source.trimStart()}: ${reason} (error token is "${program.source.slice(offset)}")`);
6970
+ throw new PublicDiagnostic(`${program.source.trimStart()}: ${reason} (error token is "${program.source.slice(offset)}")`);
6948
6971
  }
6949
6972
  throw error;
6950
6973
  }
@@ -11944,8 +11967,9 @@ function resolveLimits(...limits) {
11944
11967
  }
11945
11968
  var budgetedSinks = /* @__PURE__ */ new WeakMap();
11946
11969
  var Budget = class {
11947
- constructor(limits, signal) {
11970
+ constructor(limits, signal, onInternalError) {
11948
11971
  this.limits = limits;
11972
+ this.onInternalError = onInternalError;
11949
11973
  this.signal = signal ? AbortSignal.any([signal, this.controller.signal]) : this.controller.signal;
11950
11974
  this.parsing = new ParseBudget(limits.maxParseUnits, this.signal, (error) => this.controller.abort(error));
11951
11975
  this.values = new ValueArena(limits.maxExpansionBytes, limits.maxExpansionFields, () => this.signal.throwIfAborted(), (limit) => this.fail(limit));
@@ -11953,6 +11977,7 @@ var Budget = class {
11953
11977
  this.#armWallClock();
11954
11978
  }
11955
11979
  limits;
11980
+ onInternalError;
11956
11981
  executionScope = Object.freeze({});
11957
11982
  pathLookup = new PathLookup();
11958
11983
  parsing;
@@ -12381,13 +12406,16 @@ function saturatedSum(left, right) {
12381
12406
  function errorCode(error) {
12382
12407
  return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
12383
12408
  }
12384
- function message(error) {
12385
- return error instanceof Error ? error.message : String(error);
12409
+ function message(error, onInternalError) {
12410
+ if (error instanceof ExpansionFailure || error instanceof CommandFailure || error instanceof ArrayFailure || error instanceof BraceExpansionFailure) return error.message;
12411
+ return publicDiagnosticMessage(error, onInternalError);
12386
12412
  }
12387
- function filesystemDiagnostic(error, target) {
12413
+ function filesystemDiagnostic(error, target, onInternalError) {
12388
12414
  const descriptions = { ENOENT: "No such file or directory", EACCES: "Permission denied", EPERM: "Operation not permitted", ENOTDIR: "Not a directory", EISDIR: "Is a directory", ELOOP: "Too many levels of symbolic links", ENOSPC: "No space left on device", EROFS: "Read-only file system" };
12389
12415
  const description = descriptions[errorCode(error) ?? ""];
12390
- return description ? `${target}: ${description}` : void 0;
12416
+ if (!description) return void 0;
12417
+ publicDiagnosticMessage(error, onInternalError);
12418
+ return `${target}: ${description}`;
12391
12419
  }
12392
12420
  function cdUtf8Width(codePoint) {
12393
12421
  return codePoint <= 127 ? 1 : codePoint <= 2047 ? 2 : codePoint <= 65535 ? 3 : 4;
@@ -12425,7 +12453,7 @@ var CdLookup = class {
12425
12453
  probes = 0;
12426
12454
  async charge(amount) {
12427
12455
  this.signal.throwIfAborted();
12428
- if (amount > 8388608 - this.spent) throw new Error("cd: helper work limit exceeded");
12456
+ if (amount > 8388608 - this.spent) throw new PublicDiagnostic("cd: helper work limit exceeded");
12429
12457
  while (amount > 0) {
12430
12458
  const step = Math.min(amount, 128 - this.spent % 128);
12431
12459
  this.spent += step;
@@ -12446,8 +12474,8 @@ var CdLookup = class {
12446
12474
  for (let index = 0; index < value2.length; ) {
12447
12475
  const codePoint = value2.codePointAt(index);
12448
12476
  const width = cdUtf8Width(codePoint);
12449
- if (bytes2 + width > 65536) throw new Error(search ? "cd: CDPATH exceeds 65536 UTF-8 bytes" : "cd: path exceeds 65536 UTF-8 bytes");
12450
- if (search && codePoint === 58 && ++slots > 4096) throw new Error("cd: CDPATH exceeds 4096 components");
12477
+ if (bytes2 + width > 65536) throw new PublicDiagnostic(search ? "cd: CDPATH exceeds 65536 UTF-8 bytes" : "cd: path exceeds 65536 UTF-8 bytes");
12478
+ if (search && codePoint === 58 && ++slots > 4096) throw new PublicDiagnostic("cd: CDPATH exceeds 4096 components");
12451
12479
  await this.charge(width);
12452
12480
  if (search && codePoint === 58) {
12453
12481
  components.push({ start, end: index, bytes: bytes2 - startBytes });
@@ -12468,13 +12496,13 @@ var CdLookup = class {
12468
12496
  const search = eligible && cdpath ? await this.scan(cdpath, true) : void 0;
12469
12497
  const probe = async (component, componentBytes) => {
12470
12498
  const rawBytes = absolute ? targetBytes : component.startsWith("/") ? componentBytes + 1 + targetBytes : cwdBytes + 1 + (component ? componentBytes + 1 : 0) + targetBytes;
12471
- if (rawBytes > 65536) throw new Error("cd: path exceeds 65536 UTF-8 bytes");
12499
+ if (rawBytes > 65536) throw new PublicDiagnostic("cd: path exceeds 65536 UTF-8 bytes");
12472
12500
  await this.charge(2 * rawBytes);
12473
12501
  const raw = absolute ? target : component.startsWith("/") ? `${component}/${target}` : component ? `${cwd}/${component}/${target}` : `${cwd}/${target}`;
12474
12502
  const path = resolvePath(cwd, raw);
12475
12503
  await this.scan(path);
12476
12504
  this.signal.throwIfAborted();
12477
- if (++this.probes > 4097) throw new Error("cd: probe limit exceeded");
12505
+ if (++this.probes > 4097) throw new PublicDiagnostic("cd: probe limit exceeded");
12478
12506
  await this.charge(1);
12479
12507
  this.signal.throwIfAborted();
12480
12508
  const stat = await fs.stat(path, { signal: this.signal });
@@ -12626,7 +12654,7 @@ var DirectoryStackWork = class {
12626
12654
  }
12627
12655
  };
12628
12656
  var closedSink = { async write() {
12629
- throw Object.assign(new Error("Bad file descriptor"), { code: "EBADF" });
12657
+ throw Object.assign(new PublicDiagnostic("Bad file descriptor"), { code: "EBADF" });
12630
12658
  } };
12631
12659
  var closedSource = { [Symbol.asyncIterator]() {
12632
12660
  let closed = false;
@@ -12643,7 +12671,7 @@ var closedSource = { [Symbol.asyncIterator]() {
12643
12671
  return enqueue(() => {
12644
12672
  if (closed) return { done: true, value: void 0 };
12645
12673
  closed = true;
12646
- throw Object.assign(new Error("Bad file descriptor"), { code: "EBADF" });
12674
+ throw Object.assign(new PublicDiagnostic("Bad file descriptor"), { code: "EBADF" });
12647
12675
  });
12648
12676
  },
12649
12677
  return(value2) {
@@ -13110,14 +13138,14 @@ var Runtime = class _Runtime {
13110
13138
  }
13111
13139
  writeVariable(state, name2, value2, origin = "assignment") {
13112
13140
  if (arrayStore(state)?.get(name2)) throw new ArrayFailure(origin === "arithmetic" ? "indexed arithmetic is unsupported" : "indexed write requires prepared publication");
13113
- if (state.readonlyVariables?.has(name2)) throw new Error(`${name2}: readonly variable`);
13141
+ if (state.readonlyVariables?.has(name2)) throw new PublicDiagnostic(`${name2}: readonly variable`);
13114
13142
  if (shellValueByteLength(value2) > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
13115
13143
  if (name2 === "OPTIND" && state.getopts?.integer && origin !== "arithmetic") {
13116
13144
  try {
13117
13145
  value2 = String(evaluateArithmetic(prepareArithmetic(shellValueText(value2) || "0", this.budget.parsing), this.arithmeticVariables(state), this.budget.parsing));
13118
13146
  } catch (error) {
13119
13147
  this.rethrowArithmeticControl(error);
13120
- throw new ExpansionFailure(message(error));
13148
+ throw new ExpansionFailure(message(error, this.budget.onInternalError));
13121
13149
  }
13122
13150
  }
13123
13151
  publishVariable(state, name2, value2);
@@ -13135,7 +13163,7 @@ var Runtime = class _Runtime {
13135
13163
  if (state.variables.OPTIND !== previous) this.syncGetopts(state);
13136
13164
  }
13137
13165
  unsetVariable(state, name2, internal = false) {
13138
- if (state.readonlyVariables?.has(name2)) throw new Error(`${name2}: readonly variable`);
13166
+ if (state.readonlyVariables?.has(name2)) throw new PublicDiagnostic(`${name2}: readonly variable`);
13139
13167
  delete state.variables[name2];
13140
13168
  state.exported.delete(name2);
13141
13169
  if (name2 === "OPTIND" && !internal) this.syncGetopts(state);
@@ -13853,7 +13881,7 @@ var Runtime = class _Runtime {
13853
13881
  }, (prepared) => evaluateArithmetic(prepared, this.arithmeticVariables(state, io.diagnosticLine), this.budget.parsing)) === 0n);
13854
13882
  } catch (error) {
13855
13883
  this.rethrowArithmeticControl(error);
13856
- throw new Error(`((: ${message(error)}`);
13884
+ throw new PublicDiagnostic(`((: ${message(error, this.budget.onInternalError)}`);
13857
13885
  }
13858
13886
  }
13859
13887
  if (command2.kind === "subshell") {
@@ -13948,9 +13976,10 @@ var Runtime = class _Runtime {
13948
13976
  if (command2.kind !== "simple" && command2.kind !== "subshell" && command2.kind !== "arithmetic" && command2.kind !== "conditional") this.errexit(141, state, io);
13949
13977
  return 141;
13950
13978
  }
13979
+ const publicMessage = message(error, this.budget.onInternalError);
13951
13980
  const line = error instanceof ExpansionFailure ? error.line ?? io.diagnosticLine ?? 1 : io.diagnosticLine ?? 1;
13952
13981
  if (error instanceof NounsetFailure || error instanceof ParameterExpansionFailure) {
13953
- const detail = error instanceof ParameterExpansionFailure ? diagnostic3 ?? message(error) : message(error);
13982
+ const detail = error instanceof ParameterExpansionFailure ? diagnostic3 ?? publicMessage : publicMessage;
13954
13983
  try {
13955
13984
  await writeDiagnostic(io.stderr, `${io.scriptName ?? "shell"}: line ${line}: ${detail}
13956
13985
  `);
@@ -13962,14 +13991,15 @@ var Runtime = class _Runtime {
13962
13991
  }
13963
13992
  throw completedExit(error instanceof ParameterExpansionFailure && !state.isolated ? 127 : 1);
13964
13993
  }
13965
- if (error instanceof ArrayFailure) await writeDiagnostic(io.stderr, `${io.scriptName ?? "shell"}: line ${line}: ${diagnostic3 ?? message(error)}
13994
+ if (error instanceof ArrayFailure) await writeDiagnostic(io.stderr, `${io.scriptName ?? "shell"}: line ${line}: ${diagnostic3 ?? publicMessage}
13966
13995
  `);
13967
13996
  else {
13968
13997
  try {
13969
- await writeDiagnostic(io.stderr, `${io.scriptName ?? "shell"}: line ${line}: ${diagnostic3 ?? message(error)}
13998
+ await writeDiagnostic(io.stderr, `${io.scriptName ?? "shell"}: line ${line}: ${diagnostic3 ?? publicMessage}
13970
13999
  `);
13971
- } catch {
14000
+ } catch (failure) {
13972
14001
  this.signal.throwIfAborted();
14002
+ publicDiagnosticMessage(failure, this.budget.onInternalError);
13973
14003
  }
13974
14004
  }
13975
14005
  if (error instanceof ExpansionFailure || error instanceof BraceExpansionFailure) throw completedExit(error instanceof ParameterExpansionFailure && !state.isolated ? 127 : 1);
@@ -14077,7 +14107,7 @@ var Runtime = class _Runtime {
14077
14107
  if (error instanceof NounsetFailure) throw error;
14078
14108
  if (error instanceof ParameterExpansionFailure && !isolatedInlineInput) throw error;
14079
14109
  if (error instanceof ParameterExpansionFailure) throw new CommandFailure(error.message, state.isolated ? 1 : 127);
14080
- if (error instanceof ExpansionFailure) throw new Error(error.message);
14110
+ if (error instanceof ExpansionFailure) throw new PublicDiagnostic(error.message);
14081
14111
  throw error;
14082
14112
  }
14083
14113
  if (hereString) {
@@ -14090,18 +14120,18 @@ var Runtime = class _Runtime {
14090
14120
  continue;
14091
14121
  }
14092
14122
  const targets = await this.word(redirect.target, state, currentIO());
14093
- if (targets.length !== 1) throw new Error("Ambiguous redirect");
14123
+ if (targets.length !== 1) throw new PublicDiagnostic("Ambiguous redirect");
14094
14124
  const target = targets[0];
14095
14125
  errorTarget = target;
14096
14126
  if (redirect.operator.endsWith("&")) {
14097
14127
  if (target === "-") descriptors.delete(redirect.descriptor);
14098
14128
  else {
14099
- if (!/^\d+-?$/u.test(target)) throw new Error(`${target}: Bad file descriptor`);
14129
+ if (!/^\d+-?$/u.test(target)) throw new PublicDiagnostic(`${target}: Bad file descriptor`);
14100
14130
  const move = target.endsWith("-");
14101
- if (move && !redirect.move) throw new Error(`${target}: ambiguous redirect`);
14131
+ if (move && !redirect.move) throw new PublicDiagnostic(`${target}: ambiguous redirect`);
14102
14132
  const sourceDescriptor = Number(move ? target.slice(0, -1) : target);
14103
14133
  const descriptor2 = descriptors.get(sourceDescriptor);
14104
- if (!descriptor2 || descriptor2.closed || !move && (redirect.operator === "<&" ? !descriptor2.input : !descriptor2.output)) throw new Error(`${move ? sourceDescriptor : target}: Bad file descriptor`);
14134
+ if (!descriptor2 || descriptor2.closed || !move && (redirect.operator === "<&" ? !descriptor2.input : !descriptor2.output)) throw new PublicDiagnostic(`${move ? sourceDescriptor : target}: Bad file descriptor`);
14105
14135
  descriptors.set(redirect.descriptor, { ...descriptor2 });
14106
14136
  if (move && sourceDescriptor !== redirect.descriptor) {
14107
14137
  descriptors.delete(sourceDescriptor);
@@ -14114,7 +14144,7 @@ var Runtime = class _Runtime {
14114
14144
  if (redirect.operator === "<") {
14115
14145
  await interruptible(this.fs.access(path, 4, options3), this.signal);
14116
14146
  const stat = await interruptible(this.fs.stat(path, options3), this.signal);
14117
- if (stat.type === "directory" && !fileShortcut) throw new Error(`${target}: Is a directory`);
14147
+ if (stat.type === "directory" && !fileShortcut) throw new PublicDiagnostic(`${target}: Is a directory`);
14118
14148
  const source = stat.type === "directory" ? toByteSource("") : await fileInput(this.fs, path, this.budget.limits.maxInputBytes, this.signal);
14119
14149
  const input3 = new ShellInput(source, this.budget, this.signal);
14120
14150
  inputs.add(input3);
@@ -14376,7 +14406,7 @@ var Runtime = class _Runtime {
14376
14406
  if (!inlineInput) await assign();
14377
14407
  if (fileShortcut) {
14378
14408
  const input3 = io.descriptors?.get(command2.redirects[0].descriptor)?.input;
14379
- if (!input3) throw new Error("Bad file descriptor");
14409
+ if (!input3) throw new PublicDiagnostic("Bad file descriptor");
14380
14410
  await pipeBytes(input3, io.stdout, this.signal);
14381
14411
  return 0;
14382
14412
  }
@@ -14386,7 +14416,7 @@ var Runtime = class _Runtime {
14386
14416
  this.signal.throwIfAborted();
14387
14417
  const original = error instanceof ExecutionFailure ? error.original : error;
14388
14418
  if (special2 && !(original instanceof ShellLimitError) && !(original instanceof ExpansionFailure) && !(original instanceof Flow) && !(original instanceof ShellSyntaxError)) {
14389
- throw new ExecutionFailure(new FatalCommandFailure(message(original), 1), error instanceof ExecutionFailure ? error.io : io, error instanceof ExecutionFailure ? error.diagnostic : void 0);
14419
+ throw new ExecutionFailure(new FatalCommandFailure(message(original, this.budget.onInternalError), 1), error instanceof ExecutionFailure ? error.io : io, error instanceof ExecutionFailure ? error.diagnostic : void 0);
14390
14420
  }
14391
14421
  if (error instanceof ExecutionFailure) throw error;
14392
14422
  throw new ExecutionFailure(error, io);
@@ -14447,6 +14477,7 @@ var Runtime = class _Runtime {
14447
14477
  fs: this.fs,
14448
14478
  signal: this.commandSignal,
14449
14479
  executionScope: this.budget.executionScope,
14480
+ onInternalError: this.budget.onInternalError,
14450
14481
  registerCleanup: (cleanup) => {
14451
14482
  scope.register(cleanup);
14452
14483
  },
@@ -14828,8 +14859,8 @@ ${functionDisplay(name2, state.functions.get(name2))}`;
14828
14859
  }
14829
14860
  const code = errorCode(error);
14830
14861
  if (code === "ENOENT" || code === "ENOTDIR") continue;
14831
- if (code !== "EACCES" && code !== "EPERM") throw new CommandFailure(filesystemDiagnostic(error, target) ?? `${target}: ${message(error)}`, 126);
14832
- denied ??= new CommandFailure(filesystemDiagnostic(error, target) ?? `${target}: ${message(error)}`, 126);
14862
+ if (code !== "EACCES" && code !== "EPERM") throw new CommandFailure(filesystemDiagnostic(error, target, this.budget.onInternalError) ?? `${target}: ${message(error, this.budget.onInternalError)}`, 126);
14863
+ denied ??= new CommandFailure(filesystemDiagnostic(error, target, this.budget.onInternalError) ?? `${target}: ${message(error, this.budget.onInternalError)}`, 126);
14833
14864
  }
14834
14865
  }
14835
14866
  if (denied && !matches.length && !discovery) throw denied;
@@ -15051,6 +15082,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
15051
15082
  args: argumentValues.args,
15052
15083
  argumentValues,
15053
15084
  executionScope: this.budget.executionScope,
15085
+ onInternalError: this.budget.onInternalError,
15054
15086
  env: Object.assign(/* @__PURE__ */ Object.create(null), incoming.env),
15055
15087
  stdin: input3 ?? incoming.stdin,
15056
15088
  stdout: this.budget.sink(incoming.stdout, runtime.signal),
@@ -15238,7 +15270,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
15238
15270
  this.signal.throwIfAborted();
15239
15271
  if (error instanceof ShellLimitError || error instanceof CommandFailure) throw error;
15240
15272
  if (errorCode(error) === "EFBIG") this.budget.fail("maxSourceBytes");
15241
- throw new CommandFailure(filesystemDiagnostic(error, target) ?? `${target}: ${message(error)}`, errorCode(error) === "ENOENT" ? 127 : 126);
15273
+ throw new CommandFailure(filesystemDiagnostic(error, target, this.budget.onInternalError) ?? `${target}: ${message(error, this.budget.onInternalError)}`, errorCode(error) === "ENOENT" ? 127 : 126);
15242
15274
  }
15243
15275
  if (direct && environmentInterpreter) return this.envShebang(context, state, io, environmentInterpreter[1], target, args, { path, source });
15244
15276
  const units = [];
@@ -15383,7 +15415,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
15383
15415
  this.signal.throwIfAborted();
15384
15416
  if (error instanceof ShellLimitError) throw error;
15385
15417
  if (errorCode(error) === "EFBIG") this.budget.fail("maxSourceBytes");
15386
- const diagnostic3 = error instanceof CommandFailure ? error.message : filesystemDiagnostic(error, target) ?? `${target}: ${message(error)}`;
15418
+ const diagnostic3 = error instanceof CommandFailure ? error.message : filesystemDiagnostic(error, target, this.budget.onInternalError) ?? `${target}: ${message(error, this.budget.onInternalError)}`;
15387
15419
  if (special2) throw new FatalCommandFailure(diagnostic3, 1);
15388
15420
  throw new CommandFailure(diagnostic3, error instanceof CommandFailure ? error.status : 1);
15389
15421
  }
@@ -15596,7 +15628,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
15596
15628
  value2 = evaluateArithmetic(prepareArithmetic(args[index], this.budget.parsing), variables, this.budget.parsing);
15597
15629
  } catch (error) {
15598
15630
  this.rethrowArithmeticControl(error);
15599
- throw new Error(`let: ${message(error)}`);
15631
+ throw new PublicDiagnostic(`let: ${message(error, this.budget.onInternalError)}`);
15600
15632
  }
15601
15633
  if ((index - offset + 1) % 128 === 0) await checkpoint();
15602
15634
  }
@@ -15691,7 +15723,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
15691
15723
  this.writeVariable(state, "OPTIND", String(result.optind), "getopts");
15692
15724
  if (result.argument.kind === "set") this.writeVariable(state, "OPTARG", result.argument.value, "getopts");
15693
15725
  else this.unsetVariable(state, "OPTARG", true);
15694
- if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) throw new Error(`getopts: \`${name2}': not a valid identifier`);
15726
+ if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) throw new PublicDiagnostic(`getopts: \`${name2}': not a valid identifier`);
15695
15727
  await this.assignVariable(state, name2, result.option, "getopts");
15696
15728
  return result.status;
15697
15729
  }
@@ -15714,8 +15746,8 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
15714
15746
  selected = await new CdLookup(this.signal).find(this.fs, state.cwd, target || ".", state.variables.CDPATH);
15715
15747
  } catch (error) {
15716
15748
  this.signal.throwIfAborted();
15717
- const description = filesystemDiagnostic(error, "");
15718
- const text = description ? "" : message(error);
15749
+ const description = filesystemDiagnostic(error, "", this.budget.onInternalError);
15750
+ const text = description ? "" : message(error, this.budget.onInternalError);
15719
15751
  diagnose?.(error, cdDiagnostic(description ? [name2, ": ", target, description] : stackHooks && text.startsWith("cd: ") ? [name2, text.slice(2)] : [text]));
15720
15752
  throw error;
15721
15753
  }
@@ -16621,7 +16653,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
16621
16653
  }, (prepared) => evaluateArithmetic(prepared, this.arithmeticVariables(state, io.diagnosticLine ?? part.line), this.budget.parsing)));
16622
16654
  } catch (error) {
16623
16655
  this.rethrowArithmeticControl(error);
16624
- throw new ExpansionFailure(message(error), io.diagnosticLine ?? part.line);
16656
+ throw new ExpansionFailure(message(error, this.budget.onInternalError), io.diagnosticLine ?? part.line);
16625
16657
  }
16626
16658
  }
16627
16659
  if (part.kind === "substitution") {
@@ -16722,7 +16754,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
16722
16754
  alternate = shellValueText(retained);
16723
16755
  if (operator === "?") throw new ParameterExpansionFailure(`${part.name}: ${alternate || (part.operator.startsWith(":") ? "parameter null or not set" : "parameter not set")}`, io.diagnosticLine ?? part.line);
16724
16756
  if (operator === "=") {
16725
- if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(part.name)) throw new Error("Cannot assign special parameter");
16757
+ if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(part.name)) throw new PublicDiagnostic("Cannot assign special parameter");
16726
16758
  this.writeVariable(state, part.name, retained);
16727
16759
  }
16728
16760
  value2 = alternate;
@@ -16780,7 +16812,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
16780
16812
  return { value: evaluateArithmetic(prepareArithmetic(source, this.budget.parsing), variables, this.budget.parsing), source };
16781
16813
  } catch (error) {
16782
16814
  this.rethrowArithmeticControl(error);
16783
- throw new ExpansionFailure(`${part.name}: ${message(error)}`, line);
16815
+ throw new ExpansionFailure(`${part.name}: ${message(error, this.budget.onInternalError)}`, line);
16784
16816
  } finally {
16785
16817
  retained?.release();
16786
16818
  }
@@ -17553,7 +17585,7 @@ var ShellInput = class _ShellInput {
17553
17585
  decoder3.decode();
17554
17586
  return { value: text.finish(), escaped, terminated };
17555
17587
  } catch (error) {
17556
- if (error instanceof TypeError && error.message.includes("encoded data")) throw new Error("read: unsupported non-UTF-8 text boundary");
17588
+ if (error instanceof TypeError && error.message.includes("encoded data")) throw new PublicDiagnostic("read: unsupported non-UTF-8 text boundary");
17557
17589
  throw error;
17558
17590
  } finally {
17559
17591
  if (offset < chunk.length) this.#cursor.remainder = chunk.subarray(offset);
@@ -17723,6 +17755,7 @@ var Shell = class {
17723
17755
  #active = /* @__PURE__ */ new Set();
17724
17756
  constructor(options3) {
17725
17757
  if (!options3?.fs) throw new TypeError("Shell requires an explicit filesystem");
17758
+ if (options3.onInternalError !== void 0 && typeof options3.onInternalError !== "function") throw new TypeError("onInternalError must be callable");
17726
17759
  warnIfHostProcessEnv(options3.env);
17727
17760
  resolveLimits(options3.limits);
17728
17761
  this.#options = { ...options3, cwd: resolvePath("/", options3.cwd ?? "/"), env: { ...options3.env }, limits: { ...options3.limits } };
@@ -17786,8 +17819,9 @@ var Shell = class {
17786
17819
  }
17787
17820
  async exec(source, options3 = {}) {
17788
17821
  if (this.#disposed) throw new Error("Shell is disposed");
17822
+ if (options3.onInternalError !== void 0 && typeof options3.onInternalError !== "function") throw new TypeError("onInternalError must be callable");
17789
17823
  warnIfHostProcessEnv(options3.env);
17790
- const budget = new Budget(resolveLimits(this.#options.limits, options3.limits), options3.signal);
17824
+ const budget = new Budget(resolveLimits(this.#options.limits, options3.limits), options3.signal, options3.onInternalError ?? this.#options.onInternalError);
17791
17825
  const scope = new InvocationScope(options3.signal);
17792
17826
  const cancellationState = new RuntimeCancellationState();
17793
17827
  const owner = new RootInvocationCancellationOwner(scope);
@@ -18219,9 +18253,9 @@ var defaults = Object.freeze({
18219
18253
  workerOldGenerationMb: 128,
18220
18254
  workerStackMb: 4
18221
18255
  });
18222
- var RegexExecutionError = class extends Error {
18223
- constructor(code, message2) {
18224
- super(code === "MATCH" ? message2 : `regex ${code}: ${message2}`);
18256
+ var RegexExecutionError = class extends PublicDiagnostic {
18257
+ constructor(code, message2, options3) {
18258
+ super(code === "MATCH" ? message2 : `regex ${code}: ${message2}`, options3);
18225
18259
  this.code = code;
18226
18260
  this.name = "RegexExecutionError";
18227
18261
  }
@@ -18428,7 +18462,7 @@ var Slot = class {
18428
18462
  if (this.receiver) this.receiver(value2);
18429
18463
  else this.fail(new RegexExecutionError("PROTOCOL", "unexpected idle message"));
18430
18464
  };
18431
- error = (error) => this.fail(new RegexExecutionError("WORKER_ERROR", error.message));
18465
+ error = (error) => this.fail(new RegexExecutionError("WORKER_ERROR", "internal error", { cause: error }));
18432
18466
  messageerror = () => this.fail(new RegexExecutionError("PROTOCOL", "worker message could not be deserialized"));
18433
18467
  exit = (code) => {
18434
18468
  this.exited = true;
@@ -18793,7 +18827,7 @@ async function* requiredFileInput(context, requirements, mode, file, maxBytes) {
18793
18827
  }
18794
18828
 
18795
18829
  // packages/safe-bash/src/commands/text-programs/shared.ts
18796
- var ProgramError = class extends Error {
18830
+ var ProgramError = class extends PublicDiagnostic {
18797
18831
  };
18798
18832
  var Budget3 = class {
18799
18833
  constructor(context, options3) {
@@ -18882,7 +18916,7 @@ function command(name2, run) {
18882
18916
  return { exitCode: await run(context) };
18883
18917
  } catch (error) {
18884
18918
  context.signal.throwIfAborted();
18885
- await writeDiagnostic(context.stderr, `${name2}: ${error instanceof Error ? error.message : String(error)}
18919
+ await writeDiagnostic(context.stderr, `${name2}: ${publicDiagnosticMessage(error, context.onInternalError)}
18886
18920
  `, context.signal);
18887
18921
  return { exitCode: error instanceof ProgramError ? 2 : 1 };
18888
18922
  }
@@ -20423,7 +20457,7 @@ var defaultFileTypes = Object.freeze({
20423
20457
  for (const patterns2 of Object.values(defaultFileTypes)) Object.freeze(patterns2);
20424
20458
 
20425
20459
  // packages/safe-bash/src/commands/search/options.ts
20426
- var SearchError = class extends Error {
20460
+ var SearchError = class extends PublicDiagnostic {
20427
20461
  };
20428
20462
  function count(value2, flag) {
20429
20463
  if (!/^[0-9]+$/u.test(value2) || !Number.isSafeInteger(Number(value2))) throw new SearchError(`${flag} requires a nonnegative integer`);
@@ -20840,7 +20874,7 @@ var Limits = class {
20840
20874
  }
20841
20875
  };
20842
20876
  async function diagnostic2(context, error) {
20843
- await writeDiagnostic(context.stderr, `rg: ${error instanceof Error ? error.message : String(error)}
20877
+ await writeDiagnostic(context.stderr, `rg: ${publicDiagnosticMessage(error, context.onInternalError)}
20844
20878
  `, context.signal);
20845
20879
  }
20846
20880
  async function* lines2(source, limits, state, binary, nullData) {
@@ -21453,7 +21487,7 @@ var byteLength = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "byteLeng
21453
21487
  var byteOffset = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "byteOffset").get;
21454
21488
  var byteBuffer = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "buffer").get;
21455
21489
  function fail(kind, message2) {
21456
- throw new Error(`bounded regex ${kind}: ${message2}`);
21490
+ throw new PublicDiagnostic(`bounded regex ${kind}: ${message2}`);
21457
21491
  }
21458
21492
  function record3(value2, keys, optional = []) {
21459
21493
  if (value2 === null || typeof value2 !== "object" || Array.isArray(value2)) fail("protocol", "expected a data record");
@@ -21762,7 +21796,8 @@ var CooperativeWorker = class {
21762
21796
  try {
21763
21797
  owned = admit(input3, this.limits, this.#controller.signal);
21764
21798
  } catch (error) {
21765
- failure = error instanceof Error ? error.message.slice(0, 512) : "bounded regex protocol: request admission failed";
21799
+ if (!(error instanceof PublicDiagnostic || error instanceof EreSyntaxError || error instanceof EreUnsupportedError || error instanceof EreProfileLimitError || error instanceof EreUsageUnknownError)) throw error;
21800
+ failure = error.message.slice(0, 512);
21766
21801
  }
21767
21802
  this.#busy = true;
21768
21803
  const task = Promise.resolve().then(async () => {
@@ -21771,7 +21806,13 @@ var CooperativeWorker = class {
21771
21806
  this.#controller.signal.throwIfAborted();
21772
21807
  reply = owned ? await execute2(owned, this.#controller.signal) : { id, error: failure };
21773
21808
  } catch (error) {
21774
- reply = { id, error: error instanceof Error ? error.message.slice(0, 512) : "bounded regex request failed" };
21809
+ if (!(error instanceof PublicDiagnostic || error instanceof EreSyntaxError || error instanceof EreUnsupportedError || error instanceof EreProfileLimitError || error instanceof EreUsageUnknownError)) {
21810
+ owned = void 0;
21811
+ this.#busy = false;
21812
+ for (const listener of this.#listeners.get("error") ?? []) listener(error);
21813
+ return;
21814
+ }
21815
+ reply = { id, error: error.message.slice(0, 512) };
21775
21816
  }
21776
21817
  if (expression && "error" in reply) reply = { id, operation: "expr-match", category: "unsupported", error: reply.error };
21777
21818
  owned = void 0;
@@ -21840,6 +21881,7 @@ function browserCommands(options3 = {}) {
21840
21881
  }
21841
21882
  export {
21842
21883
  ACCESS_MODES,
21884
+ CommandArgumentIdentityError,
21843
21885
  CommandRegistry,
21844
21886
  EreLedger,
21845
21887
  EreProfileLimitError,