@sjawhar/pi-legion-envoy 5.17.0 → 5.17.2

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 (2) hide show
  1. package/dist/legion.js +138 -52
  2. package/package.json +1 -1
package/dist/legion.js CHANGED
@@ -33473,7 +33473,7 @@ import { logger } from "@oh-my-pi/pi-utils";
33473
33473
  // package.json
33474
33474
  var package_default = {
33475
33475
  name: "@sjawhar/pi-legion-envoy",
33476
- version: "5.17.0",
33476
+ version: "5.17.2",
33477
33477
  type: "module",
33478
33478
  omp: {
33479
33479
  extensions: [
@@ -42174,9 +42174,11 @@ function visitParts(parts, st, ctx) {
42174
42174
  visitParts(part.parts, st, ctx);
42175
42175
  break;
42176
42176
  case "CommandExpansion":
42177
- case "ProcessSubstitution":
42178
42177
  walkSubstitution(part.script, part.inner, part.text, st, ctx);
42179
42178
  break;
42179
+ case "ProcessSubstitution":
42180
+ uncertainly(ctx, () => walkSubstitution(part.script, part.inner, part.text, st, ctx));
42181
+ break;
42180
42182
  case "ArithmeticExpansion":
42181
42183
  visitArithmetic(part.expression, st, ctx);
42182
42184
  break;
@@ -42396,10 +42398,47 @@ function merge2(target, branches) {
42396
42398
  if (target.traps.includes(trap))
42397
42399
  continue;
42398
42400
  merged ??= new Map(target.vars);
42399
- lifted.push({ ...trap, vars: handlerVars(trap, branch.vars), merged });
42401
+ lifted.push({ ...trap, vars: handlerVars(trap, branch.vars), merged, uncertainSet: true });
42400
42402
  }
42401
42403
  }
42402
- target.traps = [...target.traps, ...lifted];
42404
+ target.traps = [
42405
+ ...target.traps.map((trap) => branches.every((branch) => branch.traps.includes(trap)) ? trap : { ...trap, uncertainSet: true }),
42406
+ ...lifted
42407
+ ];
42408
+ }
42409
+ function uncertainly(ctx, walk) {
42410
+ ctx.uncertain.depth += 1;
42411
+ try {
42412
+ walk();
42413
+ } finally {
42414
+ ctx.uncertain.depth -= 1;
42415
+ }
42416
+ }
42417
+ function modelWrite(st, ctx, file2, content) {
42418
+ st.files.set(file2, ctx.uncertain.depth > 0 ? UNCERTAIN_WRITE : content);
42419
+ }
42420
+ var UNCERTAIN_WRITE = {
42421
+ why: "the write is inside a branch, a loop body, a handler, or a command this shell does not wait " + "for, so the guard cannot know the shell performed it"
42422
+ };
42423
+ var UNRENDERED_WRITE = {
42424
+ why: "the command writes output the guard cannot render"
42425
+ };
42426
+ var OVERLONG_WRITE = {
42427
+ why: `the command writes more than the ${MAX_SCRIPT_BYTES} bytes the guard reads of a script`
42428
+ };
42429
+ var UNREAD_FILE = {
42430
+ why: "the command appends to a file it has not written, whose contents on disk the guard never reads"
42431
+ };
42432
+ function modelPidFile(st, ctx, file2, pid) {
42433
+ const model = st.pidFiles;
42434
+ const before = model.get(file2);
42435
+ model.delete(file2);
42436
+ if (ctx.uncertain.depth === 0) {
42437
+ if (pid !== undefined)
42438
+ model.set(file2, pid);
42439
+ } else if (pid !== undefined && before !== undefined) {
42440
+ model.set(file2, [unknown2("a pid a branch or loop body wrote to this file", true)]);
42441
+ }
42403
42442
  }
42404
42443
  function handlerVars(trap, vars) {
42405
42444
  const { vars: branch, merged } = trap;
@@ -42444,11 +42483,17 @@ function subshell(st, patch) {
42444
42483
  function runSetTraps(st, ctx) {
42445
42484
  for (const trap of st.traps) {
42446
42485
  const vars = new Map([...handlerVars(trap, st.vars), ...trap.pids ?? []]);
42447
- try {
42448
- runText(trap.text, "the EXIT trap", subshell(st, { source: trap.file, vars }), ctx, trap.site);
42449
- } catch (error48) {
42450
- locateRefusal(error48, trap.file);
42451
- }
42486
+ const run = () => {
42487
+ try {
42488
+ runText(trap.text, "the EXIT trap", subshell(st, { source: trap.file, vars }), ctx, trap.site);
42489
+ } catch (error48) {
42490
+ locateRefusal(error48, trap.file);
42491
+ }
42492
+ };
42493
+ if (trap.signals.includes("EXIT") && trap.uncertainSet !== true)
42494
+ run();
42495
+ else
42496
+ uncertainly(ctx, run);
42452
42497
  }
42453
42498
  }
42454
42499
  function walkList(statements, st, ctx) {
@@ -42459,8 +42504,10 @@ var MAX_DECIDED_PASSES = 64;
42459
42504
  function walkLoopAnyPasses(node, st, ctx) {
42460
42505
  const before = st.output;
42461
42506
  const body = clone2(st);
42462
- walkList(node.clause.commands, body, ctx);
42463
- walkList(node.body.commands, body, ctx);
42507
+ uncertainly(ctx, () => {
42508
+ walkList(node.clause.commands, body, ctx);
42509
+ walkList(node.body.commands, body, ctx);
42510
+ });
42464
42511
  merge2(st, [clone2(st), body]);
42465
42512
  if (outputChanged(before, body.output))
42466
42513
  st.output = undefined;
@@ -42564,8 +42611,10 @@ function walkNode(node, st, ctx, pipeIn) {
42564
42611
  if (node.background) {
42565
42612
  const before = st.output;
42566
42613
  const child = subshell(st);
42567
- walkNode(node.command, child, ctx, pipeIn);
42568
- runSetTraps(child, ctx);
42614
+ uncertainly(ctx, () => {
42615
+ walkNode(node.command, child, ctx, pipeIn);
42616
+ runSetTraps(child, ctx);
42617
+ });
42569
42618
  if (outputChanged(before, child.output))
42570
42619
  st.output = undefined;
42571
42620
  st.backgroundStarted = true;
@@ -42574,7 +42623,7 @@ function walkNode(node, st, ctx, pipeIn) {
42574
42623
  if (node.command.type === "BraceGroup") {
42575
42624
  const written = groupOutputFile(node, st, ctx);
42576
42625
  if (written !== undefined) {
42577
- st.files.set(written, walkRenderingGroup(node.command, st, ctx));
42626
+ modelWrite(st, ctx, written, walkRenderingGroup(node.command, st, ctx) ?? UNRENDERED_WRITE);
42578
42627
  return;
42579
42628
  }
42580
42629
  }
@@ -42592,20 +42641,38 @@ function walkNode(node, st, ctx, pipeIn) {
42592
42641
  }
42593
42642
  const before = st.output;
42594
42643
  const parts = [];
42595
- for (const [index, command] of node.commands.entries()) {
42596
- const part = subshell(st);
42597
- walkNode(command, part, ctx, index > 0);
42598
- runSetTraps(part, ctx);
42599
- parts.push(part);
42600
- }
42644
+ uncertainly(ctx, () => {
42645
+ for (const [index, command] of node.commands.entries()) {
42646
+ const part = subshell(st);
42647
+ walkNode(command, part, ctx, index > 0);
42648
+ runSetTraps(part, ctx);
42649
+ parts.push(part);
42650
+ }
42651
+ });
42601
42652
  if (parts.some((part) => outputChanged(before, part.output)))
42602
42653
  st.output = undefined;
42603
42654
  return;
42604
42655
  }
42605
- case "AndOr":
42606
- for (const command of node.commands)
42607
- walkNode(command, st, ctx, pipeIn);
42656
+ case "AndOr": {
42657
+ const [first, ...rest] = node.commands;
42658
+ if (first !== undefined)
42659
+ walkNode(first, st, ctx, pipeIn);
42660
+ if (rest.length === 0)
42661
+ return;
42662
+ const before = st.output;
42663
+ const branches = [clone2(st)];
42664
+ const running = clone2(st);
42665
+ uncertainly(ctx, () => {
42666
+ for (const command of rest) {
42667
+ walkNode(command, running, ctx, pipeIn);
42668
+ branches.push(clone2(running));
42669
+ }
42670
+ });
42671
+ merge2(st, branches);
42672
+ if (branches.some((branch) => outputChanged(before, branch.output)))
42673
+ st.output = undefined;
42608
42674
  return;
42675
+ }
42609
42676
  case "CompoundList":
42610
42677
  walkList(node.commands, st, ctx);
42611
42678
  return;
@@ -42626,10 +42693,12 @@ function walkNode(node, st, ctx, pipeIn) {
42626
42693
  walkList(node.clause.commands, st, ctx);
42627
42694
  const clauseOutput = st.output;
42628
42695
  const then = clone2(st);
42629
- walkList(node.then.commands, then, ctx);
42630
42696
  const otherwise = clone2(st);
42631
- if (node.else !== undefined)
42632
- walkNode(node.else, otherwise, ctx, pipeIn);
42697
+ uncertainly(ctx, () => {
42698
+ walkList(node.then.commands, then, ctx);
42699
+ if (node.else !== undefined)
42700
+ walkNode(node.else, otherwise, ctx, pipeIn);
42701
+ });
42633
42702
  merge2(st, [then, otherwise]);
42634
42703
  if (outputChanged(before, clauseOutput) || outputChanged(clauseOutput, then.output) || outputChanged(clauseOutput, otherwise.output)) {
42635
42704
  st.output = undefined;
@@ -42649,7 +42718,7 @@ function walkNode(node, st, ctx, pipeIn) {
42649
42718
  for (const value of known) {
42650
42719
  const body = clone2(st);
42651
42720
  assignScalar(body, name, [literal2(value)]);
42652
- walkList(node.body.commands, body, ctx);
42721
+ uncertainly(ctx, () => walkList(node.body.commands, body, ctx));
42653
42722
  branches.push(body);
42654
42723
  }
42655
42724
  } else {
@@ -42661,7 +42730,7 @@ function walkNode(node, st, ctx, pipeIn) {
42661
42730
  assignScalar(body, name, signalSafe ? [unknown2(`\`$${name}\`, a loop variable`, true)] : [unknown2(`\`$${name}\`, a loop variable`)]);
42662
42731
  if (node.type === "Select")
42663
42732
  assignScalar(body, "REPLY", [unknown2("`$REPLY`, read from input")]);
42664
- walkList(node.body.commands, body, ctx);
42733
+ uncertainly(ctx, () => walkList(node.body.commands, body, ctx));
42665
42734
  branches.push(body);
42666
42735
  }
42667
42736
  merge2(st, branches);
@@ -42675,7 +42744,7 @@ function walkNode(node, st, ctx, pipeIn) {
42675
42744
  visitArithmetic(node.test, st, ctx);
42676
42745
  visitArithmetic(node.update, st, ctx);
42677
42746
  const body = clone2(st);
42678
- walkList(node.body.commands, body, ctx);
42747
+ uncertainly(ctx, () => walkList(node.body.commands, body, ctx));
42679
42748
  merge2(st, [clone2(st), body]);
42680
42749
  if (outputChanged(before, body.output))
42681
42750
  st.output = undefined;
@@ -42702,7 +42771,7 @@ function walkNode(node, st, ctx, pipeIn) {
42702
42771
  for (const word of item.pattern)
42703
42772
  visitWord(word, st, ctx);
42704
42773
  const body = clone2(st);
42705
- walkList(item.body.commands, body, ctx);
42774
+ uncertainly(ctx, () => walkList(item.body.commands, body, ctx));
42706
42775
  branches.push(body);
42707
42776
  }
42708
42777
  merge2(st, branches);
@@ -42723,8 +42792,10 @@ function walkNode(node, st, ctx, pipeIn) {
42723
42792
  case "Coproc": {
42724
42793
  const before = st.output;
42725
42794
  const child = subshell(st);
42726
- walkNode(node.body, child, ctx, false);
42727
- runSetTraps(child, ctx);
42795
+ uncertainly(ctx, () => {
42796
+ walkNode(node.body, child, ctx, false);
42797
+ runSetTraps(child, ctx);
42798
+ });
42728
42799
  if (outputChanged(before, child.output))
42729
42800
  st.output = undefined;
42730
42801
  checkRedirects(node.redirects, undefined, siteOf(node, st), st, ctx);
@@ -42773,12 +42844,10 @@ function checkRedirects(redirects, command, site, st, ctx) {
42773
42844
  } else if (command?.name === "printf") {
42774
42845
  content = printfText(command.args, MAX_SCRIPT_BYTES, true) ?? null;
42775
42846
  }
42776
- st.pidFiles.delete(file2);
42777
- const before = appends ? st.files.get(file2) : "";
42778
- st.files.set(file2, content === null || before === null ? null : readable(`${before ?? ""}${content}`));
42779
- if (writes && !appends && command?.name === "echo" && command.args.length === 1 && command.args[0]?.exp.length > 0 && command.args[0]?.exp.every((piece) => piece.descendantPid)) {
42780
- st.pidFiles.set(file2, command.args[0].exp);
42781
- }
42847
+ const before = appends ? st.files.get(file2) ?? UNREAD_FILE : "";
42848
+ modelWrite(st, ctx, file2, content === null ? UNRENDERED_WRITE : typeof before !== "string" ? before : readable(`${before}${content}`) ?? OVERLONG_WRITE);
42849
+ const pidWritten = writes && !appends && command?.name === "echo" && command.args.length === 1 && command.args[0]?.exp.length > 0 && command.args[0].exp.every((piece) => piece.descendantPid);
42850
+ modelPidFile(st, ctx, file2, pidWritten ? command?.args[0]?.exp : undefined);
42782
42851
  }
42783
42852
  }
42784
42853
  }
@@ -43222,15 +43291,18 @@ function dispatch(invocation, outer, ctx) {
43222
43291
  runFunction(base, only, rest, outer, ctx);
43223
43292
  return;
43224
43293
  }
43225
- const runs = callee.map((definition) => {
43226
- const run = clone2(outer);
43227
- if (definition !== undefined)
43228
- runFunction(base, definition, rest, run, ctx);
43229
- else {
43230
- run.functions.delete(base);
43231
- dispatch(invocation, run, ctx);
43294
+ const runs = [];
43295
+ uncertainly(ctx, () => {
43296
+ for (const definition of callee) {
43297
+ const run = clone2(outer);
43298
+ if (definition !== undefined)
43299
+ runFunction(base, definition, rest, run, ctx);
43300
+ else {
43301
+ run.functions.delete(base);
43302
+ dispatch(invocation, run, ctx);
43303
+ }
43304
+ runs.push(run);
43232
43305
  }
43233
- return run;
43234
43306
  });
43235
43307
  merge2(outer, runs);
43236
43308
  return;
@@ -43410,11 +43482,24 @@ function dispatch(invocation, outer, ctx) {
43410
43482
  pids.set(name2, [piece]);
43411
43483
  return `\${${name2}}`;
43412
43484
  }).join("");
43413
- outer.traps = [...outer.traps, { text: handlerText, site, signals: handled, file: file2, pids }];
43485
+ outer.traps = [
43486
+ ...outer.traps,
43487
+ {
43488
+ text: handlerText,
43489
+ site,
43490
+ signals: handled,
43491
+ file: file2,
43492
+ pids,
43493
+ uncertainSet: ctx.uncertain.depth > 0
43494
+ }
43495
+ ];
43414
43496
  } else if (text === undefined) {
43415
43497
  throw new Refusal(site.snippet, site.line, `the guard cannot read the handler this \`trap\` sets, \`${handler.text}\` (${handler.exp.find((piece) => piece.kind !== "literal")?.why ?? "a value the guard cannot know"}), so it cannot check what runs when this shell exits; write the handler out, or put it in a function`);
43416
43498
  } else if (!text.startsWith("-")) {
43417
- outer.traps = [...outer.traps, { text, site, signals: handled, file: file2 }];
43499
+ outer.traps = [
43500
+ ...outer.traps,
43501
+ { text, site, signals: handled, file: file2, uncertainSet: ctx.uncertain.depth > 0 }
43502
+ ];
43418
43503
  }
43419
43504
  return;
43420
43505
  }
@@ -43530,7 +43615,7 @@ function dispatch(invocation, outer, ctx) {
43530
43615
  const file2 = path4.resolve(st.cwd, target);
43531
43616
  st.pidFiles.delete(file2);
43532
43617
  const text = heredoc === undefined ? null : heredocText(heredoc);
43533
- st.files.set(file2, append || text === null ? null : readable(text));
43618
+ modelWrite(st, ctx, file2, append ? UNREAD_FILE : text === null ? UNRENDERED_WRITE : readable(text) ?? OVERLONG_WRITE);
43534
43619
  }
43535
43620
  }
43536
43621
  return;
@@ -44195,8 +44280,8 @@ function runFile(file2, positional, st, ctx, site, kind, source = false) {
44195
44280
  let content;
44196
44281
  if (st.files.has(abs)) {
44197
44282
  const written = st.files.get(abs);
44198
- if (written === null || written === undefined) {
44199
- throw new Refusal(site.snippet, site.line, `this command writes ${abs} in a way the guard cannot read before running it (output it cannot render, or more than the ${MAX_SCRIPT_BYTES} bytes it reads of a script); write the script with the write tool first`);
44283
+ if (written === undefined || typeof written !== "string") {
44284
+ throw new Refusal(site.snippet, site.line, `this command may write ${abs} in a way the guard cannot read before running it (${written?.why ?? "the guard cannot say what it holds"}); write the script with the write tool first`);
44200
44285
  }
44201
44286
  content = written;
44202
44287
  } else {
@@ -44389,7 +44474,8 @@ function createPaneGuard(options) {
44389
44474
  env,
44390
44475
  ompPid: options.ompPid,
44391
44476
  parentOf: options.parentOf ?? procParent,
44392
- steps: { count: 0 }
44477
+ steps: { count: 0 },
44478
+ uncertain: { depth: 0 }
44393
44479
  });
44394
44480
  const initial = (cwd, source) => ({
44395
44481
  vars: new Map,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "5.17.0",
3
+ "version": "5.17.2",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [