@poe-platform/safe-bash 0.1.748 → 0.1.750

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.
@@ -1383,7 +1383,7 @@ function basicCommands() {
1383
1383
  return { exitCode: 0 };
1384
1384
  }),
1385
1385
  define("basename", async (context2) => {
1386
- const parsed = options(context2.args, "as:z", { multiple: "a", suffix: "s", zero: "z" });
1386
+ const parsed = options(context2.args, "as:z", { multiple: "a", suffix: "s", zero: "z" }, true);
1387
1387
  const multiple = parsed.flags.has("a") || parsed.flags.has("s");
1388
1388
  requireOperands(parsed.operands, 1, multiple ? Infinity : 2);
1389
1389
  const suffix2 = value(parsed, "s") ?? (multiple ? void 0 : parsed.operands[1]);
@@ -1395,7 +1395,7 @@ function basicCommands() {
1395
1395
  return { exitCode: 0 };
1396
1396
  }, 1, 1),
1397
1397
  define("dirname", async (context2) => {
1398
- const parsed = options(context2.args, "z", { zero: "z" });
1398
+ const parsed = options(context2.args, "z", { zero: "z" }, true);
1399
1399
  requireOperands(parsed.operands);
1400
1400
  for (const operand of parsed.operands) {
1401
1401
  const parent = dirname(operand);
@@ -56372,7 +56372,6 @@ async function patternAdmission(pattern, context2) {
56372
56372
  }
56373
56373
  } else if (character === "]" && bracket && index > bracketStart + 1) bracket = false;
56374
56374
  }
56375
- if (bracket) unsupported("unclosed bracket pattern");
56376
56375
  }
56377
56376
  async function unary2(operator, value2, context2) {
56378
56377
  if (operator === "-n") return value2.length > 0;
@@ -56443,9 +56442,20 @@ async function leaf(node, context2) {
56443
56442
  return node.operator === "!=" ? !match : match;
56444
56443
  }
56445
56444
  if (node.operator === "<" || node.operator === ">") {
56446
- cLocale(context2);
56447
56445
  await charge(context2, shellValueByteLength(left) + shellValueByteLength(right));
56448
- const order = compareUtf8(left, right);
56446
+ let order;
56447
+ if (cCollation(context2.locale)) {
56448
+ order = compareUtf8(left, right);
56449
+ } else {
56450
+ if (!utf8Locale(context2.locale)) unsupported("collation locale");
56451
+ const locale = context2.locale.split(".")[0].split("_").join("-");
56452
+ try {
56453
+ if (Intl.Collator.supportedLocalesOf([locale]).length === 0) unsupported("collation locale");
56454
+ order = new Intl.Collator(locale).compare(left, right);
56455
+ } catch {
56456
+ unsupported("collation locale");
56457
+ }
56458
+ }
56449
56459
  return node.operator === "<" ? order < 0 : order > 0;
56450
56460
  }
56451
56461
  await charge(context2, left.length + right.length);
@@ -75593,7 +75603,7 @@ var Runtime = class _Runtime {
75593
75603
  }
75594
75604
  }
75595
75605
  if (command7.kind === "conditional") {
75596
- if (rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(command7.expression, 0, rawState)) return false;
75606
+ if (rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(command7.expression, 0, rawState, true)) return false;
75597
75607
  const checkCondNoFile = (e) => {
75598
75608
  if (e.kind === "nonempty") return this.isPureSyncValueWord(e.operand, rawState);
75599
75609
  if (e.kind === "unary") return (e.operator === "-n" || e.operator === "-z" || e.operator === "-v" || syncConditionalFileUnaryOps.has(e.operator) && this._isMemoryBackingFs && this.canFastMemoryRedirect && this.budget.limits.maxFileSystemOperations >= 1e3 && (this._fileWrites === void 0 || this._fileWrites.size === 0) && (this._outputFiles === void 0 || this._outputFiles.size === 0)) && this.isPureSyncValueWord(e.operand, rawState);
@@ -75620,7 +75630,7 @@ var Runtime = class _Runtime {
75620
75630
  }
75621
75631
  return !rem.associative && rem.references === 1;
75622
75632
  }
75623
- return this.isPureSyncValueWord(e.left, rawState) && (e.operator === "==" || e.operator === "=" || e.operator === "!=" ? this.canSyncPatternWordParts(e.right, rawState) : this.isPureSyncValueWord(e.right, rawState));
75633
+ return this.isPureSyncValueWord(e.left, rawState) && this.isPureSyncValueWord(e.right, rawState) && (!(e.operator === "==" || e.operator === "=" || e.operator === "!=") || e.right.parts.length > 0 && e.right.parts.every((p) => p.quoted));
75624
75634
  }
75625
75635
  if (e.kind === "not") return checkCondNoFile(e.operand);
75626
75636
  if (e.kind === "and" || e.kind === "or") return checkCondNoFile(e.left) && checkCondNoFile(e.right);
@@ -75869,8 +75879,9 @@ var Runtime = class _Runtime {
75869
75879
  }
75870
75880
  return false;
75871
75881
  }
75872
- canSyncConditional(expr, depth = 0, rawState) {
75882
+ canSyncConditional(expr, depth = 0, rawState, requireTotal = false) {
75873
75883
  if (depth > 8) return false;
75884
+ if (requireTotal && (expr.kind === "unary" && syncConditionalFileUnaryOps.has(expr.operator) || expr.kind === "binary" && expr.operator !== "==" && expr.operator !== "=" && expr.operator !== "!=" && expr.operator !== "=~")) return false;
75874
75885
  const okWord = (w) => !_Runtime.wordMayMutate(w) || rawState !== void 0 && this.isPureSyncValueWord(w, rawState);
75875
75886
  if (expr.kind === "nonempty") return okWord(expr.operand);
75876
75887
  if (expr.kind === "unary") return (expr.operator === "-n" || expr.operator === "-z" || expr.operator === "-v" || syncConditionalFileUnaryOps.has(expr.operator)) && okWord(expr.operand);
@@ -75886,8 +75897,8 @@ var Runtime = class _Runtime {
75886
75897
  }
75887
75898
  return expr.operator === "<" || expr.operator === ">" || expr.operator === "-eq" || expr.operator === "-ne" || expr.operator === "-lt" || expr.operator === "-le" || expr.operator === "-gt" || expr.operator === "-ge";
75888
75899
  }
75889
- if (expr.kind === "not") return this.canSyncConditional(expr.operand, depth + 1, rawState);
75890
- if (expr.kind === "and" || expr.kind === "or") return this.canSyncConditional(expr.left, depth + 1, rawState) && this.canSyncConditional(expr.right, depth + 1, rawState);
75900
+ if (expr.kind === "not") return this.canSyncConditional(expr.operand, depth + 1, rawState, requireTotal);
75901
+ if (expr.kind === "and" || expr.kind === "or") return this.canSyncConditional(expr.left, depth + 1, rawState, requireTotal) && this.canSyncConditional(expr.right, depth + 1, rawState, requireTotal);
75891
75902
  return false;
75892
75903
  }
75893
75904
  tryEvalFastMemoryFileUnary(op, rawVal, rawState) {
@@ -78540,6 +78551,7 @@ var Runtime = class _Runtime {
78540
78551
  positionalSetVersion,
78541
78552
  savedPositionals: resumeSavedPos,
78542
78553
  callerLoopDepth,
78554
+ lastArgument: fnArgs.at(-1) ?? w0Plain,
78543
78555
  listIndex: bodyRes.listIndex,
78544
78556
  pipelineIndex: bodyRes.pipelineIndex
78545
78557
  });
@@ -78594,6 +78606,7 @@ var Runtime = class _Runtime {
78594
78606
  this.setSyncPipeStatusCell(activeExisting, statusStr);
78595
78607
  activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
78596
78608
  }
