@sjawhar/pi-legion-envoy 5.17.1 → 5.17.3
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.
- package/dist/legion.js +371 -107
- 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.
|
|
33476
|
+
version: "5.17.3",
|
|
33477
33477
|
type: "module",
|
|
33478
33478
|
omp: {
|
|
33479
33479
|
extensions: [
|
|
@@ -41507,6 +41507,51 @@ var FILE_COMMANDS = new Set([
|
|
|
41507
41507
|
"chgrp"
|
|
41508
41508
|
]);
|
|
41509
41509
|
var SIGNAL_COMMANDS = new Set(["kill", "pkill", "killall", "killall5"]);
|
|
41510
|
+
var FIND_VALUED_PREDICATES = new Set([
|
|
41511
|
+
"-amin",
|
|
41512
|
+
"-anewer",
|
|
41513
|
+
"-atime",
|
|
41514
|
+
"-cmin",
|
|
41515
|
+
"-cnewer",
|
|
41516
|
+
"-ctime",
|
|
41517
|
+
"-fls",
|
|
41518
|
+
"-fprint",
|
|
41519
|
+
"-fprint0",
|
|
41520
|
+
"-fprintf",
|
|
41521
|
+
"-fstype",
|
|
41522
|
+
"-gid",
|
|
41523
|
+
"-group",
|
|
41524
|
+
"-ilname",
|
|
41525
|
+
"-iname",
|
|
41526
|
+
"-inum",
|
|
41527
|
+
"-ipath",
|
|
41528
|
+
"-iregex",
|
|
41529
|
+
"-iwholename",
|
|
41530
|
+
"-links",
|
|
41531
|
+
"-lname",
|
|
41532
|
+
"-maxdepth",
|
|
41533
|
+
"-mindepth",
|
|
41534
|
+
"-mmin",
|
|
41535
|
+
"-mtime",
|
|
41536
|
+
"-name",
|
|
41537
|
+
"-newer",
|
|
41538
|
+
"-newerat",
|
|
41539
|
+
"-newerct",
|
|
41540
|
+
"-newermt",
|
|
41541
|
+
"-path",
|
|
41542
|
+
"-perm",
|
|
41543
|
+
"-printf",
|
|
41544
|
+
"-regex",
|
|
41545
|
+
"-regextype",
|
|
41546
|
+
"-samefile",
|
|
41547
|
+
"-size",
|
|
41548
|
+
"-type",
|
|
41549
|
+
"-uid",
|
|
41550
|
+
"-used",
|
|
41551
|
+
"-user",
|
|
41552
|
+
"-wholename",
|
|
41553
|
+
"-xtype"
|
|
41554
|
+
]);
|
|
41510
41555
|
var FUNCTION_OUTPUT_SILENT = {
|
|
41511
41556
|
":": true,
|
|
41512
41557
|
break: true,
|
|
@@ -42166,6 +42211,43 @@ function literalText(exp) {
|
|
|
42166
42211
|
return;
|
|
42167
42212
|
return exp.map((piece) => piece.text).join("");
|
|
42168
42213
|
}
|
|
42214
|
+
function readableWord(arg) {
|
|
42215
|
+
const whole = literalText(arg.exp);
|
|
42216
|
+
if (whole !== undefined)
|
|
42217
|
+
return { text: whole, whole: true };
|
|
42218
|
+
let text = "";
|
|
42219
|
+
for (const piece of arg.exp) {
|
|
42220
|
+
if (piece.kind !== "literal")
|
|
42221
|
+
break;
|
|
42222
|
+
text += piece.text;
|
|
42223
|
+
}
|
|
42224
|
+
return { text, whole: false };
|
|
42225
|
+
}
|
|
42226
|
+
function mayBeOption(arg, matches) {
|
|
42227
|
+
const { text, whole } = readableWord(arg);
|
|
42228
|
+
if (whole)
|
|
42229
|
+
return matches(text);
|
|
42230
|
+
return text === "" || /^--?[a-zA-Z-]*$/.test(text);
|
|
42231
|
+
}
|
|
42232
|
+
function valueInWord(arg, count) {
|
|
42233
|
+
const pieces = [];
|
|
42234
|
+
let dropped = 0;
|
|
42235
|
+
for (const piece of arg.exp) {
|
|
42236
|
+
if (dropped >= count) {
|
|
42237
|
+
pieces.push(piece);
|
|
42238
|
+
continue;
|
|
42239
|
+
}
|
|
42240
|
+
if (piece.kind !== "literal")
|
|
42241
|
+
return;
|
|
42242
|
+
if (piece.text.length + dropped <= count) {
|
|
42243
|
+
dropped += piece.text.length;
|
|
42244
|
+
continue;
|
|
42245
|
+
}
|
|
42246
|
+
pieces.push({ ...piece, text: piece.text.slice(count - dropped) });
|
|
42247
|
+
dropped = count;
|
|
42248
|
+
}
|
|
42249
|
+
return dropped < count || pieces.length === 0 ? undefined : pieces;
|
|
42250
|
+
}
|
|
42169
42251
|
function visitParts(parts, st, ctx) {
|
|
42170
42252
|
for (const part of parts ?? []) {
|
|
42171
42253
|
switch (part.type) {
|
|
@@ -42174,9 +42256,11 @@ function visitParts(parts, st, ctx) {
|
|
|
42174
42256
|
visitParts(part.parts, st, ctx);
|
|
42175
42257
|
break;
|
|
42176
42258
|
case "CommandExpansion":
|
|
42177
|
-
case "ProcessSubstitution":
|
|
42178
42259
|
walkSubstitution(part.script, part.inner, part.text, st, ctx);
|
|
42179
42260
|
break;
|
|
42261
|
+
case "ProcessSubstitution":
|
|
42262
|
+
uncertainly(ctx, () => walkSubstitution(part.script, part.inner, part.text, st, ctx));
|
|
42263
|
+
break;
|
|
42180
42264
|
case "ArithmeticExpansion":
|
|
42181
42265
|
visitArithmetic(part.expression, st, ctx);
|
|
42182
42266
|
break;
|
|
@@ -42396,10 +42480,47 @@ function merge2(target, branches) {
|
|
|
42396
42480
|
if (target.traps.includes(trap))
|
|
42397
42481
|
continue;
|
|
42398
42482
|
merged ??= new Map(target.vars);
|
|
42399
|
-
lifted.push({ ...trap, vars: handlerVars(trap, branch.vars), merged });
|
|
42483
|
+
lifted.push({ ...trap, vars: handlerVars(trap, branch.vars), merged, uncertainSet: true });
|
|
42400
42484
|
}
|
|
42401
42485
|
}
|
|
42402
|
-
target.traps = [
|
|
42486
|
+
target.traps = [
|
|
42487
|
+
...target.traps.map((trap) => branches.every((branch) => branch.traps.includes(trap)) ? trap : { ...trap, uncertainSet: true }),
|
|
42488
|
+
...lifted
|
|
42489
|
+
];
|
|
42490
|
+
}
|
|
42491
|
+
function uncertainly(ctx, walk) {
|
|
42492
|
+
ctx.uncertain.depth += 1;
|
|
42493
|
+
try {
|
|
42494
|
+
walk();
|
|
42495
|
+
} finally {
|
|
42496
|
+
ctx.uncertain.depth -= 1;
|
|
42497
|
+
}
|
|
42498
|
+
}
|
|
42499
|
+
function modelWrite(st, ctx, file2, content) {
|
|
42500
|
+
st.files.set(file2, ctx.uncertain.depth > 0 ? UNCERTAIN_WRITE : content);
|
|
42501
|
+
}
|
|
42502
|
+
var UNCERTAIN_WRITE = {
|
|
42503
|
+
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"
|
|
42504
|
+
};
|
|
42505
|
+
var UNRENDERED_WRITE = {
|
|
42506
|
+
why: "the command writes output the guard cannot render"
|
|
42507
|
+
};
|
|
42508
|
+
var OVERLONG_WRITE = {
|
|
42509
|
+
why: `the command writes more than the ${MAX_SCRIPT_BYTES} bytes the guard reads of a script`
|
|
42510
|
+
};
|
|
42511
|
+
var UNREAD_FILE = {
|
|
42512
|
+
why: "the command appends to a file it has not written, whose contents on disk the guard never reads"
|
|
42513
|
+
};
|
|
42514
|
+
function modelPidFile(st, ctx, file2, pid) {
|
|
42515
|
+
const model = st.pidFiles;
|
|
42516
|
+
const before = model.get(file2);
|
|
42517
|
+
model.delete(file2);
|
|
42518
|
+
if (ctx.uncertain.depth === 0) {
|
|
42519
|
+
if (pid !== undefined)
|
|
42520
|
+
model.set(file2, pid);
|
|
42521
|
+
} else if (pid !== undefined && before !== undefined) {
|
|
42522
|
+
model.set(file2, [unknown2("a pid a branch or loop body wrote to this file", true)]);
|
|
42523
|
+
}
|
|
42403
42524
|
}
|
|
42404
42525
|
function handlerVars(trap, vars) {
|
|
42405
42526
|
const { vars: branch, merged } = trap;
|
|
@@ -42444,11 +42565,17 @@ function subshell(st, patch) {
|
|
|
42444
42565
|
function runSetTraps(st, ctx) {
|
|
42445
42566
|
for (const trap of st.traps) {
|
|
42446
42567
|
const vars = new Map([...handlerVars(trap, st.vars), ...trap.pids ?? []]);
|
|
42447
|
-
|
|
42448
|
-
|
|
42449
|
-
|
|
42450
|
-
|
|
42451
|
-
|
|
42568
|
+
const run = () => {
|
|
42569
|
+
try {
|
|
42570
|
+
runText(trap.text, "the EXIT trap", subshell(st, { source: trap.file, vars }), ctx, trap.site);
|
|
42571
|
+
} catch (error48) {
|
|
42572
|
+
locateRefusal(error48, trap.file);
|
|
42573
|
+
}
|
|
42574
|
+
};
|
|
42575
|
+
if (trap.signals.includes("EXIT") && trap.uncertainSet !== true)
|
|
42576
|
+
run();
|
|
42577
|
+
else
|
|
42578
|
+
uncertainly(ctx, run);
|
|
42452
42579
|
}
|
|
42453
42580
|
}
|
|
42454
42581
|
function walkList(statements, st, ctx) {
|
|
@@ -42459,8 +42586,10 @@ var MAX_DECIDED_PASSES = 64;
|
|
|
42459
42586
|
function walkLoopAnyPasses(node, st, ctx) {
|
|
42460
42587
|
const before = st.output;
|
|
42461
42588
|
const body = clone2(st);
|
|
42462
|
-
|
|
42463
|
-
|
|
42589
|
+
uncertainly(ctx, () => {
|
|
42590
|
+
walkList(node.clause.commands, body, ctx);
|
|
42591
|
+
walkList(node.body.commands, body, ctx);
|
|
42592
|
+
});
|
|
42464
42593
|
merge2(st, [clone2(st), body]);
|
|
42465
42594
|
if (outputChanged(before, body.output))
|
|
42466
42595
|
st.output = undefined;
|
|
@@ -42564,8 +42693,10 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42564
42693
|
if (node.background) {
|
|
42565
42694
|
const before = st.output;
|
|
42566
42695
|
const child = subshell(st);
|
|
42567
|
-
|
|
42568
|
-
|
|
42696
|
+
uncertainly(ctx, () => {
|
|
42697
|
+
walkNode(node.command, child, ctx, pipeIn);
|
|
42698
|
+
runSetTraps(child, ctx);
|
|
42699
|
+
});
|
|
42569
42700
|
if (outputChanged(before, child.output))
|
|
42570
42701
|
st.output = undefined;
|
|
42571
42702
|
st.backgroundStarted = true;
|
|
@@ -42574,7 +42705,7 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42574
42705
|
if (node.command.type === "BraceGroup") {
|
|
42575
42706
|
const written = groupOutputFile(node, st, ctx);
|
|
42576
42707
|
if (written !== undefined) {
|
|
42577
|
-
st
|
|
42708
|
+
modelWrite(st, ctx, written, walkRenderingGroup(node.command, st, ctx) ?? UNRENDERED_WRITE);
|
|
42578
42709
|
return;
|
|
42579
42710
|
}
|
|
42580
42711
|
}
|
|
@@ -42592,20 +42723,38 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42592
42723
|
}
|
|
42593
42724
|
const before = st.output;
|
|
42594
42725
|
const parts = [];
|
|
42595
|
-
|
|
42596
|
-
const
|
|
42597
|
-
|
|
42598
|
-
|
|
42599
|
-
|
|
42600
|
-
|
|
42726
|
+
uncertainly(ctx, () => {
|
|
42727
|
+
for (const [index, command] of node.commands.entries()) {
|
|
42728
|
+
const part = subshell(st);
|
|
42729
|
+
walkNode(command, part, ctx, index > 0);
|
|
42730
|
+
runSetTraps(part, ctx);
|
|
42731
|
+
parts.push(part);
|
|
42732
|
+
}
|
|
42733
|
+
});
|
|
42601
42734
|
if (parts.some((part) => outputChanged(before, part.output)))
|
|
42602
42735
|
st.output = undefined;
|
|
42603
42736
|
return;
|
|
42604
42737
|
}
|
|
42605
|
-
case "AndOr":
|
|
42606
|
-
|
|
42607
|
-
|
|
42738
|
+
case "AndOr": {
|
|
42739
|
+
const [first, ...rest] = node.commands;
|
|
42740
|
+
if (first !== undefined)
|
|
42741
|
+
walkNode(first, st, ctx, pipeIn);
|
|
42742
|
+
if (rest.length === 0)
|
|
42743
|
+
return;
|
|
42744
|
+
const before = st.output;
|
|
42745
|
+
const branches = [clone2(st)];
|
|
42746
|
+
const running = clone2(st);
|
|
42747
|
+
uncertainly(ctx, () => {
|
|
42748
|
+
for (const command of rest) {
|
|
42749
|
+
walkNode(command, running, ctx, pipeIn);
|
|
42750
|
+
branches.push(clone2(running));
|
|
42751
|
+
}
|
|
42752
|
+
});
|
|
42753
|
+
merge2(st, branches);
|
|
42754
|
+
if (branches.some((branch) => outputChanged(before, branch.output)))
|
|
42755
|
+
st.output = undefined;
|
|
42608
42756
|
return;
|
|
42757
|
+
}
|
|
42609
42758
|
case "CompoundList":
|
|
42610
42759
|
walkList(node.commands, st, ctx);
|
|
42611
42760
|
return;
|
|
@@ -42626,10 +42775,12 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42626
42775
|
walkList(node.clause.commands, st, ctx);
|
|
42627
42776
|
const clauseOutput = st.output;
|
|
42628
42777
|
const then = clone2(st);
|
|
42629
|
-
walkList(node.then.commands, then, ctx);
|
|
42630
42778
|
const otherwise = clone2(st);
|
|
42631
|
-
|
|
42632
|
-
|
|
42779
|
+
uncertainly(ctx, () => {
|
|
42780
|
+
walkList(node.then.commands, then, ctx);
|
|
42781
|
+
if (node.else !== undefined)
|
|
42782
|
+
walkNode(node.else, otherwise, ctx, pipeIn);
|
|
42783
|
+
});
|
|
42633
42784
|
merge2(st, [then, otherwise]);
|
|
42634
42785
|
if (outputChanged(before, clauseOutput) || outputChanged(clauseOutput, then.output) || outputChanged(clauseOutput, otherwise.output)) {
|
|
42635
42786
|
st.output = undefined;
|
|
@@ -42649,7 +42800,7 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42649
42800
|
for (const value of known) {
|
|
42650
42801
|
const body = clone2(st);
|
|
42651
42802
|
assignScalar(body, name, [literal2(value)]);
|
|
42652
|
-
walkList(node.body.commands, body, ctx);
|
|
42803
|
+
uncertainly(ctx, () => walkList(node.body.commands, body, ctx));
|
|
42653
42804
|
branches.push(body);
|
|
42654
42805
|
}
|
|
42655
42806
|
} else {
|
|
@@ -42661,7 +42812,7 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42661
42812
|
assignScalar(body, name, signalSafe ? [unknown2(`\`$${name}\`, a loop variable`, true)] : [unknown2(`\`$${name}\`, a loop variable`)]);
|
|
42662
42813
|
if (node.type === "Select")
|
|
42663
42814
|
assignScalar(body, "REPLY", [unknown2("`$REPLY`, read from input")]);
|
|
42664
|
-
walkList(node.body.commands, body, ctx);
|
|
42815
|
+
uncertainly(ctx, () => walkList(node.body.commands, body, ctx));
|
|
42665
42816
|
branches.push(body);
|
|
42666
42817
|
}
|
|
42667
42818
|
merge2(st, branches);
|
|
@@ -42675,7 +42826,7 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42675
42826
|
visitArithmetic(node.test, st, ctx);
|
|
42676
42827
|
visitArithmetic(node.update, st, ctx);
|
|
42677
42828
|
const body = clone2(st);
|
|
42678
|
-
walkList(node.body.commands, body, ctx);
|
|
42829
|
+
uncertainly(ctx, () => walkList(node.body.commands, body, ctx));
|
|
42679
42830
|
merge2(st, [clone2(st), body]);
|
|
42680
42831
|
if (outputChanged(before, body.output))
|
|
42681
42832
|
st.output = undefined;
|
|
@@ -42702,7 +42853,7 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42702
42853
|
for (const word of item.pattern)
|
|
42703
42854
|
visitWord(word, st, ctx);
|
|
42704
42855
|
const body = clone2(st);
|
|
42705
|
-
walkList(item.body.commands, body, ctx);
|
|
42856
|
+
uncertainly(ctx, () => walkList(item.body.commands, body, ctx));
|
|
42706
42857
|
branches.push(body);
|
|
42707
42858
|
}
|
|
42708
42859
|
merge2(st, branches);
|
|
@@ -42723,8 +42874,10 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42723
42874
|
case "Coproc": {
|
|
42724
42875
|
const before = st.output;
|
|
42725
42876
|
const child = subshell(st);
|
|
42726
|
-
|
|
42727
|
-
|
|
42877
|
+
uncertainly(ctx, () => {
|
|
42878
|
+
walkNode(node.body, child, ctx, false);
|
|
42879
|
+
runSetTraps(child, ctx);
|
|
42880
|
+
});
|
|
42728
42881
|
if (outputChanged(before, child.output))
|
|
42729
42882
|
st.output = undefined;
|
|
42730
42883
|
checkRedirects(node.redirects, undefined, siteOf(node, st), st, ctx);
|
|
@@ -42773,12 +42926,10 @@ function checkRedirects(redirects, command, site, st, ctx) {
|
|
|
42773
42926
|
} else if (command?.name === "printf") {
|
|
42774
42927
|
content = printfText(command.args, MAX_SCRIPT_BYTES, true) ?? null;
|
|
42775
42928
|
}
|
|
42776
|
-
st.
|
|
42777
|
-
|
|
42778
|
-
|
|
42779
|
-
|
|
42780
|
-
st.pidFiles.set(file2, command.args[0].exp);
|
|
42781
|
-
}
|
|
42929
|
+
const before = appends ? st.files.get(file2) ?? UNREAD_FILE : "";
|
|
42930
|
+
modelWrite(st, ctx, file2, content === null ? UNRENDERED_WRITE : typeof before !== "string" ? before : readable(`${before}${content}`) ?? OVERLONG_WRITE);
|
|
42931
|
+
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);
|
|
42932
|
+
modelPidFile(st, ctx, file2, pidWritten ? command?.args[0]?.exp : undefined);
|
|
42782
42933
|
}
|
|
42783
42934
|
}
|
|
42784
42935
|
}
|
|
@@ -43018,6 +43169,7 @@ function operands(list, valued, longValued = []) {
|
|
|
43018
43169
|
return { options, operands: found };
|
|
43019
43170
|
}
|
|
43020
43171
|
function unwrap2(argv, st, ctx, site) {
|
|
43172
|
+
const alts = [];
|
|
43021
43173
|
let list = argv;
|
|
43022
43174
|
let state = st;
|
|
43023
43175
|
for (let guard = 0;guard < 16; guard += 1) {
|
|
@@ -43026,13 +43178,19 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43026
43178
|
break;
|
|
43027
43179
|
const base = path4.basename(name);
|
|
43028
43180
|
const rest = list.slice(1);
|
|
43029
|
-
const skip = (valued, longValued = []) => {
|
|
43181
|
+
const skip = (valued, longValued = [], positional = false) => {
|
|
43030
43182
|
let i = 0;
|
|
43031
43183
|
for (;i < rest.length; i += 1) {
|
|
43032
|
-
const
|
|
43184
|
+
const arg = rest[i];
|
|
43185
|
+
const text = literalText(arg.exp);
|
|
43033
43186
|
if (text === "--")
|
|
43034
43187
|
return rest.slice(i + 1);
|
|
43035
|
-
if (text === undefined
|
|
43188
|
+
if (text === undefined) {
|
|
43189
|
+
if (positional || !mayBeOption(arg, (option) => option.startsWith("-")))
|
|
43190
|
+
break;
|
|
43191
|
+
continue;
|
|
43192
|
+
}
|
|
43193
|
+
if (!text.startsWith("-") || text === "-")
|
|
43036
43194
|
break;
|
|
43037
43195
|
if (text.startsWith("--")) {
|
|
43038
43196
|
if (!text.includes("=") && longValued.includes(text))
|
|
@@ -43046,8 +43204,10 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43046
43204
|
}
|
|
43047
43205
|
return rest.slice(i);
|
|
43048
43206
|
};
|
|
43049
|
-
if ((base === "busybox" || base === "toybox") && rest[0] !== undefined)
|
|
43207
|
+
if ((base === "busybox" || base === "toybox") && rest[0] !== undefined && literalText(rest[0].exp) !== undefined) {
|
|
43050
43208
|
list = rest;
|
|
43209
|
+
continue;
|
|
43210
|
+
}
|
|
43051
43211
|
if (base === "sudo" || base === "doas")
|
|
43052
43212
|
list = skip("ughpCDrtUT", ["--user", "--group"]);
|
|
43053
43213
|
else if (base === "nice")
|
|
@@ -43059,15 +43219,23 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43059
43219
|
else if (base === "command") {
|
|
43060
43220
|
const flags = rest.map((arg) => literalText(arg.exp));
|
|
43061
43221
|
if (flags[0] === "-v" || flags[0] === "-V")
|
|
43062
|
-
return { argv: [], st: state };
|
|
43222
|
+
return { argv: [], st: state, alts };
|
|
43063
43223
|
list = skip("");
|
|
43064
43224
|
} else if (base === "stdbuf")
|
|
43065
43225
|
list = skip("ioe", ["--input", "--output", "--error"]);
|
|
43066
43226
|
else if (base === "ionice")
|
|
43067
43227
|
list = skip("cnt", ["--class", "--classdata"]);
|
|
43068
43228
|
else if (base === "timeout") {
|
|
43069
|
-
const
|
|
43070
|
-
list =
|
|
43229
|
+
const stopped = skip("sk", ["--signal", "--kill-after"], true);
|
|
43230
|
+
list = stopped.slice(1);
|
|
43231
|
+
for (let at = rest.length - stopped.length;at < rest.length; at += 1) {
|
|
43232
|
+
if (literalText(rest[at]?.exp) !== undefined)
|
|
43233
|
+
break;
|
|
43234
|
+
alts.push(rest.slice(at + 1));
|
|
43235
|
+
}
|
|
43236
|
+
const read = skip("sk", ["--signal", "--kill-after"]);
|
|
43237
|
+
if (read.length !== stopped.length)
|
|
43238
|
+
alts.push(read.slice(1));
|
|
43071
43239
|
} else if (base === "env") {
|
|
43072
43240
|
let i = 0;
|
|
43073
43241
|
const overlay = new Map;
|
|
@@ -43107,7 +43275,7 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43107
43275
|
overlay.set(arg.exp[0].text.slice(0, arg.exp[0].text.indexOf("=")), [
|
|
43108
43276
|
unknown2("an `env` assignment")
|
|
43109
43277
|
]);
|
|
43110
|
-
} else
|
|
43278
|
+
} else if (text === undefined && mayBeOption(arg, (option) => option.startsWith("-"))) {} else
|
|
43111
43279
|
break;
|
|
43112
43280
|
}
|
|
43113
43281
|
if (i !== -1)
|
|
@@ -43124,7 +43292,7 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43124
43292
|
} else
|
|
43125
43293
|
break;
|
|
43126
43294
|
}
|
|
43127
|
-
return { argv: list, st: state };
|
|
43295
|
+
return { argv: list, st: state, alts };
|
|
43128
43296
|
}
|
|
43129
43297
|
function runFunction(name, definition, args2, outer, ctx) {
|
|
43130
43298
|
if (outer.runningFunctions.has(name))
|
|
@@ -43209,6 +43377,9 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43209
43377
|
const unwrapped = unwrap2(invocation.args, outer, ctx, invocation.site);
|
|
43210
43378
|
const argv = unwrapped.argv;
|
|
43211
43379
|
const st = unwrapped.st;
|
|
43380
|
+
for (const other of unwrapped.alts) {
|
|
43381
|
+
dispatch({ ...invocation, args: other }, clone2(outer), ctx);
|
|
43382
|
+
}
|
|
43212
43383
|
const name = literalText(argv[0]?.exp);
|
|
43213
43384
|
if (name === undefined)
|
|
43214
43385
|
return;
|
|
@@ -43222,15 +43393,18 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43222
43393
|
runFunction(base, only, rest, outer, ctx);
|
|
43223
43394
|
return;
|
|
43224
43395
|
}
|
|
43225
|
-
const runs =
|
|
43226
|
-
|
|
43227
|
-
|
|
43228
|
-
|
|
43229
|
-
|
|
43230
|
-
|
|
43231
|
-
|
|
43396
|
+
const runs = [];
|
|
43397
|
+
uncertainly(ctx, () => {
|
|
43398
|
+
for (const definition of callee) {
|
|
43399
|
+
const run = clone2(outer);
|
|
43400
|
+
if (definition !== undefined)
|
|
43401
|
+
runFunction(base, definition, rest, run, ctx);
|
|
43402
|
+
else {
|
|
43403
|
+
run.functions.delete(base);
|
|
43404
|
+
dispatch(invocation, run, ctx);
|
|
43405
|
+
}
|
|
43406
|
+
runs.push(run);
|
|
43232
43407
|
}
|
|
43233
|
-
return run;
|
|
43234
43408
|
});
|
|
43235
43409
|
merge2(outer, runs);
|
|
43236
43410
|
return;
|
|
@@ -43353,15 +43527,21 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43353
43527
|
const leading = head[0];
|
|
43354
43528
|
const spaced = literalText(head) === "-v";
|
|
43355
43529
|
const joined = !spaced && leading?.kind === "literal" && leading.text.startsWith("-v") && (leading.text.length > 2 || head.length > 1);
|
|
43356
|
-
|
|
43357
|
-
|
|
43530
|
+
const first = rest[0];
|
|
43531
|
+
const mayBeV = !spaced && !joined && first !== undefined && rest[1] !== undefined && mayBeOption(first, (text) => text.startsWith("-v"));
|
|
43532
|
+
if (spaced || joined || mayBeV) {
|
|
43533
|
+
const variable = spaced || mayBeV ? literalText(rest[1]?.exp) : literalText([
|
|
43358
43534
|
{ ...leading, text: leading?.text.slice(2) ?? "" },
|
|
43359
43535
|
...head.slice(1)
|
|
43360
43536
|
]);
|
|
43361
|
-
const printed = rest.slice(spaced ? 2 : 1);
|
|
43537
|
+
const printed = rest.slice(spaced || mayBeV ? 2 : 1);
|
|
43362
43538
|
const [format, value, ...others] = printed;
|
|
43363
43539
|
let assigned;
|
|
43364
|
-
if (
|
|
43540
|
+
if (mayBeV) {
|
|
43541
|
+
assigned = [
|
|
43542
|
+
unknown2(`\`$${variable ?? "?"}\` (printf with an option word the guard cannot read, which may be \`-v\`)`)
|
|
43543
|
+
];
|
|
43544
|
+
} else if (literalText(format?.exp) === "%s" && value !== undefined && others.length === 0) {
|
|
43365
43545
|
assigned = value.exp;
|
|
43366
43546
|
} else {
|
|
43367
43547
|
const text = printfText(printed, MAX_VALUE_LENGTH);
|
|
@@ -43410,11 +43590,24 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43410
43590
|
pids.set(name2, [piece]);
|
|
43411
43591
|
return `\${${name2}}`;
|
|
43412
43592
|
}).join("");
|
|
43413
|
-
outer.traps = [
|
|
43593
|
+
outer.traps = [
|
|
43594
|
+
...outer.traps,
|
|
43595
|
+
{
|
|
43596
|
+
text: handlerText,
|
|
43597
|
+
site,
|
|
43598
|
+
signals: handled,
|
|
43599
|
+
file: file2,
|
|
43600
|
+
pids,
|
|
43601
|
+
uncertainSet: ctx.uncertain.depth > 0
|
|
43602
|
+
}
|
|
43603
|
+
];
|
|
43414
43604
|
} else if (text === undefined) {
|
|
43415
43605
|
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
43606
|
} else if (!text.startsWith("-")) {
|
|
43417
|
-
outer.traps = [
|
|
43607
|
+
outer.traps = [
|
|
43608
|
+
...outer.traps,
|
|
43609
|
+
{ text, site, signals: handled, file: file2, uncertainSet: ctx.uncertain.depth > 0 }
|
|
43610
|
+
];
|
|
43418
43611
|
}
|
|
43419
43612
|
return;
|
|
43420
43613
|
}
|
|
@@ -43479,22 +43672,29 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43479
43672
|
case "tar":
|
|
43480
43673
|
case "unzip": {
|
|
43481
43674
|
const extracting = base === "unzip" || rest.some((arg, index) => {
|
|
43482
|
-
const text =
|
|
43483
|
-
|
|
43675
|
+
const { text, whole } = readableWord(arg);
|
|
43676
|
+
if (!whole && index === 0 && /^[A-Za-z]*$/.test(text))
|
|
43677
|
+
return true;
|
|
43678
|
+
return mayBeOption(arg, (mode) => mode === "--extract" || mode === "--get" || mode.startsWith("-") && !mode.startsWith("--") && mode.includes("x") || index === 0 && /^[A-Za-z]*x[A-Za-z]*$/.test(mode));
|
|
43484
43679
|
});
|
|
43485
43680
|
if (!extracting)
|
|
43486
43681
|
return;
|
|
43487
43682
|
const targetDirectories = [];
|
|
43488
43683
|
const short = base === "tar" ? "-C" : "-d";
|
|
43489
43684
|
const long = base === "tar" ? "--directory" : "--destination";
|
|
43685
|
+
const letter = short.slice(1);
|
|
43490
43686
|
for (const [index, arg] of rest.entries()) {
|
|
43491
|
-
const text =
|
|
43492
|
-
|
|
43687
|
+
const { text, whole } = readableWord(arg);
|
|
43688
|
+
const clusterAt = text.startsWith("-") && !text.startsWith("--") ? text.indexOf(letter, 1) : -1;
|
|
43689
|
+
const carried = text.startsWith(`${long}=`) ? valueInWord(arg, long.length + 1) : clusterAt !== -1 && (!whole || text.length > clusterAt + 1) ? valueInWord(arg, clusterAt + 1) : undefined;
|
|
43690
|
+
if (carried !== undefined) {
|
|
43691
|
+
targetDirectories.push({ text: arg.text, exp: carried });
|
|
43692
|
+
continue;
|
|
43693
|
+
}
|
|
43694
|
+
if (clusterAt !== -1 || mayBeOption(arg, (option) => option === short || option === long)) {
|
|
43493
43695
|
const target = rest[index + 1];
|
|
43494
43696
|
if (target !== undefined)
|
|
43495
43697
|
targetDirectories.push(target);
|
|
43496
|
-
} else if (text?.startsWith(`${long}=`)) {
|
|
43497
|
-
targetDirectories.push({ text: arg.text, exp: [literal2(text.slice(long.length + 1))] });
|
|
43498
43698
|
}
|
|
43499
43699
|
}
|
|
43500
43700
|
checkTargets(base, "extract and overwrite in", targetDirectories, true, st, ctx, site);
|
|
@@ -43530,7 +43730,7 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43530
43730
|
const file2 = path4.resolve(st.cwd, target);
|
|
43531
43731
|
st.pidFiles.delete(file2);
|
|
43532
43732
|
const text = heredoc === undefined ? null : heredocText(heredoc);
|
|
43533
|
-
st
|
|
43733
|
+
modelWrite(st, ctx, file2, append ? UNREAD_FILE : text === null ? UNRENDERED_WRITE : readable(text) ?? OVERLONG_WRITE);
|
|
43534
43734
|
}
|
|
43535
43735
|
}
|
|
43536
43736
|
return;
|
|
@@ -43542,41 +43742,73 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43542
43742
|
case "killall":
|
|
43543
43743
|
case "killall5":
|
|
43544
43744
|
throw new Refusal(site.snippet, site.line, `${base} selects processes by name or pattern, which reaches other agents' processes on a ` + "shared machine; a pane signals only processes it started. Stop a process you started " + 'with the hub tool (`op: "stop"`), or `kill` the pid of a child you started from this pane');
|
|
43545
|
-
case "fuser":
|
|
43546
|
-
|
|
43745
|
+
case "fuser": {
|
|
43746
|
+
const kills = rest.some((arg) => mayBeOption(arg, (text) => /^-[a-zA-Z]*k/.test(text) || text === "--kill"));
|
|
43747
|
+
const readable2 = rest.every((arg) => literalText(arg.exp) !== undefined);
|
|
43748
|
+
const mayBeSeveral = rest.some((arg) => arg.fields === "unknown");
|
|
43749
|
+
if (kills && (readable2 || mayBeSeveral || rest.length > 1)) {
|
|
43547
43750
|
throw new Refusal(site.snippet, site.line, "`fuser -k` kills every process using a file, other agents' included; a pane signals only " + "processes it started");
|
|
43548
43751
|
}
|
|
43549
43752
|
return;
|
|
43753
|
+
}
|
|
43550
43754
|
case "tmux": {
|
|
43551
43755
|
let socket;
|
|
43552
43756
|
let socketIsPath = false;
|
|
43553
|
-
|
|
43554
|
-
|
|
43555
|
-
|
|
43556
|
-
|
|
43557
|
-
|
|
43558
|
-
|
|
43559
|
-
|
|
43560
|
-
|
|
43561
|
-
|
|
43757
|
+
let current = { words: [], speculative: false };
|
|
43758
|
+
const segments = [current];
|
|
43759
|
+
for (const arg of rest) {
|
|
43760
|
+
const word = literalText(arg.exp);
|
|
43761
|
+
const trailing = word !== ";" && word !== undefined && word.endsWith(";");
|
|
43762
|
+
if (trailing)
|
|
43763
|
+
current.words.push({ text: arg.text, exp: [literal2(word.slice(0, -1))] });
|
|
43764
|
+
else if (word !== ";")
|
|
43765
|
+
current.words.push(arg);
|
|
43766
|
+
if (word === ";" || trailing) {
|
|
43767
|
+
current = { words: [], speculative: false };
|
|
43768
|
+
segments.push(current);
|
|
43769
|
+
} else if (word === undefined || arg.fields === "unknown") {
|
|
43770
|
+
current = { words: [], speculative: true };
|
|
43771
|
+
segments.push(current);
|
|
43562
43772
|
}
|
|
43563
43773
|
}
|
|
43564
43774
|
const killCommands = ["kill-server", "kill-session", "kill-window", "kill-pane"];
|
|
43565
43775
|
const respawnCommands = ["respawn-pane", "respawn-window"];
|
|
43566
|
-
const
|
|
43567
|
-
|
|
43568
|
-
if (text === undefined)
|
|
43569
|
-
return false;
|
|
43570
|
-
const compact = text.replace("-", "");
|
|
43571
|
-
return respawnCommands.filter((command) => command.replace("-", "").startsWith(compact)).length === 1;
|
|
43572
|
-
}) && rest.some((arg) => literalText(arg.exp) === "-k");
|
|
43573
|
-
const killing = rest.find((arg) => {
|
|
43574
|
-
const text = literalText(arg.exp);
|
|
43575
|
-
if (text === undefined)
|
|
43776
|
+
const names = (word, commands) => {
|
|
43777
|
+
if (word === undefined)
|
|
43576
43778
|
return false;
|
|
43779
|
+
const { text, whole } = readableWord(word);
|
|
43577
43780
|
const compact = text.replace("-", "");
|
|
43578
|
-
|
|
43579
|
-
|
|
43781
|
+
const reachable = commands.filter((command) => command.replace("-", "").startsWith(compact));
|
|
43782
|
+
return whole ? reachable.length === 1 : reachable.length > 0;
|
|
43783
|
+
};
|
|
43784
|
+
let killing;
|
|
43785
|
+
for (const segment of segments) {
|
|
43786
|
+
const words = segment.words;
|
|
43787
|
+
let subcommand;
|
|
43788
|
+
for (let i = 0;i < words.length; i += 1) {
|
|
43789
|
+
const arg = words[i];
|
|
43790
|
+
const { text, whole } = readableWord(arg);
|
|
43791
|
+
const attached = (option) => text.startsWith(option) && (!whole || text.length > option.length) ? valueInWord(arg, option.length) : undefined;
|
|
43792
|
+
const carried = attached("-L") ?? attached("-S") ?? attached("--socket=");
|
|
43793
|
+
if (carried !== undefined) {
|
|
43794
|
+
socket = { text: arg.text, exp: carried };
|
|
43795
|
+
socketIsPath = !text.startsWith("-L");
|
|
43796
|
+
} else if (text === "-L" || text === "-S" || text === "--socket") {
|
|
43797
|
+
socket = words[i + 1];
|
|
43798
|
+
socketIsPath = text !== "-L";
|
|
43799
|
+
i += 1;
|
|
43800
|
+
} else if (text === "-f" || text === "-T") {
|
|
43801
|
+
i += 1;
|
|
43802
|
+
} else if (subcommand === undefined && !text.startsWith("-")) {
|
|
43803
|
+
subcommand = arg;
|
|
43804
|
+
}
|
|
43805
|
+
}
|
|
43806
|
+
if (segment.speculative && (subcommand === undefined || readableWord(subcommand).text === ""))
|
|
43807
|
+
continue;
|
|
43808
|
+
const respawning = names(subcommand, respawnCommands) && words.some((arg) => mayBeOption(arg, (text) => text === "-k"));
|
|
43809
|
+
if (names(subcommand, killCommands) || respawning)
|
|
43810
|
+
killing ??= subcommand;
|
|
43811
|
+
}
|
|
43580
43812
|
if (killing === undefined)
|
|
43581
43813
|
return;
|
|
43582
43814
|
let resolvedSocket;
|
|
@@ -43600,13 +43832,19 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43600
43832
|
if (resolvedSocket !== undefined && judgePath(resolvedSocket, st, ctx, { follow: true, overwrite: false }).ok) {
|
|
43601
43833
|
return;
|
|
43602
43834
|
}
|
|
43603
|
-
throw new Refusal(site.snippet, site.line, `\`tmux ${
|
|
43835
|
+
throw new Refusal(site.snippet, site.line, `\`tmux ${killing.text}\` needs a socket path inside this pane's roots; the ` + "resolved socket can end panes and processes this pane did not start");
|
|
43836
|
+
}
|
|
43837
|
+
case "busybox":
|
|
43838
|
+
case "toybox": {
|
|
43839
|
+
if (rest.length === 0)
|
|
43840
|
+
return;
|
|
43841
|
+
throw new Refusal(site.snippet, site.line, `the guard cannot read the applet \`${rest[0].text}\` ${base} would run, and the ` + "applets it carries include `rm`, `sh` and `killall`, which reach paths and processes " + `this pane did not start; name the applet (\`${base} rm \u2026\`) so it can be checked`);
|
|
43604
43842
|
}
|
|
43605
43843
|
default:
|
|
43606
43844
|
break;
|
|
43607
43845
|
}
|
|
43608
|
-
if (SHELLS.has(base)
|
|
43609
|
-
runShell(
|
|
43846
|
+
if (SHELLS.has(base)) {
|
|
43847
|
+
runShell(rest, invocation, st, ctx);
|
|
43610
43848
|
return;
|
|
43611
43849
|
}
|
|
43612
43850
|
const interpreter = interpreterLanguage(base);
|
|
@@ -43636,8 +43874,9 @@ function changeDirectory(target, st, ctx) {
|
|
|
43636
43874
|
function declaration(builtin, list, st, ctx, site) {
|
|
43637
43875
|
const options = list.map((arg) => literalText(arg.exp) ?? "").filter((text) => /^[-+][a-zA-Z]+$/.test(text));
|
|
43638
43876
|
const option = (letter) => options.some((text) => text.startsWith("-") && text.includes(letter));
|
|
43639
|
-
|
|
43640
|
-
|
|
43877
|
+
const mayBeNameref = list.some((arg) => mayBeOption(arg, (text) => /^-[a-zA-Z]*n/.test(text)));
|
|
43878
|
+
if (builtin !== "export" && mayBeNameref) {
|
|
43879
|
+
throw new Refusal(site.snippet, site.line, option("n") ? "the guard does not follow a nameref (`declare -n`), whose writes land in the variable it names" : `an option word \`${builtin}\` carries that the guard cannot read may be \`-n\`, a nameref ` + "whose writes land in the variable it names and which the guard does not follow; write " + "the option as a literal");
|
|
43641
43880
|
}
|
|
43642
43881
|
if (option("f") || option("F"))
|
|
43643
43882
|
return;
|
|
@@ -43822,11 +44061,20 @@ function checkRecursiveMode(program, list, st, ctx, site) {
|
|
|
43822
44061
|
}
|
|
43823
44062
|
found.push(arg);
|
|
43824
44063
|
}
|
|
43825
|
-
if (!recursive)
|
|
43826
|
-
return;
|
|
43827
|
-
const targets = reference ? found : found.slice(1);
|
|
43828
44064
|
const verb = program === "chmod" ? "recursively change the mode of" : "recursively change the owner of";
|
|
43829
|
-
|
|
44065
|
+
if (recursive) {
|
|
44066
|
+
checkTargets(`${program} -R`, verb, reference ? found : found.slice(1), true, st, ctx, site);
|
|
44067
|
+
return;
|
|
44068
|
+
}
|
|
44069
|
+
for (const [index, arg] of found.entries()) {
|
|
44070
|
+
if (!mayBeOption(arg, (text) => /^-[A-Za-z]*R/.test(text)))
|
|
44071
|
+
continue;
|
|
44072
|
+
const others = arg.fields === "unknown" ? found : found.filter((_, at) => at !== index);
|
|
44073
|
+
const targets = reference || arg.fields === "unknown" ? others : others.slice(1);
|
|
44074
|
+
if (targets.length === 0)
|
|
44075
|
+
continue;
|
|
44076
|
+
checkTargets(`${program} -R`, verb, targets, true, st, ctx, site);
|
|
44077
|
+
}
|
|
43830
44078
|
}
|
|
43831
44079
|
function checkFind(list, st, ctx, site) {
|
|
43832
44080
|
let i = 0;
|
|
@@ -43841,17 +44089,27 @@ function checkFind(list, st, ctx, site) {
|
|
|
43841
44089
|
break;
|
|
43842
44090
|
}
|
|
43843
44091
|
const starts = [];
|
|
44092
|
+
let rootsBeforePredicate;
|
|
43844
44093
|
for (;i < list.length; i += 1) {
|
|
43845
|
-
const
|
|
44094
|
+
const arg = list[i];
|
|
44095
|
+
const text = literalText(arg.exp);
|
|
43846
44096
|
if (text !== undefined && (text.startsWith("-") || text === "(" || text === "!" || text === ")"))
|
|
43847
44097
|
break;
|
|
43848
|
-
|
|
44098
|
+
if (rootsBeforePredicate === undefined && mayBeOption(arg, (option) => option.startsWith("-"))) {
|
|
44099
|
+
rootsBeforePredicate = [...starts];
|
|
44100
|
+
}
|
|
44101
|
+
starts.push(arg);
|
|
43849
44102
|
}
|
|
43850
44103
|
const targets = starts.length > 0 ? starts : [{ text: ".", exp: [literal2(".")] }];
|
|
43851
44104
|
const expression = list.slice(i).map((arg) => literalText(arg.exp));
|
|
43852
44105
|
let action;
|
|
43853
44106
|
let shell;
|
|
44107
|
+
let consumedByPredicate = false;
|
|
43854
44108
|
for (const [index, word] of expression.entries()) {
|
|
44109
|
+
const isValue = consumedByPredicate;
|
|
44110
|
+
consumedByPredicate = word !== undefined && FIND_VALUED_PREDICATES.has(word);
|
|
44111
|
+
if (word === undefined && !isValue)
|
|
44112
|
+
action ??= "find with a predicate the guard cannot read";
|
|
43855
44113
|
if (word === "-delete")
|
|
43856
44114
|
action = "find -delete";
|
|
43857
44115
|
if (word !== "-exec" && word !== "-execdir" && word !== "-ok" && word !== "-okdir")
|
|
@@ -43868,8 +44126,13 @@ function checkFind(list, st, ctx, site) {
|
|
|
43868
44126
|
shell = inner.argv;
|
|
43869
44127
|
}
|
|
43870
44128
|
}
|
|
43871
|
-
if (action === undefined)
|
|
44129
|
+
if (action === undefined) {
|
|
44130
|
+
if (rootsBeforePredicate === undefined)
|
|
44131
|
+
return;
|
|
44132
|
+
const under = rootsBeforePredicate.length > 0 ? rootsBeforePredicate : [{ text: ".", exp: [literal2(".")] }];
|
|
44133
|
+
checkTargets("find with a root the guard cannot read, which may be a predicate", "delete or change what it finds under", under, false, st, ctx, site);
|
|
43872
44134
|
return;
|
|
44135
|
+
}
|
|
43873
44136
|
checkTargets(action, "delete or change what it finds under", targets, false, st, ctx, site);
|
|
43874
44137
|
if (shell === undefined)
|
|
43875
44138
|
return;
|
|
@@ -44146,7 +44409,7 @@ function runInterpreter(base, language, list, invocation, st, ctx) {
|
|
|
44146
44409
|
for (;i < words.length; i += 1) {
|
|
44147
44410
|
const word = words[i];
|
|
44148
44411
|
if (word === undefined)
|
|
44149
|
-
|
|
44412
|
+
continue;
|
|
44150
44413
|
if (codeFlags.includes(word)) {
|
|
44151
44414
|
runCode(language, list[i + 1], invocation, st, ctx, site);
|
|
44152
44415
|
return;
|
|
@@ -44195,8 +44458,8 @@ function runFile(file2, positional, st, ctx, site, kind, source = false) {
|
|
|
44195
44458
|
let content;
|
|
44196
44459
|
if (st.files.has(abs)) {
|
|
44197
44460
|
const written = st.files.get(abs);
|
|
44198
|
-
if (written ===
|
|
44199
|
-
throw new Refusal(site.snippet, site.line, `this command
|
|
44461
|
+
if (written === undefined || typeof written !== "string") {
|
|
44462
|
+
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
44463
|
}
|
|
44201
44464
|
content = written;
|
|
44202
44465
|
} else {
|
|
@@ -44389,7 +44652,8 @@ function createPaneGuard(options) {
|
|
|
44389
44652
|
env,
|
|
44390
44653
|
ompPid: options.ompPid,
|
|
44391
44654
|
parentOf: options.parentOf ?? procParent,
|
|
44392
|
-
steps: { count: 0 }
|
|
44655
|
+
steps: { count: 0 },
|
|
44656
|
+
uncertain: { depth: 0 }
|
|
44393
44657
|
});
|
|
44394
44658
|
const initial = (cwd, source) => ({
|
|
44395
44659
|
vars: new Map,
|