78609
+ rawState.lastArgument = fnArgs.at(-1) ?? w0Plain;
78597
78610
  rawState.status = exitStatus;
78598
78611
  if (exitStatus !== 0 && !ignored && rawState.errexit) throw new Flow2("exit", exitStatus);
78599
78612
  return exitStatus;
@@ -79058,22 +79071,22 @@ var Runtime = class _Runtime {
79058
79071
  const list = part.script.lists[0];
79059
79072
  if (list.terminator || list.pipelines.length !== 1) return false;
79060
79073
  const p = list.pipelines[0];
79061
- if (p.negate || p.commands.length < 1 || p.commands.length > 5) return false;
79074
+ if (p.negate || p.commands.length !== 1) return false;
79062
79075
  let cmd = p.commands[0];
79063
- const hasSingleStdinRedir = cmd.kind === "simple" && cmd.redirects.length === 1 && cmd.redirects[0].operator === "<" && (cmd.redirects[0].descriptor === void 0 || cmd.redirects[0].descriptor === 0) && !cmd.redirects[0].move && !cmd.redirects[0].document && cmd.redirects[0].target.plain !== void 0 && !cmd.redirects[0].target.plain.startsWith("-") && cmd.redirects[0].target.plain !== "/dev/stdin";
79064
- const hasSingleHereStringRedir = cmd.kind === "simple" && cmd.redirects.length === 1 && cmd.redirects[0].operator === "<<<" && (cmd.redirects[0].descriptor === void 0 || cmd.redirects[0].descriptor === 0) && !cmd.redirects[0].move && !cmd.redirects[0].document && this.isPureSyncValueWord(cmd.redirects[0].target, rawState);
79065
79076
  if (cmd.kind === "for" || cmd.kind === "arithmetic-for" || cmd.kind === "while") return false;
79066
79077
  if (p.commands.length === 1 && (cmd.kind === "if" || cmd.kind === "case") && this.isPureSyncSubIfOrCase(cmd, rawState)) {
79067
79078
  continue;
79068
79079
  }
79069
- if (cmd.kind !== "simple" || cmd.redirects.length > 0 && !hasSingleStdinRedir && !hasSingleHereStringRedir || cmd.words.length === 0) return false;
79080
+ if (cmd.kind !== "simple" || cmd.redirects.length > 0 || cmd.words.length === 0) return false;
79070
79081
  let w0Plain = cmd.words[0].plain;
79071
79082
  if (p.commands.length === 1 && w0Plain !== void 0 && rawState.functions.has(w0Plain) && this.firstInternalDiscovery(w0Plain, rawState, false) === "function" && !rawState.extensions?.builtins.has(w0Plain)) {
79072
79083
  const fnBody = rawState.functions.get(w0Plain);
79073
- if (fnBody.kind === "group" && fnBody.redirects.length === 0 && fnBody.body.lists.length === 1 && !fnBody.body.lists[0].terminator && fnBody.body.lists[0].pipelines.length === 1 && !fnBody.body.lists[0].pipelines[0].negate && fnBody.body.lists[0].pipelines[0].commands.length === 1 && fnBody.body.lists[0].pipelines[0].commands[0].kind === "simple" && fnBody.body.lists[0].pipelines[0].commands[0].redirects.length === 0 && cmd.words.slice(1).every((w) => this.isPureSyncValueWord(w, rawState))) {
79084
+ if (fnBody.kind === "group" && fnBody.redirects.length === 0 && fnBody.body.lists.length === 1 && !fnBody.body.lists[0].terminator && fnBody.body.lists[0].pipelines.length === 1 && !fnBody.body.lists[0].pipelines[0].negate && fnBody.body.lists[0].pipelines[0].commands.length === 1 && fnBody.body.lists[0].pipelines[0].commands[0].kind === "simple" && fnBody.body.lists[0].pipelines[0].commands[0].redirects.length === 0 && cmd.words.slice(1).every((w) => this.isPureSyncValueWord(w, rawState) && w.parts.length > 0 && w.parts.every(
79085
+ (part2) => part2.quoted || part2.kind === "text" && part2.value.length > 0 && !part2.value.includes(" ") && !part2.value.includes(" ") && !part2.value.includes("\n") && !part2.value.includes("{") && !hasGlobOrEscape(part2.value, true)
79086
+ ))) {
79074
79087
  const innerCmd = fnBody.body.lists[0].pipelines[0].commands[0];
79075
79088
  const innerW0 = innerCmd.words[0]?.plain;
79076
- if (innerW0 && !rawState.functions.has(innerW0) && !rawState.extensions?.builtins.has(innerW0)) {
79089
+ if (innerW0 && (innerW0 === "echo" || innerW0 === "printf" || innerW0 === "dirname" || innerW0 === "basename" || innerW0 === "pwd" || innerW0 === "command" || innerW0 === "type" || innerW0 === "seq") && !rawState.functions.has(innerW0) && !rawState.extensions?.builtins.has(innerW0)) {
79077
79090
  cmd = innerCmd;
79078
79091
  w0Plain = innerW0;
79079
79092
  }
@@ -79085,81 +79098,15 @@ var Runtime = class _Runtime {
79085
79098
  return false;
79086
79099
  }
79087
79100
  if (w0Plain === "command" && cmd.words[1]?.plain === "-v" || w0Plain === "type" && cmd.words[1]?.plain === "-t") {
79088
- if (p.commands.length === 1 && cmd.words.length === 3 && !rawState.functions.has(w0Plain) && !rawState.extensions?.builtins.has(w0Plain) && this.isPureSyncValueWord(cmd.words[2], rawState) && (cmd.words[2].plain !== void 0 && this.tryResolveSyncDiscovery(w0Plain === "command" ? "name" : "kind", cmd.words[2].plain, rawState) !== void 0 || this._isMemoryBackingFs && this.backingFs?.capabilities?.permissions !== true)) {
79089
- continue;
79090
- }
79091
79101
  return false;
79092
79102
  }
79093
- const isFileCommand = w0Plain === "cat" || w0Plain === "head" || w0Plain === "tail" || w0Plain === "jq" || w0Plain === "awk" || w0Plain === "grep" || w0Plain === "sed" || w0Plain === "cut" || w0Plain === "wc" || w0Plain === "sort" || w0Plain === "uniq" || w0Plain === "tr" || hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "numfmt");
79094
- const def = w0Plain ? this.commands.get(w0Plain) ?? (w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "jq" ? this.getExternalCommand(w0Plain) : void 0) : void 0;
79095
- if (!w0Plain || w0Plain !== "printf" && w0Plain !== "echo" && w0Plain !== "dirname" && w0Plain !== "basename" && w0Plain !== "seq" && !isFileCommand || !def || rawState.functions.has(w0Plain) || rawState.extensions?.builtins.has(w0Plain)) return false;
79096
- if ((hasSingleStdinRedir || hasSingleHereStringRedir) && !isFileCommand) return false;
79097
- if (w0Plain === "printf" ? def.execute !== printfCommand.execute : w0Plain === "echo" ? !defaultEchoExecutors.has(def.execute) : w0Plain === "seq" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "jq" ? !builtInDirectContextExecutors.has(def.execute) && customRegisteredCommands.has(def.execute) : !builtInDirectContextExecutors.has(def.execute)) return false;
79103
+ const def = w0Plain ? this.commands.get(w0Plain) : void 0;
79104
+ if (!w0Plain || w0Plain !== "printf" && w0Plain !== "echo" && w0Plain !== "dirname" && w0Plain !== "basename" && w0Plain !== "seq" || !def || rawState.functions.has(w0Plain) || rawState.extensions?.builtins.has(w0Plain)) return false;
79105
+ if (w0Plain === "printf" ? def.execute !== printfCommand.execute : w0Plain === "echo" ? !defaultEchoExecutors.has(def.execute) : w0Plain === "seq" ? !builtInDirectContextExecutors.has(def.execute) && customRegisteredCommands.has(def.execute) : !builtInDirectContextExecutors.has(def.execute)) return false;
79098
79106
  if (!cmd.words.slice(1).every((w) => this.isPureSyncValueWord(w, rawState))) return false;
79099
- if (isFileCommand) {
79100
- if (w0Plain === "tr" && !hasSingleStdinRedir && !hasSingleHereStringRedir) return false;
79101
- if (w0Plain === "grep" && rawState.errexit) return false;
79102
- if (!hasSingleHereStringRedir) {
79103
- const fPlain = hasSingleStdinRedir ? cmd.redirects[0].target.plain : cmd.words[cmd.words.length - 1]?.plain;
79104
- if (!fPlain || fPlain.startsWith("-") || fPlain === "/dev/stdin") return false;
79105
- const vCheck = this.tryReadMemoryFileViewSync(resolvePath(rawState.cwd, fPlain), false);
79106
- if (!vCheck || vCheck.byteLength > 16384 || vCheck.includes(0)) return false;
79107
- }
79108
- const opWords = hasSingleStdinRedir || hasSingleHereStringRedir ? cmd.words.slice(1) : cmd.words.slice(1, -1);
79109
- const opCount = opWords.length;
79110
- const op0 = opWords[0]?.plain;
79111
- const op1 = opWords[1]?.plain;
79112
- if (w0Plain === "cat" || w0Plain === "rev" || w0Plain === "tac") {
79113
- if (opCount !== 0) return false;
79114
- } else {
79115
- if (p.commands.length !== 1 && !hasSingleHereStringRedir) return false;
79116
- if (w0Plain === "head" || w0Plain === "tail") {
79117
- const validHT = opCount === 0 || opCount === 1 && op0 !== void 0 && (/^-(?:n|c|--lines=|--bytes=)?[0-9]{1,5}$/.test(op0) || /^--(?:lines|bytes)=[0-9]{1,5}$/.test(op0) || w0Plain === "tail" && /^(?:-n|--lines=)\+[0-9]{1,5}$/.test(op0) || w0Plain === "head" && /^(?:-n|--lines=)-[0-9]{1,5}$/.test(op0)) || opCount === 2 && (op0 === "-n" && op1 !== void 0 && (/^[0-9]{1,5}$/.test(op1) || w0Plain === "tail" && /^\+[0-9]{1,5}$/.test(op1) || w0Plain === "head" && /^-[0-9]{1,5}$/.test(op1)) || op0 === "-c" && op1 !== void 0 && /^[0-9]{1,5}$/.test(op1));
79118
- if (!validHT) return false;
79119
- }
79120
- const plainOps = [];
79121
- for (let oi = 0; oi < opCount; oi++) {
79122
- const ow = opWords[oi];
79123
- const pw = ow.plain ?? (ow.parts.length > 0 && ow.parts.every((pt) => pt.kind === "text") ? ow.parts.map((pt) => pt.value).join("") : void 0);
79124
- if (pw === void 0) break;
79125
- plainOps.push(pw);
79126
- }
79127
- if (w0Plain === "cut") {
79128
- if (plainOps.length !== opCount || this.evalSyncCut(["\xE9"], plainOps, byteLocale(rawState.variables)) === void 0) return false;
79129
- } else if (w0Plain === "sed") {
79130
- if (plainOps.length !== opCount || this.evalSyncSed([], plainOps) === void 0) return false;
79131
- } else if (w0Plain === "grep") {
79132
- if (plainOps.length !== opCount || this.evalSyncGrep([], plainOps, Boolean(rawState.errexit)) === void 0) return false;
79133
- } else if (w0Plain === "awk") {
79134
- const input3 = this.extractLoopInvariantInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState);
79135
- if (plainOps.length !== opCount || input3 === void 0) return false;
79136
- const lines3 = input3.length === 0 ? [] : input3.split("\n");
79137
- if (input3.endsWith("\n")) lines3.pop();
79138
- if (this.evalSyncAwk(lines3, plainOps) === void 0) return false;
79139
- } else if (w0Plain === "jq") {
79140
- if (plainOps.length !== opCount) return false;
79141
- const jqIn = this.extractLoopInvariantInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState)?.trim();
79142
- if (jqIn === void 0 || this.evalSyncJq(jqIn, plainOps) === void 0) return false;
79143
- } else if (w0Plain === "wc") {
79144
- if (opCount !== 1 || this.normalizeSyncWcFlag(op0) === void 0) return false;
79145
- } else if (w0Plain === "sort") {
79146
- if (plainOps.length !== opCount || this.evalSyncSort([], plainOps, byteLocale(rawState.variables)) === void 0) return false;
79147
- } else if (w0Plain === "uniq") {
79148
- if (plainOps.length !== opCount || this.evalSyncUniq([], plainOps) === void 0) return false;
79149
- } else if (w0Plain === "base64") {
79150
- if (opCount > 1 || opCount === 1 && op0 !== "-d" && op0 !== "--decode") return false;
79151
- } else if (w0Plain === "tr") {
79152
- if (plainOps.length !== opCount || this.evalSyncTr("", plainOps) === void 0) return false;
79153
- } else if (w0Plain === "nl") {
79154
- if (plainOps.length !== opCount || this.evalSyncNl([], plainOps) === void 0) return false;
79155
- } else if (w0Plain === "paste") {
79156
- if (plainOps.length !== opCount || this.evalSyncPaste([], plainOps) === void 0) return false;
79157
- } else if (w0Plain === "numfmt") {
79158
- const nmCheck = this.extractLoopInvariantInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState)?.trim();
79159
- if (nmCheck === void 0 || plainOps.length !== opCount || this.evalSyncNumfmt(nmCheck.split("\n"), plainOps) === void 0) return false;
79160
- }
79161
- }
79162
- }
79107
+ if ((w0Plain === "echo" || w0Plain === "basename" || w0Plain === "dirname") && !cmd.words.slice(1).every((w) => w.parts.length > 0 && w.parts.every(
79108
+ (part2) => part2.quoted || part2.kind === "text" && part2.value.length > 0 && !part2.value.includes(" ") && !part2.value.includes(" ") && !part2.value.includes("\n") && !part2.value.includes("{") && !hasGlobOrEscape(part2.value, true)
79109
+ ))) return false;
79163
79110
  if (w0Plain === "printf") {
79164
79111
  if (!this.isSyncPrintfCallOk(cmd, 1, rawState, this._activePrintfInductionName)) return false;
79165
79112
  } else if (w0Plain === "echo") {
@@ -79185,90 +79132,13 @@ var Runtime = class _Runtime {
79185
79132
  }
79186
79133
  if ((w0Plain === "dirname" ? this.evalSyncDirname(simArgs) : this.evalSyncBasename(simArgs)) === void 0) return false;
79187
79134
  } else if (w0Plain === "seq") {
79188
- const isSeqIntWord = (w) => {
79189
- if (w.plain !== void 0) return /^-?[0-9]{1,7}$/.test(w.plain);
79190
- if (w.parts.length === 1) {
79191
- const p02 = w.parts[0];
79192
- if (p02.kind === "arithmetic") return true;
79193
- if (p02.kind === "variable" && !p02.indirect && !p02.prefixNames && !p02.substring && !p02.transform && p02.operator === void 0 && getArraySelector(p02) === void 0) {
79194
- const cur = rawState.variables[p02.name];
79195
- return cur !== void 0 && /^-?[0-9]{1,7}$/.test(cur);
79196
- }
79197
- }
79198
- return false;
79199
- };
79200
- if (cmd.words.length < 2 || cmd.words.length > 4 || !cmd.words.slice(1).every(isSeqIntWord)) return false;
79201
- }
79202
- if (p.commands.length >= 2) {
79203
- if (w0Plain !== "printf" && w0Plain !== "echo" && w0Plain !== "seq" && w0Plain !== "cat" && !hasSingleHereStringRedir || syncPurePipelineSlotInUse || !this.budget.canSyncPurePipe || rawState.errexit || rawState.nounset) return false;
79204
- if (w0Plain === "printf") {
79205
- if (!this.isSyncPrintfCallOk(cmd, 1, rawState, this._activePrintfInductionName)) return false;
79206
- }
79207
- for (let sIdx = 1; sIdx < p.commands.length; sIdx++) {
79208
- const sCmd = p.commands[sIdx];
79209
- if (sCmd.kind !== "simple" || sCmd.redirects.length !== 0 || sCmd.words.length === 0) return false;
79210
- const sName = sCmd.words[0].plain;
79211
- if (!sName || sName !== "cut" && sName !== "tr" && sName !== "sort" && sName !== "head" && sName !== "tail" && sName !== "wc" && sName !== "sed" && sName !== "uniq" && sName !== "rev" && sName !== "awk" && sName !== "grep" && sName !== "jq" && sName !== "base64" && sName !== "tac" && sName !== "nl" && sName !== "paste" && sName !== "numfmt") return false;
79212
- const sDef = this.commands.get(sName) ?? (sName === "rev" || sName === "tac" || sName === "nl" || sName === "paste" || sName === "jq" ? this.getExternalCommand(sName) : void 0);
79213
- if (!sDef || customRegisteredCommands.has(sDef.execute) || sName !== "rev" && sName !== "tac" && sName !== "nl" && sName !== "paste" && sName !== "jq" && !builtInDirectContextExecutors.has(sDef.execute)) return false;
79214
- if (rawState.functions.has(sName) || rawState.extensions?.builtins.has(sName)) return false;
79215
- const sArgWords = sCmd.words.slice(1);
79216
- const sPlainArgs = [];
79217
- let allPlainStageArgs = true;
79218
- for (let k = 0; k < sArgWords.length; k++) {
79219
- const sw = sArgWords[k];
79220
- const sp = sw.plain ?? (sw.parts.length > 0 && sw.parts.every((pt) => pt.kind === "text") ? sw.parts.map((pt) => pt.value).join("") : void 0);
79221
- if (sp === void 0) {
79222
- allPlainStageArgs = false;
79223
- break;
79224
- }
79225
- sPlainArgs.push(sp);
79226
- }
79227
- if (!allPlainStageArgs) return false;
79228
- if (sName === "sort") {
79229
- if (this.evalSyncSort([], sPlainArgs, byteLocale(rawState.variables)) === void 0) return false;
79230
- } else if (sName === "uniq") {
79231
- if (this.evalSyncUniq([], sPlainArgs) === void 0) return false;
79232
- } else if (sName === "wc") {
79233
- if (sPlainArgs.length !== 1 || this.normalizeSyncWcFlag(sPlainArgs[0]) === void 0) return false;
79234
- } else if (sName === "head" || sName === "tail") {
79235
- const okHT = sPlainArgs.length === 0 || sPlainArgs.length === 1 && (/^-(?:n|c)?[0-9]{1,5}$/.test(sPlainArgs[0]) || /^--(?:lines|bytes)=[0-9]{1,5}$/.test(sPlainArgs[0]) || sName === "tail" && /^(?:-n|--lines=)\+[0-9]{1,5}$/.test(sPlainArgs[0]) || sName === "head" && /^(?:-n|--lines=)-[0-9]{1,5}$/.test(sPlainArgs[0])) || sPlainArgs.length === 2 && (sPlainArgs[0] === "-n" && (/^[0-9]{1,5}$/.test(sPlainArgs[1]) || sName === "tail" && /^\+[0-9]{1,5}$/.test(sPlainArgs[1]) || sName === "head" && /^-[0-9]{1,5}$/.test(sPlainArgs[1])) || sPlainArgs[0] === "-c" && /^[0-9]{1,5}$/.test(sPlainArgs[1]));
79236
- if (!okHT) return false;
79237
- } else if (sName === "cut") {
79238
- if (this.evalSyncCut(["\xE9"], sPlainArgs, byteLocale(rawState.variables)) === void 0) return false;
79239
- } else if (sName === "sed") {
79240
- if (this.evalSyncSed([], sPlainArgs) === void 0) return false;
79241
- } else if (sName === "awk") {
79242
- if (sIdx !== 1) return false;
79243
- const input3 = this.extractLoopInvariantInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState);
79244
- if (input3 === void 0) return false;
79245
- const lines3 = input3.length === 0 ? [] : input3.split("\n");
79246
- if (input3.endsWith("\n")) lines3.pop();
79247
- if (this.evalSyncAwk(lines3, sPlainArgs) === void 0) return false;
79248
- } else if (sName === "grep") {
79249
- if (this.evalSyncGrep([], sPlainArgs, Boolean(rawState.errexit)) === void 0) return false;
79250
- } else if (sName === "tr") {
79251
- if (this.evalSyncTr("", sPlainArgs) === void 0) return false;
79252
- } else if (sName === "jq") {
79253
- if (sIdx !== 1) return false;
79254
- const jqIn = this.extractLoopInvariantInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState)?.trim();
79255
- if (jqIn === void 0 || this.evalSyncJq(jqIn, sPlainArgs) === void 0) return false;
79256
- } else if (sName === "base64") {
79257
- if (sPlainArgs.length !== 0) return false;
79258
- } else if (sName === "tac") {
79259
- if (sPlainArgs.length !== 0 || w0Plain !== "echo" && !hasSingleHereStringRedir) return false;
79260
- } else if (sName === "nl") {
79261
- if (w0Plain !== "echo" && !hasSingleHereStringRedir || this.evalSyncNl([], sPlainArgs) === void 0) return false;
79262
- } else if (sName === "paste") {
79263
- if (this.evalSyncPaste([], sPlainArgs) === void 0) return false;
79264
- } else if (sName === "numfmt") {
79265
- if (sIdx !== 1) return false;
79266
- const nmCheck = this.extractLoopInvariantInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState)?.trim();
79267
- if (nmCheck === void 0 || this.evalSyncNumfmt(nmCheck.split("\n"), sPlainArgs) === void 0) return false;
79268
- } else if (sName === "rev") {
79269
- if (sPlainArgs.length !== 0) return false;
79270
- }
79271
- }
79135
+ if (cmd.words.length < 2 || cmd.words.length > 4) return false;
79136
+ const operands = cmd.words.slice(1).map((w) => w.plain);
79137
+ if (!operands.every((value2) => value2 !== void 0 && Number.isInteger(Number(value2)) && String(Number(value2)) === value2 && Math.abs(Number(value2)) <= 9999999)) return false;
79138
+ const first = operands.length === 1 ? 1 : Number(operands[0]);
79139
+ const increment = operands.length === 3 ? Number(operands[1]) : 1;
79140
+ const last = Number(operands[operands.length - 1]);
79141
+ if (increment === 0 || Math.abs((last - first) / increment) > 1024) return false;
79272
79142
  }
79273
79143
  continue;
79274
79144
  }
@@ -79632,7 +79502,7 @@ var Runtime = class _Runtime {
79632
79502
  if (bc.kind === "arithmetic") {
79633
79503
  if (bc.redirects.length !== 0 || bc.expression.error || bc.expression.hasMutation || bc.expression.hasSubscript || !isSafeSmiProgram(bc.expression) || !this.canSyncArithmeticWithoutFault(bc.expression.tree, rawState, bc.line ?? 1)) return false;
79634
79504
  } else if (bc.kind === "conditional") {
79635
- if (bc.redirects.length !== 0 || rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(bc.expression, 0, rawState)) return false;
79505
+ if (bc.redirects.length !== 0 || rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(bc.expression, 0, rawState, true)) return false;
79636
79506
  if (bc.expression.kind === "binary" && bc.expression.operator === "=~") return false;
79637
79507
  } else if (!this.extractPosixBracketCondExpr(bc, rawState, true, br.body)) {
79638
79508
  return false;
@@ -79662,7 +79532,7 @@ var Runtime = class _Runtime {
79662
79532
  if (pipeline.negate || pipeline.commands.length !== 1) return false;
79663
79533
  const cmd = pipeline.commands[0];
79664
79534
  const canSyncLoopCondCmd = (c) => {
79665
- if (c.redirects.length !== 0 || rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(c.expression, 0, rawState)) return false;
79535
+ if (c.redirects.length !== 0 || rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(c.expression, 0, rawState, true)) return false;
79666
79536
  const checkLeaf = (e) => {
79667
79537
  if (e.kind === "nonempty") return this.isPureSyncValueWord(e.operand, rawState);
79668
79538
  if (e.kind === "unary") return (e.operator === "-n" || e.operator === "-z" || e.operator === "-v" || syncConditionalFileUnaryOps.has(e.operator) && this._isMemoryBackingFs && this.canFastMemoryRedirect && this.budget.limits.maxFileSystemOperations >= 1e3 && (this._fileWrites === void 0 || this._fileWrites.size === 0) && (this._outputFiles === void 0 || this._outputFiles.size === 0)) && this.isPureSyncValueWord(e.operand, rawState);
@@ -79672,7 +79542,7 @@ var Runtime = class _Runtime {
79672
79542
  if (patInfo?.isVar) return false;
79673
79543
  return this.isPureSyncValueWord(e.left, rawState) && this.getFastAnchoredEreRegex(e.right, rawState) !== void 0 && !rawState.readonlyVariables?.has("BASH_REMATCH") && !rawState.exported.has("BASH_REMATCH") && !stateMonitor(rawState)?.hasOverlay("BASH_REMATCH") && !(store ?? requireArrays(rawState))?.watches.has("BASH_REMATCH");
79674
79544
  }
79675
- return this.isPureSyncValueWord(e.left, rawState) && (e.operator === "==" || e.operator === "=" || e.operator === "!=" ? this.canSyncPatternWordParts(e.right, rawState) : this.isPureSyncValueWord(e.right, rawState));
79545
+ return this.isPureSyncValueWord(e.left, rawState) && this.isPureSyncValueWord(e.right, rawState) && (!(e.operator === "==" || e.operator === "=" || e.operator === "!=") || e.right.parts.length > 0 && e.right.parts.every((p2) => p2.quoted));
79676
79546
  }
79677
79547
  if (e.kind === "not") return checkLeaf(e.operand);
79678
79548
  if (e.kind === "and" || e.kind === "or") return checkLeaf(e.left) && checkLeaf(e.right);
@@ -79792,6 +79662,7 @@ var Runtime = class _Runtime {
79792
79662
  if (this.extractPosixBracketCondExpr(cmd, rawState, true, script2) !== void 0) continue;
79793
79663
  if (cmd.kind !== "simple") return false;
79794
79664
  if (nested && cmd.redirects.length !== 0) return false;
79665
+ if (cmd.words.length === 0) return false;
79795
79666
  if (cmd.redirects.length === 1) {
79796
79667
  const r0Check = cmd.redirects[0];
79797
79668
  const w0DevPlain = cmd.words[0].plain;
@@ -80377,21 +80248,12 @@ var Runtime = class _Runtime {
80377
80248
  const forPrintfInd = command7.kind === "for" && command7.words?.length === 1 && /^\{[0-9]{1,4}\.\.[0-9]{1,4}(?:\.\.[1-9][0-9]{0,2})?\}$/.test(command7.words[0].plain ?? "") ? command7.name : void 0;
80378
80249
  const printfInductionName = initializer?.kind === "binary" && initializer.operator === "=" && initializer.left.kind === "name" && initializer.right.kind === "literal" && initializer.right.value >= 0n && initializer.right.value <= 2000n && condition?.kind === "binary" && (condition.operator === "<" || condition.operator === "<=") && condition.left.kind === "name" && condition.left.name === initializer.left.name && condition.right.kind === "literal" && condition.right.value >= 0n && condition.right.value <= 2000n && increment?.kind === "unary" && increment.operator === "++" && increment.operand.kind === "name" && increment.operand.name === initializer.left.name && this.canSyncPrintfInductionBody(command7.body, rawState, initializer.left.name) ? initializer.left.name : whilePrintfInd && this.canSyncPrintfInductionBody(command7.body, rawState, whilePrintfInd) ? whilePrintfInd : forPrintfInd && this.canSyncPrintfInductionBody(command7.body, rawState, forPrintfInd) ? forPrintfInd : void 0;
80379
80250
  const prevActivePrintfInd = this._activePrintfInductionName;
80380
- const prevActiveLoopScript = this._activeLoopBodyScript;
80381
- const prevActiveLoopCond = this._activeLoopCondScript;
80382
- const prevActiveLoopVar = this._activeLoopVarName;
80383
80251
  this._activePrintfInductionName = printfInductionName;
80384
- this._activeLoopBodyScript = command7.body;
80385
- this._activeLoopCondScript = command7.kind === "while" ? command7.condition : void 0;
80386
- this._activeLoopVarName = command7.kind === "for" ? command7.name : printfInductionName ?? (whilePrintfInd || void 0);
80387
80252
  let bodySyncOk = false;
80388
80253
  try {
80389
80254
  bodySyncOk = !(guestArrays(rawState) && (guestArrays(rawState).watches.size > 0 || this.budget.limits.maxExpansionBytes < 65536)) && this.canSyncLoopBody(command7.body, rawState, io, false, printfInductionName);
80390
80255
  } finally {
80391
80256
  this._activePrintfInductionName = prevActivePrintfInd;
80392
- this._activeLoopBodyScript = prevActiveLoopScript;
80393
- this._activeLoopCondScript = prevActiveLoopCond;
80394
- this._activeLoopVarName = prevActiveLoopVar;
80395
80257
  }
80396
80258
  if (!bodySyncOk) {
80397
80259
  command7._skipTrySyncLoop = true;
@@ -80907,7 +80769,7 @@ var Runtime = class _Runtime {
80907
80769
  }
80908
80770
  whileArithProg = condCmd.expression;
80909
80771
  } else if (condCmd.kind === "conditional") {
80910
- if (condCmd.redirects.length !== 0 || rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(condCmd.expression, 0, rawState)) return void 0;
80772
+ if (condCmd.redirects.length !== 0 || rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(condCmd.expression, 0, rawState, true)) return void 0;
80911
80773
  const checkWhileCond = (e, depth) => {
80912
80774
  if (e.kind === "nonempty") return this.isPureSyncValueWord(e.operand, rawState);
80913
80775
  if (e.kind === "unary") return (e.operator === "-n" || e.operator === "-z" || e.operator === "-v") && this.isPureSyncValueWord(e.operand, rawState);
@@ -80917,7 +80779,7 @@ var Runtime = class _Runtime {
80917
80779
  if (patInfo?.isVar) return false;
80918
80780
  return depth === 0 && this.isPureSyncValueWord(e.left, rawState) && this.getFastAnchoredEreRegex(e.right, rawState) !== void 0 && !rawState.readonlyVariables?.has("BASH_REMATCH") && !rawState.exported.has("BASH_REMATCH") && !monitor.hasOverlay("BASH_REMATCH") && !(store ?? requireArrays(rawState))?.watches.has("BASH_REMATCH");
80919
80781
  }
80920
- return this.isPureSyncValueWord(e.left, rawState) && (e.operator === "==" || e.operator === "=" || e.operator === "!=" ? this.canSyncPatternWordParts(e.right, rawState) : this.isPureSyncValueWord(e.right, rawState));
80782
+ return this.isPureSyncValueWord(e.left, rawState) && this.isPureSyncValueWord(e.right, rawState) && (!(e.operator === "==" || e.operator === "=" || e.operator === "!=") || e.right.parts.length > 0 && e.right.parts.every((p) => p.quoted));
80921
80783
  }
80922
80784
  if (e.kind === "not") return checkWhileCond(e.operand, depth + 1);
80923
80785
  if (e.kind === "and" || e.kind === "or") return checkWhileCond(e.left, depth + 1) && checkWhileCond(e.right, depth + 1);
@@ -81176,7 +81038,7 @@ var Runtime = class _Runtime {
81176
81038
  if (store) store.epoch = restEpoch2;
81177
81039
  return loopStatus2;
81178
81040
  }
81179
- if (!isShellIdentifier(command7.name) || command7.name === "OPTIND" || command7.name.includes("[") || store?.get(command7.name) || command7.words && (command7.words.length === 0 || command7.words.length > 64) || rawState.braceexpand === false) {
81041
+ if (!isShellIdentifier(command7.name) || command7.name === "OPTIND" || controlNames.has(command7.name) || command7.name === "LC_COLLATE" || command7.name.includes("[") || store?.get(command7.name) || command7.words && (command7.words.length === 0 || command7.words.length > 64) || rawState.braceexpand === false) {
81180
81042
  return void 0;
81181
81043
  }
81182
81044
  const activeValScope = io[valueScope];
@@ -81631,149 +81493,6 @@ ${s1}
81631
81493
  return pos <= 128 ? fastRedirectScratchViews[pos] : fastRedirectScratchBytes.subarray(0, pos);
81632
81494
  }
81633
81495
  _activePrintfInductionName = void 0;
81634
- _activeLoopBodyScript = void 0;
81635
- _activeLoopCondScript = void 0;
81636
- _activeLoopVarName = void 0;
81637
- isVarUnmutatedInScript(varName, script2) {
81638
- for (const list of script2.lists) {
81639
- for (const pipeline of list.pipelines) {
81640
- for (const cmd of pipeline.commands) {
81641
- if (cmd.kind === "arithmetic") {
81642
- if (cmd.expression.hasMutation && cmd.expression.source.includes(varName)) return false;
81643
- continue;
81644
- }
81645
- if (cmd.kind === "if") {
81646
- for (const br of cmd.branches) {
81647
- if (!this.isVarUnmutatedInScript(varName, br.condition) || !this.isVarUnmutatedInScript(varName, br.body)) return false;
81648
- }
81649
- if (cmd.otherwise && !this.isVarUnmutatedInScript(varName, cmd.otherwise)) return false;
81650
- continue;
81651
- }
81652
- if (cmd.kind === "case") {
81653
- for (const cl of cmd.clauses) {
81654
- if (!this.isVarUnmutatedInScript(varName, cl.body)) return false;
81655
- }
81656
- continue;
81657
- }
81658
- if (cmd.kind === "for") {
81659
- if (cmd.name === varName || !this.isVarUnmutatedInScript(varName, cmd.body)) return false;
81660
- continue;
81661
- }
81662
- if (cmd.kind === "arithmetic-for") {
81663
- if (cmd.expressions.some((e) => e && e.hasMutation && e.source.includes(varName)) || !this.isVarUnmutatedInScript(varName, cmd.body)) return false;
81664
- continue;
81665
- }
81666
- if (cmd.kind === "while") {
81667
- if (!this.isVarUnmutatedInScript(varName, cmd.condition) || !this.isVarUnmutatedInScript(varName, cmd.body)) return false;
81668
- continue;
81669
- }
81670
- if (cmd.kind === "group" || cmd.kind === "subshell") {
81671
- if (!this.isVarUnmutatedInScript(varName, cmd.body)) return false;
81672
- continue;
81673
- }
81674
- if (cmd.kind !== "simple") return false;
81675
- for (const w of cmd.words) {
81676
- const arrAss = getArrayAssignment(w);
81677
- if (arrAss && arrAss.name === varName) return false;
81678
- const p02 = w.parts[0];
81679
- if (p02?.kind === "text" && !p02.quoted && (p02.value.startsWith(varName + "=") || p02.value.startsWith(varName + "+=") || p02.value.startsWith(varName + "["))) return false;
81680
- }
81681
- const w0 = cmd.words[0]?.plain;
81682
- if (w0 === "read" || w0 === "unset" || w0 === "declare" || w0 === "typeset" || w0 === "local" || w0 === "export" || w0 === "mapfile" || w0 === "readarray") {
81683
- if (w0 === "read" && varName === "REPLY") return false;
81684
- if (cmd.words.slice(1).some((w) => (w.plain ?? "").includes(varName))) return false;
81685
- }
81686
- if (w0 === "printf" && cmd.words[1]?.plain === "-v" && (cmd.words[2]?.plain ?? "").startsWith(varName)) return false;
81687
- for (const w of [...cmd.words, ...cmd.redirects.map((r) => r.target)]) {
81688
- for (const pt of w.parts) {
81689
- if (pt.kind === "arithmetic" && pt.expression.hasMutation && pt.expression.source.includes(varName)) return false;
81690
- if (pt.kind === "substitution" && !this.isVarUnmutatedInScript(varName, pt.script)) return false;
81691
- }
81692
- }
81693
- }
81694
- }
81695
- }
81696
- return true;
81697
- }
81698
- isVarUnmutatedInActiveLoop(varName) {
81699
- if (varName === this._activeLoopVarName || varName === this._activePrintfInductionName) return false;
81700
- if (this._activeLoopCondScript && !this.isVarUnmutatedInScript(varName, this._activeLoopCondScript)) return false;
81701
- if (this._activeLoopBodyScript && !this.isVarUnmutatedInScript(varName, this._activeLoopBodyScript)) return false;
81702
- return true;
81703
- }
81704
- isFileReadOnlyScript(script2, rawState) {
81705
- const visit = (value2) => {
81706
- if (value2 === null || typeof value2 !== "object") return true;
81707
- if (Array.isArray(value2)) return value2.every(visit);
81708
- const node = value2;
81709
- if (typeof node.operator === "string" && "target" in node && !["<", "<<<", "<<", "<<-"].includes(node.operator)) return false;
81710
- if (node.kind === "simple") {
81711
- const cmd = value2;
81712
- const name2 = cmd.words[0]?.plain;
81713
- if (name2 === void 0 && !cmd.words.every((word) => this.assignment(word) || getArrayAssignment(word))) return false;
81714
- if (name2 !== void 0 && (hasShellFunction(rawState, name2) || !["jq", "cat", "echo", "printf", "test", "[", ":", "true", "false"].includes(name2))) return false;
81715
- }
81716
- return Object.values(node).every(visit);
81717
- };
81718
- return visit(script2);
81719
- }
81720
- extractLoopInvariantInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState) {
81721
- const w0 = cmd.words[0]?.plain;
81722
- const resolveInvariantWord = (w) => {
81723
- if (w.plain !== void 0) return w.plain;
81724
- if (w.parts.length > 0 && w.parts.every((pt) => pt.kind === "text")) return w.parts.map((pt) => pt.value).join("");
81725
- if (w.parts.length === 1 && w.parts[0].kind === "variable") {
81726
- const vp = w.parts[0];
81727
- if (!vp.indirect && !vp.operator && !vp.substring && !vp.transform && !vp.length && !vp.prefixNames && getArraySelector(vp) === void 0 && this.isVarUnmutatedInActiveLoop(vp.name)) {
81728
- const val = rawState.variables[vp.name];
81729
- if (typeof val === "string") return val;
81730
- }
81731
- }
81732
- return void 0;
81733
- };
81734
- if (w0 === "jq" || w0 === "numfmt" || w0 === "awk") {
81735
- if (hasSingleHereStringRedir) {
81736
- const resolved = resolveInvariantWord(cmd.redirects[0].target);
81737
- return resolved !== void 0 ? resolved + "\n" : void 0;
81738
- }
81739
- if (this._fileWrites?.size || this._outputFiles?.size) return void 0;
81740
- if ([this._activeLoopBodyScript, this._activeLoopCondScript].some((script2) => script2 && !this.isFileReadOnlyScript(script2, rawState))) return void 0;
81741
- const fPlain = hasSingleStdinRedir ? cmd.redirects[0].target.plain : cmd.words[cmd.words.length - 1]?.plain;
81742
- if (!fPlain || fPlain.startsWith("-") || fPlain === "/dev/stdin") return void 0;
81743
- const vCheck = this.tryReadMemoryFileViewSync(resolvePath(rawState.cwd, fPlain), false);
81744
- if (!vCheck || vCheck.byteLength > 16384 || vCheck.includes(0)) return void 0;
81745
- return sharedSyncPipeDecoder.decode(vCheck);
81746
- }
81747
- if (w0 === "cat") {
81748
- if (hasSingleHereStringRedir) {
81749
- const resolved = resolveInvariantWord(cmd.redirects[0].target);
81750
- return resolved !== void 0 ? resolved + "\n" : void 0;
81751
- }
81752
- if (this._fileWrites?.size || this._outputFiles?.size) return void 0;
81753
- if ([this._activeLoopBodyScript, this._activeLoopCondScript].some((script2) => script2 && !this.isFileReadOnlyScript(script2, rawState))) return void 0;
81754
- const fPlain = hasSingleStdinRedir ? cmd.redirects[0].target.plain : cmd.words[1]?.plain;
81755
- if (!fPlain || fPlain.startsWith("-") || fPlain === "/dev/stdin") return void 0;
81756
- const vCheck = this.tryReadMemoryFileViewSync(resolvePath(rawState.cwd, fPlain), false);
81757
- if (!vCheck || vCheck.byteLength > 16384 || vCheck.includes(0)) return void 0;
81758
- return sharedSyncPipeDecoder.decode(vCheck);
81759
- }
81760
- if (w0 === "echo" && cmd.words.length === 2) {
81761
- const resolved = resolveInvariantWord(cmd.words[1]);
81762
- if (resolved !== void 0 && !resolved.startsWith("-")) return resolved + "\n";
81763
- return void 0;
81764
- }
81765
- if (w0 === "printf" && cmd.words.length >= 2) {
81766
- const args = [];
81767
- for (let i = 1; i < cmd.words.length; i++) {
81768
- const r = resolveInvariantWord(cmd.words[i]);
81769
- if (r === void 0) return void 0;
81770
- args.push(r);
81771
- }
81772
- const formatted3 = tryFastPrintf(args);
81773
- return formatted3;
81774
- }
81775
- return void 0;
81776
- }
81777
81496
  canSyncPrintfInductionBody(script2, rawState, inductionName) {
81778
81497
  for (const list of script2.lists) for (const pipeline of list.pipelines) for (const command7 of pipeline.commands) {
81779
81498
  if (command7.kind === "arithmetic") {
@@ -82351,6 +82070,7 @@ ${s1}
82351
82070
  return check(tree);
82352
82071
  }
82353
82072
  canSyncErrorArithmeticStmt(expr, rawState) {
82073
+ if (expr.source.includes("$")) return false;
82354
82074
  if (expr.source.includes("/") || expr.source.includes("%") || expr.source.includes("<<") || expr.source.includes(">>") || expr.source.includes("**") || expr.source.includes("[")) return false;
82355
82075
  try {
82356
82076
  const cachedExpr = expr;
@@ -82492,27 +82212,40 @@ ${s1}
82492
82212
  const prevFastSubPos = this._fastSubPositional;
82493
82213
  rawState.positional = fnArgs;
82494
82214
  this._fastSubPositional = fnArgs;
82495
- const savedLocals = new Array(fnCall.locals.length);
82215
+ const savedLocals = [];
82216
+ const seenLocals = /* @__PURE__ */ new Set();
82496
82217
  try {
82497
- for (let i = 0; i < fnCall.locals.length; i++) {
82498
- const loc = fnCall.locals[i];
82499
- if (loc.isFirstInCmd) this.budget.tick();
82500
- savedLocals[i] = { name: loc.name, val: rawState.variables[loc.name], wasTouched: touched.has(loc.name) };
82501
- if (loc.valueWord !== void 0) {
82502
- rawState.variables[loc.name] = this.fastValueWord(loc.valueWord, rawState, io, false, false, false, false, 0, step.line);
82503
- touched.add(loc.name);
82504
- } else {
82505
- delete rawState.variables[loc.name];
82218
+ for (let i = 0; i < fnCall.locals.length; ) {
82219
+ this.budget.tick();
82220
+ let end = i + 1;
82221
+ while (end < fnCall.locals.length && !fnCall.locals[end].isFirstInCmd) end++;
82222
+ const values = fnCall.locals.slice(i, end).map((loc) => loc.valueWord === void 0 ? void 0 : this.fastValueWord(loc.valueWord, rawState, io, false, false, false, false, 0, step.line));
82223
+ const start = i;
82224
+ for (; i < end; i++) {
82225
+ const loc = fnCall.locals[i];
82226
+ const alreadyLocal = seenLocals.has(loc.name);
82227
+ if (!alreadyLocal) {
82228
+ savedLocals.push({ name: loc.name, val: rawState.variables[loc.name], wasTouched: touched.has(loc.name) });
82229
+ seenLocals.add(loc.name);
82230
+ }
82231
+ const value2 = values[i - start];
82232
+ if (value2 !== void 0) {
82233
+ rawState.variables[loc.name] = value2;
82234
+ touched.add(loc.name);
82235
+ } else if (!alreadyLocal) {
82236
+ delete rawState.variables[loc.name];
82237
+ }
82506
82238
  }
82507
82239
  }
82508
82240
  if (fnCall.steps.length > 0) {
82509
82241
  this.execSyncLoopSteps(fnCall.steps, rawState, io, monitor, touched, mode, onUpdate);
82510
82242
  } else {
82511
82243
  rawState.status = 0;
82512
- onUpdate({ lastCmd: step.cmd, lastArg: fnArgs.length > 0 ? fnArgs[fnArgs.length - 1] : fnCall.name });
82513
82244
  }
82245
+ rawState.lastArgument = fnArgs.at(-1) ?? fnCall.name;
82246
+ onUpdate({ lastCmd: step.cmd, lastArg: rawState.lastArgument });
82514
82247
  } finally {
82515
- for (let i = fnCall.locals.length - 1; i >= 0; i--) {
82248
+ for (let i = savedLocals.length - 1; i >= 0; i--) {
82516
82249
  const saved = savedLocals[i];
82517
82250
  if (saved.val !== void 0) {
82518
82251
  rawState.variables[saved.name] = saved.val;
@@ -85387,6 +85120,7 @@ ${s1}
85387
85120
  throw checkpointFailure;
85388
85121
  }
85389
85122
  if (hasThrown) throw thrownError;
85123
+ state.lastArgument = pendingResume?.lastArgument ?? args.at(-1) ?? name2;
85390
85124
  return exitStatus;
85391
85125
  } finally {
85392
85126
  await scope.close();
@@ -85885,6 +85619,7 @@ ${s1}
85885
85619
  throw checkpointFailure;
85886
85620
  }
85887
85621
  if (outcome.kind === "throw") throw outcome.reason;
85622
+ state.lastArgument = context3.args.at(-1) ?? context3.command;
85888
85623
  return outcome.value;
85889
85624
  }
85890
85625
  if (selectedKind === "builtin" && !(state.externalInvocation && this.commands.has(context3.command))) {
@@ -90447,6 +90182,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
90447
90182
  }
90448
90183
  expandSyncTrCharArray(spec) {
90449
90184
  if (spec.length === 0) return void 0;
90185
+ for (let i = 0; i < spec.length; i++) if (spec.charCodeAt(i) >= 128) return void 0;
90450
90186
  if (spec.includes("\\") && spec.includes("-")) return void 0;
90451
90187
  const posixClasses = {
90452
90188
  "[:lower:]": "abcdefghijklmnopqrstuvwxyz",
@@ -90872,9 +90608,9 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
90872
90608
  for (const el of item) {
90873
90609
  if (!el || typeof el !== "object" || Array.isArray(el)) return void 0;
90874
90610
  const rec = el;
90875
- const k = rec.key ?? rec.name ?? rec.k;
90611
+ const k = [rec.key, rec.Key, rec.name, rec.Name].find((value2) => value2 !== void 0 && value2 !== null && value2 !== false);
90876
90612
  if (typeof k !== "string") return void 0;
90877
- obj[k] = Object.hasOwn(rec, "value") ? rec.value : Object.hasOwn(rec, "v") ? rec.v : null;
90613
+ obj[k] = Object.hasOwn(rec, "value") ? rec.value : Object.hasOwn(rec, "Value") ? rec.Value : null;
90878
90614
  }
90879
90615
  return [obj];
90880
90616
  }
@@ -90903,7 +90639,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
90903
90639
  if (!Array.isArray(item) || !item.every((x) => typeof x === "string" || typeof x === "number" || typeof x === "boolean" || x === null)) return void 0;
90904
90640
  return [item.map((x) => x === null ? "" : String(x)).join(arg)];
90905
90641
  }
90906
- if (fn === "split") return typeof item === "string" ? [item.split(arg)] : void 0;
90642
+ if (fn === "split") return typeof item === "string" ? [arg === "" ? Array.from(item) : item.split(arg)] : void 0;
90907
90643
  if (fn === "ltrimstr") return typeof item === "string" ? [item.startsWith(arg) ? item.slice(arg.length) : item] : void 0;
90908
90644
  if (fn === "rtrimstr") return typeof item === "string" ? [arg.length > 0 && item.endsWith(arg) ? item.slice(0, -arg.length) : item] : void 0;
90909
90645
  if (fn === "startswith") return typeof item === "string" ? [item.startsWith(arg)] : void 0;
@@ -91108,9 +90844,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
91108
90844
  break;
91109
90845
  }
91110
90846
  if (!a.startsWith("-") || a === "-") {
91111
- operands.push(a);
91112
- idx++;
91113
- continue;
90847
+ operands.push(...args.slice(idx));
90848
+ break;
91114
90849
  }
91115
90850
  if (a === "-a" || a === "--multiple") {
91116
90851
  multiple = true;
@@ -91431,7 +91166,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
91431
91166
  }
91432
91167
  if (st.kind === "=") {
91433
91168
  out.push(String(idx1));
91434
- lastInputIndex = i;
91169
+ lastInputIndex = -1;
91435
91170
  continue;
91436
91171
  }
91437
91172
  if (st.kind === "q") {
@@ -91468,7 +91203,10 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
91468
91203
  }
91469
91204
  return replacement;
91470
91205
  });
91471
- if (matchedOnce && st.printOnMatch) out.push(l);
91206
+ if (matchedOnce && st.printOnMatch) {
91207
+ out.push(l);
91208
+ lastInputIndex = i;
91209
+ }
91472
91210
  }
91473
91211
  if (quitNow) {
91474
91212
  break;
@@ -92401,14 +92139,16 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
92401
92139
  endField = km[2] !== void 0 ? Number(km[2]) : void 0;
92402
92140
  if (endField !== void 0 && endField < startField) return void 0;
92403
92141
  const kf = km[3] ?? "";
92404
- if (kf.includes("n")) keyNum = true;
92405
- if (kf.includes("h")) keyHuman = true;
92406
- if (kf.includes("M")) keyMonth = true;
92407
- if (kf.includes("d")) keyDict = true;
92408
- if (kf.includes("r")) keyRev = true;
92409
- if (kf.includes("f")) keyFold = true;
92410
- if (kf.includes("b")) keyBlanks = true;
92411
- if (kf.includes("V")) keyVer = true;
92142
+ if (kf.length > 0) {
92143
+ keyNum = kf.includes("n");
92144
+ keyHuman = kf.includes("h");
92145
+ keyMonth = kf.includes("M");
92146
+ keyDict = kf.includes("d");
92147
+ keyRev = kf.includes("r");
92148
+ keyFold = kf.includes("f");
92149
+ keyBlanks = kf.includes("b");
92150
+ keyVer = kf.includes("V");
92151
+ }
92412
92152
  }
92413
92153
  const extractKey = (l) => {
92414
92154
  let raw = keySpec === void 0 ? l : (() => {
@@ -92432,7 +92172,13 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
92432
92172
  })();
92433
92173
  if (keyBlanks) raw = raw.replace(/^[ \t]+/, "");
92434
92174
  if (keyDict) raw = raw.replace(/[^a-zA-Z0-9 \t]+/g, "");
92435
- return keyFold ? raw.toUpperCase() : raw;
92175
+ if (!keyFold) return raw;
92176
+ let folded = "";
92177
+ for (let i = 0; i < raw.length; i++) {
92178
+ const code = raw.charCodeAt(i);
92179
+ folded += code >= 97 && code <= 122 ? String.fromCharCode(code - 32) : raw[i];
92180
+ }
92181
+ return folded;
92436
92182
  };
92437
92183
  const parseNum = (s) => {
92438
92184
  const m = /^[ \t]*(-?(?:\d+(?:\.\d*)?|\.\d+))/.exec(s);
@@ -92460,6 +92206,23 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
92460
92206
  const idx = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"].indexOf(m[1].toUpperCase());
92461
92207
  return idx === -1 ? 0 : idx + 1;
92462
92208
  };
92209
+ const encoded2 = /* @__PURE__ */ new Map();
92210
+ const bytesOf = (line) => {
92211
+ let bytes2 = encoded2.get(line);
92212
+ if (bytes2 === void 0) {
92213
+ bytes2 = fastSharedTextEncoder.encode(line);
92214
+ encoded2.set(line, bytes2);
92215
+ }
92216
+ return bytes2;
92217
+ };
92218
+ const compareBytes2 = (left, right) => {
92219
+ const a = bytesOf(left);
92220
+ const b = bytesOf(right);
92221
+ for (let i = 0; i < Math.min(a.length, b.length); i++) {
92222
+ if (a[i] !== b[i]) return a[i] - b[i];
92223
+ }
92224
+ return a.length - b.length;
92225
+ };
92463
92226
  const sorted = [...rawLines].sort((a, b) => {
92464
92227
  const ka = extractKey(a);
92465
92228
  const kb = extractKey(b);
@@ -92478,13 +92241,12 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
92478
92241
  const vc = this.compareSyncVersion(ka, kb);
92479
92242
  if (vc !== 0) return keyRev ? -vc : vc;
92480
92243
  } else if (ka !== kb) {
92481
- return ka < kb ? keyRev ? 1 : -1 : keyRev ? -1 : 1;
92244
+ const comparison2 = compareBytes2(ka, kb);
92245
+ return keyRev ? -comparison2 : comparison2;
92482
92246
  }
92483
92247
  if (uniq || stable) return 0;
92484
- const fa = fold2 ? a.toUpperCase() : a;
92485
- const fb = fold2 ? b.toUpperCase() : b;
92486
- if (fa !== fb) return fa < fb ? rev ? 1 : -1 : rev ? -1 : 1;
92487
- return a < b ? rev ? 1 : -1 : a > b ? rev ? -1 : 1 : 0;
92248
+ const comparison = compareBytes2(a, b);
92249
+ return rev ? -comparison : comparison;
92488
92250
  });
92489
92251
  if (!uniq) return sorted;
92490
92252
  const dedup = [];