@yanlinglabs/winter-agent-runtime 0.0.39 → 0.0.41
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/embedded-worker.js +3 -3
- package/dist/embedded.js +3 -3
- package/dist/engine.d.ts +8 -0
- package/dist/{index-b08mghw8.js → index-ey5c52j3.js} +2 -2
- package/dist/{index-es0skt5n.js → index-hdvvezf8.js} +8 -2
- package/dist/{index-dh2xed37.js → index-z9yngxj4.js} +1963 -111
- package/dist/index.js +1 -1
- package/dist/permissions/bash-read-only.d.ts +26 -0
- package/dist/permissions/grammar.d.ts +32 -6
- package/dist/production-wiring.d.ts +3 -1
- package/dist/rpc/bridge.d.ts +1 -0
- package/dist/store/dialect.d.ts +1 -1
- package/dist/subagents/child-engine.d.ts +2 -0
- package/dist/subagents/register-default-factory.d.ts +2 -0
- package/dist/testing.js +2 -2
- package/dist/tools/concurrency.d.ts +48 -0
- package/dist/tools/registry.d.ts +25 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -61,12 +61,24 @@ function createRpcBridge2(output, bridgeOpts = {}) {
|
|
|
61
61
|
const onAbort = () => {
|
|
62
62
|
if (pending.get(requestId) !== entry)
|
|
63
63
|
return;
|
|
64
|
-
pending.delete(requestId);
|
|
65
64
|
if (entry.timer !== undefined)
|
|
66
65
|
clearTimeout(entry.timer);
|
|
67
|
-
|
|
66
|
+
const wasHeld = held?.delete(requestId) === true;
|
|
67
|
+
if (!wasHeld)
|
|
68
68
|
output.write({ type: "control_cancel_request", requestId });
|
|
69
|
-
|
|
69
|
+
const cancelled = () => {
|
|
70
|
+
if (pending.get(requestId) !== entry)
|
|
71
|
+
return;
|
|
72
|
+
pending.delete(requestId);
|
|
73
|
+
reject(new WinterRpcError("cancelled", `the '${subtype}' request was cancelled: the runtime stopped waiting for it`));
|
|
74
|
+
};
|
|
75
|
+
const grace = opts?.cancelGraceMs;
|
|
76
|
+
if (grace === undefined || wasHeld) {
|
|
77
|
+
cancelled();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
entry.timer = setTimeout(cancelled, grace);
|
|
81
|
+
entry.timer.unref?.();
|
|
70
82
|
};
|
|
71
83
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
72
84
|
entry.detach = () => signal.removeEventListener("abort", onAbort);
|
|
@@ -265,10 +277,28 @@ function leadingWord(s) {
|
|
|
265
277
|
function joinLineContinuations(command) {
|
|
266
278
|
if (!command.includes("\\\n"))
|
|
267
279
|
return command;
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
280
|
+
let out = "";
|
|
281
|
+
let i = 0;
|
|
282
|
+
while (i < command.length) {
|
|
283
|
+
if (command[i] !== "\\") {
|
|
284
|
+
out += command[i];
|
|
285
|
+
i++;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
let end = i;
|
|
289
|
+
while (end < command.length && command[end] === "\\")
|
|
290
|
+
end++;
|
|
291
|
+
const run = end - i;
|
|
292
|
+
if (command[end] === `
|
|
293
|
+
` && run % 2 === 1) {
|
|
294
|
+
out += "\\".repeat(run - 1);
|
|
295
|
+
i = end + 1;
|
|
296
|
+
} else {
|
|
297
|
+
out += "\\".repeat(run);
|
|
298
|
+
i = end;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return out;
|
|
272
302
|
}
|
|
273
303
|
function splitCompound(rawCommand) {
|
|
274
304
|
const command = joinLineContinuations(rawCommand);
|
|
@@ -350,25 +380,34 @@ function stripLeadingAssignmentsAt(s, info, start, direction) {
|
|
|
350
380
|
}
|
|
351
381
|
return pos;
|
|
352
382
|
}
|
|
353
|
-
function
|
|
383
|
+
function stripWrappersDetailed(rawCmd, direction) {
|
|
354
384
|
const cmd = joinLineContinuations(rawCmd);
|
|
355
385
|
const info = scanShellLike(cmd);
|
|
386
|
+
const finish = (pos, ambiguousForAllow = false) => {
|
|
387
|
+
const carried = info.ok ? redirectWriteSpans(cmd, info).filter((span) => span.start < pos).map((span) => cmd.slice(span.start, span.end)) : [];
|
|
388
|
+
return { inner: cmd.slice(pos), carried, ambiguousForAllow };
|
|
389
|
+
};
|
|
356
390
|
let pos = 0;
|
|
357
391
|
for (;; ) {
|
|
358
392
|
pos = stripLeadingAssignmentsAt(cmd, info, pos, direction);
|
|
359
393
|
const { word: rawWord, end: afterWordEnd } = leadingWordAt(cmd, info, pos);
|
|
360
394
|
if (rawWord === undefined)
|
|
361
|
-
return
|
|
362
|
-
const
|
|
395
|
+
return finish(pos);
|
|
396
|
+
const isWrapperName = (r) => r === XARGS || FIXED_WRAPPERS.has(r);
|
|
397
|
+
const readings = shellWordReadings(rawWord);
|
|
398
|
+
const exact = readings[0];
|
|
399
|
+
if (direction === "allow" && !isWrapperName(exact) && readings.some(isWrapperName))
|
|
400
|
+
return finish(pos, true);
|
|
401
|
+
const word = direction === "allow" ? exact : readings.find(isWrapperName) ?? exact;
|
|
363
402
|
if (word === XARGS) {
|
|
364
403
|
const { word: next } = leadingWordAt(cmd, info, afterWordEnd);
|
|
365
404
|
if (next !== undefined && next.startsWith("-"))
|
|
366
|
-
return
|
|
405
|
+
return finish(pos);
|
|
367
406
|
pos = afterWordEnd;
|
|
368
407
|
continue;
|
|
369
408
|
}
|
|
370
409
|
if (!FIXED_WRAPPERS.has(word))
|
|
371
|
-
return
|
|
410
|
+
return finish(pos);
|
|
372
411
|
let remainderPos = afterWordEnd;
|
|
373
412
|
for (;; ) {
|
|
374
413
|
const { word: flag, end: afterFlagEnd } = leadingWordAt(cmd, info, remainderPos);
|
|
@@ -384,6 +423,17 @@ function stripWrappers(rawCmd, direction) {
|
|
|
384
423
|
pos = remainderPos;
|
|
385
424
|
}
|
|
386
425
|
}
|
|
426
|
+
var joinedStrip = (strip) => [strip.inner, ...strip.carried].filter((part) => part !== "").join(" ");
|
|
427
|
+
function stripWrappers(rawCmd, direction) {
|
|
428
|
+
const strip = stripWrappersDetailed(rawCmd, direction);
|
|
429
|
+
return strip.ambiguousForAllow ? joinLineContinuations(rawCmd).trimStart() : joinedStrip(strip);
|
|
430
|
+
}
|
|
431
|
+
function ruleMatchTexts(command, direction) {
|
|
432
|
+
const strip = stripWrappersDetailed(command, direction);
|
|
433
|
+
if (strip.ambiguousForAllow)
|
|
434
|
+
return [];
|
|
435
|
+
return direction === "allow" ? [strip.inner] : [joinedStrip(strip), strip.inner];
|
|
436
|
+
}
|
|
387
437
|
var ANSI_C_SIMPLE_ESCAPES = { n: `
|
|
388
438
|
`, t: "\t", r: "\r", a: "\x07", b: "\b", e: "\x1B", E: "\x1B", f: "\f", v: "\v", "\\": "\\", "'": "'", '"': '"', "?": "?" };
|
|
389
439
|
function decodeAnsiCEscape(s, i) {
|
|
@@ -413,7 +463,9 @@ function decodeAnsiCEscape(s, i) {
|
|
|
413
463
|
return { text: String.fromCharCode(s.charCodeAt(i + 1) & 31), next: i + 2 };
|
|
414
464
|
return { text: `\\${ch}`, next: i + 1 };
|
|
415
465
|
}
|
|
416
|
-
|
|
466
|
+
var DOUBLE_QUOTE_ESCAPABLE = new Set(["$", "`", '"', "\\", `
|
|
467
|
+
`]);
|
|
468
|
+
function shellWords(s, split = true, reading = "broad") {
|
|
417
469
|
const words = [];
|
|
418
470
|
let cur = "";
|
|
419
471
|
let start = -1;
|
|
@@ -455,9 +507,12 @@ function shellWords(s, split = true) {
|
|
|
455
507
|
if (ch === '"')
|
|
456
508
|
quote = null;
|
|
457
509
|
else if (ch === "\\" && i + 1 < s.length) {
|
|
458
|
-
|
|
510
|
+
const next = s[i + 1];
|
|
511
|
+
if (reading === "bash" && !DOUBLE_QUOTE_ESCAPABLE.has(next))
|
|
512
|
+
cur += ch + next;
|
|
513
|
+
else if (next !== `
|
|
459
514
|
`)
|
|
460
|
-
cur +=
|
|
515
|
+
cur += next;
|
|
461
516
|
i++;
|
|
462
517
|
} else
|
|
463
518
|
cur += ch;
|
|
@@ -498,7 +553,12 @@ function shellWords(s, split = true) {
|
|
|
498
553
|
return words;
|
|
499
554
|
}
|
|
500
555
|
function dequoteShellWord(word) {
|
|
501
|
-
return shellWords(word, false)[0]?.word ?? "";
|
|
556
|
+
return shellWords(word, false, "bash")[0]?.word ?? "";
|
|
557
|
+
}
|
|
558
|
+
function shellWordReadings(word) {
|
|
559
|
+
const exact = dequoteShellWord(word);
|
|
560
|
+
const broad = shellWords(word, false, "broad")[0]?.word ?? "";
|
|
561
|
+
return broad === exact ? [exact] : [exact, broad];
|
|
502
562
|
}
|
|
503
563
|
var REDIRECT_WORD_STOP = /[\s;&|<>()]/;
|
|
504
564
|
function redirectWordAt(s, info, start) {
|
|
@@ -515,12 +575,23 @@ function extractRedirectWrites(rawCommand) {
|
|
|
515
575
|
const info = scanShellLike(command);
|
|
516
576
|
if (!info.ok)
|
|
517
577
|
return [];
|
|
518
|
-
const { topLevel } = info;
|
|
519
578
|
const writes = [];
|
|
520
|
-
const
|
|
521
|
-
|
|
579
|
+
const pushReadings = (raw) => {
|
|
580
|
+
for (const target of shellWordReadings(raw))
|
|
581
|
+
writes.push({ raw, target });
|
|
582
|
+
};
|
|
583
|
+
for (const { target: raw } of redirectWriteSpans(command, info)) {
|
|
584
|
+
pushReadings(raw);
|
|
522
585
|
if (raw.length > 1 && raw.startsWith("!"))
|
|
523
|
-
|
|
586
|
+
pushReadings(raw.slice(1));
|
|
587
|
+
}
|
|
588
|
+
return writes;
|
|
589
|
+
}
|
|
590
|
+
function redirectWriteSpans(command, info) {
|
|
591
|
+
const { topLevel } = info;
|
|
592
|
+
const spans = [];
|
|
593
|
+
const push = (start, target, end) => {
|
|
594
|
+
spans.push({ start, end, target });
|
|
524
595
|
};
|
|
525
596
|
let i = 0;
|
|
526
597
|
while (i < command.length) {
|
|
@@ -566,10 +637,10 @@ function extractRedirectWrites(rawCommand) {
|
|
|
566
637
|
continue;
|
|
567
638
|
}
|
|
568
639
|
if (!(descriptorCopy && /^(?:[0-9]+|-)$/.test(dequoteShellWord(word))))
|
|
569
|
-
push(word);
|
|
640
|
+
push(i, word, end);
|
|
570
641
|
i = end;
|
|
571
642
|
}
|
|
572
|
-
return
|
|
643
|
+
return spans;
|
|
573
644
|
}
|
|
574
645
|
function extractRedirectTargets(command) {
|
|
575
646
|
return extractRedirectWrites(command).map((w) => w.target);
|
|
@@ -583,8 +654,8 @@ function isRecognizedReadOnly(command) {
|
|
|
583
654
|
const { word: first, afterWord } = leadingWord(stripped);
|
|
584
655
|
if (first === undefined)
|
|
585
656
|
return false;
|
|
586
|
-
const
|
|
587
|
-
const hasFlag = (pattern) =>
|
|
657
|
+
const views = [afterWord, ...["broad", "bash"].map((reading) => shellWords(afterWord, true, reading).map((w) => w.word).join(" "))];
|
|
658
|
+
const hasFlag = (pattern) => views.some((view) => pattern.test(view));
|
|
588
659
|
if (first === "git") {
|
|
589
660
|
const { word: sub } = leadingWord(afterWord);
|
|
590
661
|
return sub !== undefined && GIT_READ_ONLY_SUBCOMMANDS.has(sub) && !hasFlag(GIT_WRITE_CAPABLE_FLAGS);
|
|
@@ -794,8 +865,8 @@ function matchesRule(rule, call, opts) {
|
|
|
794
865
|
case "pattern": {
|
|
795
866
|
const raw = call.input["command"];
|
|
796
867
|
const cmd = typeof raw === "string" ? raw : "";
|
|
797
|
-
const
|
|
798
|
-
return
|
|
868
|
+
const pattern = compilePattern(rule.specifier.source);
|
|
869
|
+
return ruleMatchTexts(cmd, opts.direction).some((text) => pattern.test(text));
|
|
799
870
|
}
|
|
800
871
|
}
|
|
801
872
|
}
|
|
@@ -1112,6 +1183,15 @@ function dedupeSameBatch(server, tools) {
|
|
|
1112
1183
|
}
|
|
1113
1184
|
return dropped ? out : tools;
|
|
1114
1185
|
}
|
|
1186
|
+
var CONCURRENCY_LANE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
1187
|
+
function isValidConcurrencyLane(lane) {
|
|
1188
|
+
return typeof lane === "string" && CONCURRENCY_LANE.test(lane);
|
|
1189
|
+
}
|
|
1190
|
+
function concurrentToolSet(raw) {
|
|
1191
|
+
if (!Array.isArray(raw))
|
|
1192
|
+
return new Set;
|
|
1193
|
+
return new Set(raw.filter((name) => typeof name === "string"));
|
|
1194
|
+
}
|
|
1115
1195
|
function registerMcpServerTools(server, incomingTools, opts) {
|
|
1116
1196
|
if (RESERVED_MCP_SERVER_NAMES.has(server)) {
|
|
1117
1197
|
throw new Error(`registerMcpServerTools: "${server}" is a RESERVED server name -- the standing Winter server ` + `(its name is defined in mcp/winter-server.ts) owns this identity and is registry-native; it is never installed through ` + `this live-mutation function, and nothing else may register live tools under it either.`);
|
|
@@ -1163,10 +1243,13 @@ function registerMcpServerTools(server, incomingTools, opts) {
|
|
|
1163
1243
|
}
|
|
1164
1244
|
}
|
|
1165
1245
|
const nowOwned = new Set;
|
|
1246
|
+
const concurrent = concurrentToolSet(opts.concurrentTools);
|
|
1166
1247
|
for (const tool of tools) {
|
|
1167
1248
|
const canonicalName = registeredName(tool);
|
|
1168
1249
|
const existingEntry = registry.get(canonicalName);
|
|
1169
|
-
const
|
|
1250
|
+
const built = buildMcpToolDescriptor(server, tool, opts, plainNameFor(tool));
|
|
1251
|
+
const lane = opts.toolLanes !== undefined && Object.hasOwn(opts.toolLanes, tool.name) ? opts.toolLanes[tool.name] : undefined;
|
|
1252
|
+
const descriptor = isValidConcurrencyLane(lane) ? { ...built, concurrencyLane: lane } : concurrent.has(tool.name) ? { ...built, concurrencySafe: true } : built;
|
|
1170
1253
|
registry.set(canonicalName, existingEntry ? { ...existingEntry, descriptor } : { descriptor });
|
|
1171
1254
|
mcpToolOwner.set(canonicalName, server);
|
|
1172
1255
|
nowOwned.add(canonicalName);
|
|
@@ -4554,7 +4637,7 @@ function parentOf(dir) {
|
|
|
4554
4637
|
// src/engine.ts
|
|
4555
4638
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
4556
4639
|
import { homedir, release as osRelease, type as osType } from "node:os";
|
|
4557
|
-
import { join as
|
|
4640
|
+
import { join as join26, resolve as resolve12 } from "node:path";
|
|
4558
4641
|
import {
|
|
4559
4642
|
PROTOCOL_VERSION,
|
|
4560
4643
|
resolveWebToolsConfig,
|
|
@@ -8390,9 +8473,10 @@ function naiveWriteWords(command) {
|
|
|
8390
8473
|
const out = [];
|
|
8391
8474
|
for (const m of command.matchAll(/(?:&>>?|[0-9]*>>?\|?|[0-9]*>&|<>)[ \t]*([^\s;&|()<>]+)/g)) {
|
|
8392
8475
|
const raw = m[1];
|
|
8393
|
-
const word
|
|
8394
|
-
|
|
8395
|
-
|
|
8476
|
+
for (const word of shellWordReadings(raw)) {
|
|
8477
|
+
if (!/^(?:[0-9]+|-)$/.test(word))
|
|
8478
|
+
out.push({ word, raw, quoted: word !== raw });
|
|
8479
|
+
}
|
|
8396
8480
|
}
|
|
8397
8481
|
for (const piece of naiveCommandPieces(command)) {
|
|
8398
8482
|
const stripped = stripWrappers(piece, "denyAsk");
|
|
@@ -22441,13 +22525,1593 @@ Sources:
|
|
|
22441
22525
|
}
|
|
22442
22526
|
replaceExecutor(SEARCH_CANONICAL_NAME, createSearchExecutor());
|
|
22443
22527
|
|
|
22528
|
+
// src/permissions/bash-read-only.ts
|
|
22529
|
+
import { statSync as statSync10 } from "node:fs";
|
|
22530
|
+
import { join as join24 } from "node:path";
|
|
22531
|
+
var READ_ONLY_LENGTH_LIMIT = 4096;
|
|
22532
|
+
var WHOLE_TEXT_REFUSALS = [
|
|
22533
|
+
(text) => text.length > Math.min(PARSE_LIMIT, READ_ONLY_LENGTH_LIMIT),
|
|
22534
|
+
(text) => text.trim() === "",
|
|
22535
|
+
(text) => splitCompound(text) === null,
|
|
22536
|
+
(text) => !passesSecurityValidators(text),
|
|
22537
|
+
(text, platform) => containsVulnerableUncPath(text, platform)
|
|
22538
|
+
];
|
|
22539
|
+
function isBashCommandReadOnly(command, ctx) {
|
|
22540
|
+
const platform = process.platform;
|
|
22541
|
+
if (typeof command !== "string" || WHOLE_TEXT_REFUSALS.some((refuses) => refuses(command, platform)))
|
|
22542
|
+
return false;
|
|
22543
|
+
const joined = joinLineContinuations(command);
|
|
22544
|
+
if ((substitutionBodies(joined) ?? [""]).length > 0)
|
|
22545
|
+
return false;
|
|
22546
|
+
const commands = readSimpleCommands(joined) ?? [];
|
|
22547
|
+
if (commands.length === 0 || gitRunsUnsafely(joined, commands, ctx))
|
|
22548
|
+
return false;
|
|
22549
|
+
return commands.every((simple) => passesSecurityValidators(simple.text) && isSimpleCommandReadOnly(simple, platform));
|
|
22550
|
+
}
|
|
22551
|
+
var SHELL_OPERATORS = ["<<<", "&&", "||", "|&", ";;", ";&", "&>", ">>", ">&", ">|", "<<", "<&", "<>", ">", "<", "&", "|", ";"];
|
|
22552
|
+
var COMMAND_SEPARATORS = new Set([";", "&&", "||", "|"]);
|
|
22553
|
+
function throwsOutputAway(operator, descriptor, target) {
|
|
22554
|
+
if (operator === ">")
|
|
22555
|
+
return target === "/dev/null" && (descriptor === undefined || ["0", "1", "2"].includes(descriptor));
|
|
22556
|
+
return operator === ">&" && descriptor === "2" && target === "1";
|
|
22557
|
+
}
|
|
22558
|
+
function readSimpleCommands(text) {
|
|
22559
|
+
const lx = lex(text);
|
|
22560
|
+
if (lx.unterminated || text.includes("\r"))
|
|
22561
|
+
return null;
|
|
22562
|
+
let lastNonBlank = text.length - 1;
|
|
22563
|
+
while (lastNonBlank >= 0 && isBlank(text[lastNonBlank]))
|
|
22564
|
+
lastNonBlank--;
|
|
22565
|
+
const commands = [];
|
|
22566
|
+
let words = [];
|
|
22567
|
+
let wordStart = -1;
|
|
22568
|
+
let awaiting;
|
|
22569
|
+
let endedBySemicolon = false;
|
|
22570
|
+
const closeWord = (end) => {
|
|
22571
|
+
if (wordStart === -1)
|
|
22572
|
+
return true;
|
|
22573
|
+
const raw = text.slice(wordStart, end);
|
|
22574
|
+
wordStart = -1;
|
|
22575
|
+
if (awaiting !== undefined) {
|
|
22576
|
+
const harmless = throwsOutputAway(awaiting.operator, awaiting.descriptor, raw);
|
|
22577
|
+
awaiting = undefined;
|
|
22578
|
+
return harmless;
|
|
22579
|
+
}
|
|
22580
|
+
words.push({ raw, value: dequoteShellWord(raw) });
|
|
22581
|
+
return true;
|
|
22582
|
+
};
|
|
22583
|
+
const opensSubstitution = (i, quoteForms) => {
|
|
22584
|
+
const next = text[i + 1];
|
|
22585
|
+
return text[i] === "$" && next !== undefined && (next === "(" || next === "{" || next === "[" || quoteForms && (next === "'" || next === '"'));
|
|
22586
|
+
};
|
|
22587
|
+
for (let i = 0;i < text.length; i++) {
|
|
22588
|
+
const ch = text[i];
|
|
22589
|
+
if (!isBare(lx, i)) {
|
|
22590
|
+
if (lx.role[i] === 0 /* Text */ && lx.quoting[i] === 2 /* Double */ && (ch === "`" || opensSubstitution(i, false)))
|
|
22591
|
+
return null;
|
|
22592
|
+
if (wordStart === -1)
|
|
22593
|
+
wordStart = i;
|
|
22594
|
+
continue;
|
|
22595
|
+
}
|
|
22596
|
+
if (ch === " " || ch === "\t" || ch === `
|
|
22597
|
+
`) {
|
|
22598
|
+
if (!closeWord(i))
|
|
22599
|
+
return null;
|
|
22600
|
+
if (ch === `
|
|
22601
|
+
` && i < lastNonBlank)
|
|
22602
|
+
return null;
|
|
22603
|
+
continue;
|
|
22604
|
+
}
|
|
22605
|
+
if (ch === "`" || ch === "(" || ch === ")" || ch === "\\")
|
|
22606
|
+
return null;
|
|
22607
|
+
if (opensSubstitution(i, true))
|
|
22608
|
+
return null;
|
|
22609
|
+
if (ch === "#" && wordStart === -1)
|
|
22610
|
+
return null;
|
|
22611
|
+
if (!";&|<>".includes(ch)) {
|
|
22612
|
+
if (wordStart === -1)
|
|
22613
|
+
wordStart = i;
|
|
22614
|
+
continue;
|
|
22615
|
+
}
|
|
22616
|
+
const operator = SHELL_OPERATORS.find((op) => text.startsWith(op, i));
|
|
22617
|
+
const glued = wordStart === -1 ? undefined : text.slice(wordStart, i);
|
|
22618
|
+
let descriptor;
|
|
22619
|
+
if (glued !== undefined && /^\d+$/.test(glued) && (operator[0] === ">" || operator[0] === "<")) {
|
|
22620
|
+
descriptor = glued;
|
|
22621
|
+
wordStart = -1;
|
|
22622
|
+
} else if (!closeWord(i)) {
|
|
22623
|
+
return null;
|
|
22624
|
+
}
|
|
22625
|
+
i += operator.length - 1;
|
|
22626
|
+
if (awaiting !== undefined)
|
|
22627
|
+
return null;
|
|
22628
|
+
if (descriptor === undefined && COMMAND_SEPARATORS.has(operator)) {
|
|
22629
|
+
if (words.length === 0)
|
|
22630
|
+
return null;
|
|
22631
|
+
commands.push({ words, text: words.map((w) => w.raw).join(" ") });
|
|
22632
|
+
words = [];
|
|
22633
|
+
endedBySemicolon = operator === ";";
|
|
22634
|
+
continue;
|
|
22635
|
+
}
|
|
22636
|
+
awaiting = descriptor === undefined ? { operator } : { operator, descriptor };
|
|
22637
|
+
}
|
|
22638
|
+
if (!closeWord(text.length) || awaiting !== undefined)
|
|
22639
|
+
return null;
|
|
22640
|
+
if (words.length > 0)
|
|
22641
|
+
commands.push({ words, text: words.map((w) => w.raw).join(" ") });
|
|
22642
|
+
else if (!(commands.length > 0 && endedBySemicolon))
|
|
22643
|
+
return null;
|
|
22644
|
+
return commands;
|
|
22645
|
+
}
|
|
22646
|
+
var DIRECTORY_CHANGERS = new Set(["cd", "pushd", "popd"]);
|
|
22647
|
+
function programsRunBy(simple) {
|
|
22648
|
+
const programs = new Set([simple.words[0].value]);
|
|
22649
|
+
const inner = leadingWord(stripWrappers(simple.text, "denyAsk")).word;
|
|
22650
|
+
if (inner !== undefined)
|
|
22651
|
+
programs.add(dequoteShellWord(inner));
|
|
22652
|
+
if (simple.words[0].value === "xargs")
|
|
22653
|
+
for (const word of simple.words)
|
|
22654
|
+
programs.add(word.value);
|
|
22655
|
+
return programs;
|
|
22656
|
+
}
|
|
22657
|
+
function entryKind(path) {
|
|
22658
|
+
try {
|
|
22659
|
+
const entry = statSync10(path);
|
|
22660
|
+
return entry.isFile() ? "file" : entry.isDirectory() ? "directory" : "other";
|
|
22661
|
+
} catch {
|
|
22662
|
+
return "missing";
|
|
22663
|
+
}
|
|
22664
|
+
}
|
|
22665
|
+
var BARE_REPOSITORY_MARKERS = [
|
|
22666
|
+
["HEAD", "file"],
|
|
22667
|
+
["objects", "directory"],
|
|
22668
|
+
["refs", "directory"]
|
|
22669
|
+
];
|
|
22670
|
+
function isCurrentDirectoryBareGitRepo(cwd) {
|
|
22671
|
+
const dotGit = entryKind(join24(cwd, ".git"));
|
|
22672
|
+
const workingRepository = dotGit === "file" || dotGit === "directory" && entryKind(join24(cwd, ".git", "HEAD")) === "file";
|
|
22673
|
+
if (workingRepository)
|
|
22674
|
+
return false;
|
|
22675
|
+
return BARE_REPOSITORY_MARKERS.some(([name, kind]) => entryKind(join24(cwd, name)) === kind);
|
|
22676
|
+
}
|
|
22677
|
+
var GIT_INTERNAL_TOP_LEVEL = new Set(["objects", "refs", "hooks"]);
|
|
22678
|
+
function namesGitInternals(path) {
|
|
22679
|
+
const segments = path.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
22680
|
+
const top = segments[0];
|
|
22681
|
+
if (top === undefined)
|
|
22682
|
+
return false;
|
|
22683
|
+
return top === "HEAD" && segments.length === 1 || GIT_INTERNAL_TOP_LEVEL.has(top);
|
|
22684
|
+
}
|
|
22685
|
+
var CREATING_COMMANDS = new Set(["mkdir", "touch", "cp", "mv"]);
|
|
22686
|
+
function gitRunsUnsafely(joined, commands, ctx) {
|
|
22687
|
+
const programs = commands.map(programsRunBy);
|
|
22688
|
+
if (!programs.some((set) => set.has("git")))
|
|
22689
|
+
return false;
|
|
22690
|
+
if (programs.some((set) => [...DIRECTORY_CHANGERS].some((changer) => set.has(changer))))
|
|
22691
|
+
return true;
|
|
22692
|
+
if (isCurrentDirectoryBareGitRepo(ctx.cwd))
|
|
22693
|
+
return true;
|
|
22694
|
+
if (extractRedirectTargets(joined).some(namesGitInternals))
|
|
22695
|
+
return true;
|
|
22696
|
+
const createsInternals = commands.some((simple) => CREATING_COMMANDS.has(simple.words[0].value) && simple.words.slice(1).some((w) => !w.value.startsWith("-") && namesGitInternals(w.value)));
|
|
22697
|
+
return createsInternals || ctx.sandboxEnabled && ctx.cwd !== ctx.originalCwd;
|
|
22698
|
+
}
|
|
22699
|
+
var WEBDAV_MARKERS = [/@SSL@\d+/i, /@\d+@SSL/i, /DavWWWRoot/i];
|
|
22700
|
+
var isPathSeparator = (ch) => ch === "/" || ch === "\\";
|
|
22701
|
+
function containsVulnerableUncPath(text, platform = process.platform) {
|
|
22702
|
+
if (platform !== "win32")
|
|
22703
|
+
return false;
|
|
22704
|
+
if (WEBDAV_MARKERS.some((marker) => marker.test(text)))
|
|
22705
|
+
return true;
|
|
22706
|
+
let i = 0;
|
|
22707
|
+
while (i < text.length) {
|
|
22708
|
+
if (!isPathSeparator(text[i])) {
|
|
22709
|
+
i++;
|
|
22710
|
+
continue;
|
|
22711
|
+
}
|
|
22712
|
+
const runStart = i;
|
|
22713
|
+
while (i < text.length && isPathSeparator(text[i]))
|
|
22714
|
+
i++;
|
|
22715
|
+
const host = text[i];
|
|
22716
|
+
if (i - runStart < 2 || host === undefined || /\s/.test(host))
|
|
22717
|
+
continue;
|
|
22718
|
+
const urlScheme = i - runStart === 2 && text[runStart] === "/" && text[runStart + 1] === "/" && text[runStart - 1] === ":";
|
|
22719
|
+
if (!urlScheme)
|
|
22720
|
+
return true;
|
|
22721
|
+
}
|
|
22722
|
+
return false;
|
|
22723
|
+
}
|
|
22724
|
+
function lex(text) {
|
|
22725
|
+
const quoting = new Uint8Array(text.length);
|
|
22726
|
+
const role = new Uint8Array(text.length);
|
|
22727
|
+
let open = 0 /* None */;
|
|
22728
|
+
for (let i = 0;i < text.length; i++) {
|
|
22729
|
+
const ch = text[i];
|
|
22730
|
+
if (open === 1 /* Single */) {
|
|
22731
|
+
quoting[i] = 1 /* Single */;
|
|
22732
|
+
if (ch === "'") {
|
|
22733
|
+
role[i] = 1 /* QuoteMark */;
|
|
22734
|
+
open = 0 /* None */;
|
|
22735
|
+
}
|
|
22736
|
+
continue;
|
|
22737
|
+
}
|
|
22738
|
+
if (ch === "\\" && i + 1 < text.length) {
|
|
22739
|
+
quoting[i] = quoting[i + 1] = open;
|
|
22740
|
+
role[i] = 2 /* Escape */;
|
|
22741
|
+
role[i + 1] = 3 /* Escaped */;
|
|
22742
|
+
i++;
|
|
22743
|
+
continue;
|
|
22744
|
+
}
|
|
22745
|
+
if (open === 2 /* Double */) {
|
|
22746
|
+
quoting[i] = 2 /* Double */;
|
|
22747
|
+
if (ch === '"') {
|
|
22748
|
+
role[i] = 1 /* QuoteMark */;
|
|
22749
|
+
open = 0 /* None */;
|
|
22750
|
+
}
|
|
22751
|
+
continue;
|
|
22752
|
+
}
|
|
22753
|
+
if (ch === "'" || ch === '"') {
|
|
22754
|
+
open = ch === "'" ? 1 /* Single */ : 2 /* Double */;
|
|
22755
|
+
quoting[i] = open;
|
|
22756
|
+
role[i] = 1 /* QuoteMark */;
|
|
22757
|
+
}
|
|
22758
|
+
}
|
|
22759
|
+
return { text, quoting, role, unterminated: open !== 0 /* None */ };
|
|
22760
|
+
}
|
|
22761
|
+
var isBare = (lx, i) => lx.quoting[i] === 0 /* None */ && lx.role[i] === 0 /* Text */;
|
|
22762
|
+
var isBlank = (ch) => ch !== undefined && /\s/.test(ch);
|
|
22763
|
+
function viewsOf(lx, keepDoubleMarks) {
|
|
22764
|
+
let outsideSingle = "";
|
|
22765
|
+
let bare = "";
|
|
22766
|
+
let bareWithMarks = "";
|
|
22767
|
+
for (let i = 0;i < lx.text.length; i++) {
|
|
22768
|
+
const ch = lx.text[i];
|
|
22769
|
+
if (lx.role[i] === 1 /* QuoteMark */) {
|
|
22770
|
+
bareWithMarks += ch;
|
|
22771
|
+
if (ch === '"' && keepDoubleMarks)
|
|
22772
|
+
outsideSingle += ch;
|
|
22773
|
+
continue;
|
|
22774
|
+
}
|
|
22775
|
+
if (lx.quoting[i] === 1 /* Single */)
|
|
22776
|
+
continue;
|
|
22777
|
+
outsideSingle += ch;
|
|
22778
|
+
if (lx.quoting[i] === 0 /* None */) {
|
|
22779
|
+
bare += ch;
|
|
22780
|
+
bareWithMarks += ch;
|
|
22781
|
+
}
|
|
22782
|
+
}
|
|
22783
|
+
return { outsideSingle, bare, bareWithMarks };
|
|
22784
|
+
}
|
|
22785
|
+
function wordSpans(lx) {
|
|
22786
|
+
const spans = [];
|
|
22787
|
+
let start = -1;
|
|
22788
|
+
for (let i = 0;i <= lx.text.length; i++) {
|
|
22789
|
+
const cut = i === lx.text.length || isBare(lx, i) && isBlank(lx.text[i]);
|
|
22790
|
+
if (cut) {
|
|
22791
|
+
if (start !== -1)
|
|
22792
|
+
spans.push({ start, end: i });
|
|
22793
|
+
start = -1;
|
|
22794
|
+
} else if (start === -1)
|
|
22795
|
+
start = i;
|
|
22796
|
+
}
|
|
22797
|
+
return spans;
|
|
22798
|
+
}
|
|
22799
|
+
function withoutHarmlessRedirections(view) {
|
|
22800
|
+
const drop = new Uint8Array(view.length);
|
|
22801
|
+
const markFrom = (from, to) => {
|
|
22802
|
+
for (let k = from;k < to; k++)
|
|
22803
|
+
drop[k] = 1;
|
|
22804
|
+
};
|
|
22805
|
+
const skipBlanks = (k) => {
|
|
22806
|
+
while (isBlank(view[k]))
|
|
22807
|
+
k++;
|
|
22808
|
+
return k;
|
|
22809
|
+
};
|
|
22810
|
+
const endsWord = (k) => k === view.length || isBlank(view[k]);
|
|
22811
|
+
const devNullAt = (k) => view.startsWith("/dev/null", k) && endsWord(k + 9) ? k + 9 : -1;
|
|
22812
|
+
for (let i = 0;i < view.length; i++) {
|
|
22813
|
+
const ch = view[i];
|
|
22814
|
+
if (ch === "<") {
|
|
22815
|
+
const end = devNullAt(skipBlanks(i + 1));
|
|
22816
|
+
if (end !== -1)
|
|
22817
|
+
markFrom(i, end);
|
|
22818
|
+
} else if (ch === ">" && view[i + 1] === "&") {
|
|
22819
|
+
const one = skipBlanks(i + 2);
|
|
22820
|
+
let two = i - 1;
|
|
22821
|
+
while (two >= 0 && isBlank(view[two]))
|
|
22822
|
+
two--;
|
|
22823
|
+
if (view[one] === "1" && endsWord(one + 1) && view[two] === "2" && isBlank(view[two - 1]))
|
|
22824
|
+
markFrom(two, one + 1);
|
|
22825
|
+
} else if (ch === ">") {
|
|
22826
|
+
const end = devNullAt(skipBlanks(i + 1));
|
|
22827
|
+
if (end !== -1)
|
|
22828
|
+
markFrom(i, end);
|
|
22829
|
+
}
|
|
22830
|
+
}
|
|
22831
|
+
let out = "";
|
|
22832
|
+
for (let i = 0;i < view.length; i++)
|
|
22833
|
+
if (drop[i] === 0)
|
|
22834
|
+
out += view[i];
|
|
22835
|
+
return out;
|
|
22836
|
+
}
|
|
22837
|
+
var CONTROL_CHARACTERS = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/;
|
|
22838
|
+
var UNICODE_WHITESPACE = /[\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]/;
|
|
22839
|
+
function singleQuoteEndsInBackslash(lx) {
|
|
22840
|
+
let lastSingleQuote = -1;
|
|
22841
|
+
for (let i = lx.text.length - 1;i >= 0; i--) {
|
|
22842
|
+
if (lx.text[i] === "'") {
|
|
22843
|
+
lastSingleQuote = i;
|
|
22844
|
+
break;
|
|
22845
|
+
}
|
|
22846
|
+
}
|
|
22847
|
+
let inside = false;
|
|
22848
|
+
let trailing = 0;
|
|
22849
|
+
for (let i = 0;i < lx.text.length; i++) {
|
|
22850
|
+
if (lx.quoting[i] !== 1 /* Single */)
|
|
22851
|
+
continue;
|
|
22852
|
+
if (lx.role[i] === 1 /* QuoteMark */) {
|
|
22853
|
+
if (inside && (trailing % 2 === 1 || trailing > 0 && lastSingleQuote > i))
|
|
22854
|
+
return true;
|
|
22855
|
+
inside = !inside;
|
|
22856
|
+
trailing = 0;
|
|
22857
|
+
continue;
|
|
22858
|
+
}
|
|
22859
|
+
trailing = lx.text[i] === "\\" ? trailing + 1 : 0;
|
|
22860
|
+
}
|
|
22861
|
+
return false;
|
|
22862
|
+
}
|
|
22863
|
+
var MIDWAY_OPENINGS = ["-", ";", ">", "<", "&&", "||"];
|
|
22864
|
+
function startsMidway(text) {
|
|
22865
|
+
const body = text.trimStart();
|
|
22866
|
+
const indentation = text.slice(0, text.length - body.length);
|
|
22867
|
+
return indentation.includes("\t") || MIDWAY_OPENINGS.some((opening) => body.startsWith(opening));
|
|
22868
|
+
}
|
|
22869
|
+
function jqReachesBeyondItsFilter(text, base) {
|
|
22870
|
+
if (base !== "jq")
|
|
22871
|
+
return false;
|
|
22872
|
+
for (let at = text.indexOf("system");at !== -1; at = text.indexOf("system", at + 1)) {
|
|
22873
|
+
if (at > 0 && /\w/.test(text[at - 1]))
|
|
22874
|
+
continue;
|
|
22875
|
+
let k = at + 6;
|
|
22876
|
+
while (isBlank(text[k]))
|
|
22877
|
+
k++;
|
|
22878
|
+
if (text[k] === "(")
|
|
22879
|
+
return true;
|
|
22880
|
+
}
|
|
22881
|
+
const words = text.split(/\s+/).slice(1);
|
|
22882
|
+
return words.some((word) => {
|
|
22883
|
+
if (["--from-file", "--rawfile", "--slurpfile", "--library-path"].some((long) => word.startsWith(long)))
|
|
22884
|
+
return true;
|
|
22885
|
+
if (!word.startsWith("-") || word.startsWith("--"))
|
|
22886
|
+
return false;
|
|
22887
|
+
const letters = /^-([A-Za-z]*)/.exec(word)[1];
|
|
22888
|
+
return letters.includes("f") || letters.includes("L");
|
|
22889
|
+
});
|
|
22890
|
+
}
|
|
22891
|
+
var QUOTE_MARK = /['"]/;
|
|
22892
|
+
var GLUED_QUOTED_VALUE_OPTION = { cut: "-d" };
|
|
22893
|
+
function quoteInsideFlagName(text, start, base) {
|
|
22894
|
+
let end = start;
|
|
22895
|
+
while (end < text.length && !isBlank(text[end]) && text[end] !== "=")
|
|
22896
|
+
end++;
|
|
22897
|
+
const head = text.slice(start, end);
|
|
22898
|
+
const mark = head.search(/['"]/);
|
|
22899
|
+
if (mark === -1)
|
|
22900
|
+
return false;
|
|
22901
|
+
if (Object.hasOwn(GLUED_QUOTED_VALUE_OPTION, base) && GLUED_QUOTED_VALUE_OPTION[base] === head.slice(0, mark))
|
|
22902
|
+
return false;
|
|
22903
|
+
const follower = text[start + mark + 1];
|
|
22904
|
+
return follower === undefined || /[\w'"-]/.test(follower);
|
|
22905
|
+
}
|
|
22906
|
+
function quoteRunNearDash(text) {
|
|
22907
|
+
for (const run of text.matchAll(/['"]+/g)) {
|
|
22908
|
+
const before = text[run.index - 1];
|
|
22909
|
+
const after = run.index + run[0].length;
|
|
22910
|
+
const opensWord = before === undefined || isBlank(before);
|
|
22911
|
+
let solid = after;
|
|
22912
|
+
while (isBlank(text[solid]))
|
|
22913
|
+
solid++;
|
|
22914
|
+
if (run[0].length >= 2 && (opensWord || before === "$") && text[solid] === "-")
|
|
22915
|
+
return true;
|
|
22916
|
+
if (run[0].length >= 3 && (opensWord || text[after] === "-"))
|
|
22917
|
+
return true;
|
|
22918
|
+
}
|
|
22919
|
+
return false;
|
|
22920
|
+
}
|
|
22921
|
+
function flagSpelledWithQuotes(lx, base) {
|
|
22922
|
+
const text = lx.text;
|
|
22923
|
+
if (base === "echo" && !/[|&;]/.test(text))
|
|
22924
|
+
return false;
|
|
22925
|
+
if (text.includes("$'") || text.includes('$"') || quoteRunNearDash(text))
|
|
22926
|
+
return true;
|
|
22927
|
+
return wordSpans(lx).some(({ start, end }) => {
|
|
22928
|
+
if (lx.role[start] === 1 /* QuoteMark */)
|
|
22929
|
+
return dequoteShellWord(text.slice(start, end)).startsWith("-");
|
|
22930
|
+
return text[start] === "-" && quoteInsideFlagName(text, start, base);
|
|
22931
|
+
});
|
|
22932
|
+
}
|
|
22933
|
+
function nextQuoteMark(s, from) {
|
|
22934
|
+
for (let k = from;k < s.length; k++)
|
|
22935
|
+
if (s[k] === "'" || s[k] === '"')
|
|
22936
|
+
return k;
|
|
22937
|
+
return -1;
|
|
22938
|
+
}
|
|
22939
|
+
function separatorInsideQuoteMarks(outsideSingle) {
|
|
22940
|
+
const s = outsideSingle;
|
|
22941
|
+
const spanHas = (open, chars, mustEndWord) => {
|
|
22942
|
+
const close = nextQuoteMark(s, open + 1);
|
|
22943
|
+
if (close === -1)
|
|
22944
|
+
return false;
|
|
22945
|
+
if (mustEndWord && !(close + 1 === s.length || isBlank(s[close + 1])))
|
|
22946
|
+
return false;
|
|
22947
|
+
for (let k = open + 1;k < close; k++)
|
|
22948
|
+
if (chars.includes(s[k]))
|
|
22949
|
+
return true;
|
|
22950
|
+
return false;
|
|
22951
|
+
};
|
|
22952
|
+
for (let i = 0;i < s.length; i++) {
|
|
22953
|
+
if ((s[i] === "'" || s[i] === '"') && (i === 0 || isBlank(s[i - 1])) && spanHas(i, ";&", true))
|
|
22954
|
+
return true;
|
|
22955
|
+
}
|
|
22956
|
+
for (const [predicate, chars] of [["-name", ";|&"], ["-path", ";|&"], ["-iname", ";|&"], ["-regex", ";&"]]) {
|
|
22957
|
+
for (let at = s.indexOf(predicate);at !== -1; at = s.indexOf(predicate, at + 1)) {
|
|
22958
|
+
let k = at + predicate.length;
|
|
22959
|
+
if (!isBlank(s[k]))
|
|
22960
|
+
continue;
|
|
22961
|
+
while (isBlank(s[k]))
|
|
22962
|
+
k++;
|
|
22963
|
+
if ((s[k] === "'" || s[k] === '"') && spanHas(k, chars, false))
|
|
22964
|
+
return true;
|
|
22965
|
+
}
|
|
22966
|
+
}
|
|
22967
|
+
return false;
|
|
22968
|
+
}
|
|
22969
|
+
function variableBesideRedirectionOrPipe(view) {
|
|
22970
|
+
const solidBefore = [];
|
|
22971
|
+
let last;
|
|
22972
|
+
for (let i = 0;i < view.length; i++) {
|
|
22973
|
+
solidBefore.push(last);
|
|
22974
|
+
if (!isBlank(view[i]))
|
|
22975
|
+
last = view[i];
|
|
22976
|
+
}
|
|
22977
|
+
const solidFrom = new Array(view.length + 1);
|
|
22978
|
+
for (let i = view.length - 1;i >= 0; i--)
|
|
22979
|
+
solidFrom[i] = isBlank(view[i]) ? solidFrom[i + 1] : view[i];
|
|
22980
|
+
const isRouting = (ch) => ch === "<" || ch === ">" || ch === "|";
|
|
22981
|
+
for (const match of view.matchAll(/\$[A-Za-z_]\w*/g)) {
|
|
22982
|
+
if (isRouting(solidBefore[match.index]) || isRouting(solidFrom[match.index + match[0].length]))
|
|
22983
|
+
return true;
|
|
22984
|
+
}
|
|
22985
|
+
return false;
|
|
22986
|
+
}
|
|
22987
|
+
function commentHoldsQuoteMark(lx) {
|
|
22988
|
+
let inComment = false;
|
|
22989
|
+
for (let i = 0;i < lx.text.length; i++) {
|
|
22990
|
+
const ch = lx.text[i];
|
|
22991
|
+
if (inComment) {
|
|
22992
|
+
if (ch === `
|
|
22993
|
+
`)
|
|
22994
|
+
inComment = false;
|
|
22995
|
+
else if (ch === "'" || ch === '"')
|
|
22996
|
+
return true;
|
|
22997
|
+
continue;
|
|
22998
|
+
}
|
|
22999
|
+
if (ch === "#" && isBare(lx, i))
|
|
23000
|
+
inComment = true;
|
|
23001
|
+
}
|
|
23002
|
+
return false;
|
|
23003
|
+
}
|
|
23004
|
+
function quotedNewlineBeforeCommentLine(lx) {
|
|
23005
|
+
if (!lx.text.includes(`
|
|
23006
|
+
`) || !lx.text.includes("#"))
|
|
23007
|
+
return false;
|
|
23008
|
+
for (let i = 0;i < lx.text.length; i++) {
|
|
23009
|
+
if (lx.text[i] !== `
|
|
23010
|
+
` || lx.quoting[i] === 0 /* None */ || lx.role[i] !== 0 /* Text */)
|
|
23011
|
+
continue;
|
|
23012
|
+
let k = i + 1;
|
|
23013
|
+
while (k < lx.text.length && lx.text[k] !== `
|
|
23014
|
+
` && isBlank(lx.text[k]))
|
|
23015
|
+
k++;
|
|
23016
|
+
if (lx.text[k] === "#")
|
|
23017
|
+
return true;
|
|
23018
|
+
}
|
|
23019
|
+
return false;
|
|
23020
|
+
}
|
|
23021
|
+
function lineBreakStartsCommand(bare) {
|
|
23022
|
+
let lastNonBlank = -1;
|
|
23023
|
+
for (let i = bare.length - 1;i >= 0; i--) {
|
|
23024
|
+
if (!isBlank(bare[i])) {
|
|
23025
|
+
lastNonBlank = i;
|
|
23026
|
+
break;
|
|
23027
|
+
}
|
|
23028
|
+
}
|
|
23029
|
+
for (let i = 0;i < lastNonBlank; i++) {
|
|
23030
|
+
if (bare[i] !== `
|
|
23031
|
+
` && bare[i] !== "\r")
|
|
23032
|
+
continue;
|
|
23033
|
+
const continuation = i >= 2 && bare[i - 1] === "\\" && isBlank(bare[i - 2]);
|
|
23034
|
+
if (!continuation)
|
|
23035
|
+
return true;
|
|
23036
|
+
}
|
|
23037
|
+
return false;
|
|
23038
|
+
}
|
|
23039
|
+
function mentionsIfs(text) {
|
|
23040
|
+
if (text.includes("$IFS"))
|
|
23041
|
+
return true;
|
|
23042
|
+
return text.split("}").some((stretch) => {
|
|
23043
|
+
const open = stretch.indexOf("${");
|
|
23044
|
+
return open !== -1 && stretch.includes("IFS", open + 2);
|
|
23045
|
+
});
|
|
23046
|
+
}
|
|
23047
|
+
function readsProcessEnvironment(text) {
|
|
23048
|
+
return text.split(/[\n\r\u2028\u2029]/).some((line) => {
|
|
23049
|
+
const proc = line.indexOf("/proc/");
|
|
23050
|
+
return proc !== -1 && line.includes("/environ", proc + "/proc/".length);
|
|
23051
|
+
});
|
|
23052
|
+
}
|
|
23053
|
+
function hasLiveBacktick(lx) {
|
|
23054
|
+
for (let i = 0;i < lx.text.length; i++) {
|
|
23055
|
+
if (lx.text[i] === "`" && lx.quoting[i] !== 1 /* Single */ && lx.role[i] !== 3 /* Escaped */)
|
|
23056
|
+
return true;
|
|
23057
|
+
}
|
|
23058
|
+
return false;
|
|
23059
|
+
}
|
|
23060
|
+
function escapesBlankOrOperator(lx) {
|
|
23061
|
+
for (let i = 0;i < lx.text.length; i++) {
|
|
23062
|
+
if (lx.role[i] !== 2 /* Escape */ || lx.quoting[i] !== 0 /* None */)
|
|
23063
|
+
continue;
|
|
23064
|
+
const next = lx.text[i + 1];
|
|
23065
|
+
if (next === " " || next === "\t" || ";|&<>".includes(next))
|
|
23066
|
+
return true;
|
|
23067
|
+
}
|
|
23068
|
+
return false;
|
|
23069
|
+
}
|
|
23070
|
+
function hashInsideWord(bareWithMarks) {
|
|
23071
|
+
const glued = (s) => s.split(/\s+/).some((word) => {
|
|
23072
|
+
for (let at = word.indexOf("#", 1);at !== -1; at = word.indexOf("#", at + 1)) {
|
|
23073
|
+
if (!word.slice(0, at).endsWith("${"))
|
|
23074
|
+
return true;
|
|
23075
|
+
}
|
|
23076
|
+
return false;
|
|
23077
|
+
});
|
|
23078
|
+
return glued(bareWithMarks) || glued(joinLineContinuations(bareWithMarks));
|
|
23079
|
+
}
|
|
23080
|
+
function hasBraceExpansion(bare, text) {
|
|
23081
|
+
const events = [];
|
|
23082
|
+
let run = 0;
|
|
23083
|
+
for (let i = 0;i < bare.length; i++) {
|
|
23084
|
+
const ch = bare[i];
|
|
23085
|
+
const escaped = run % 2 === 1;
|
|
23086
|
+
run = ch === "\\" ? run + 1 : 0;
|
|
23087
|
+
if ((ch === "{" || ch === "}") && !escaped)
|
|
23088
|
+
events.push(ch === "{" ? "open" : "close");
|
|
23089
|
+
else if (ch === "," || ch === "." && bare[i + 1] === ".")
|
|
23090
|
+
events.push("separator");
|
|
23091
|
+
}
|
|
23092
|
+
const opens = events.filter((e) => e === "open").length;
|
|
23093
|
+
const closes = events.filter((e) => e === "close").length;
|
|
23094
|
+
if (opens > 0 && closes > opens)
|
|
23095
|
+
return true;
|
|
23096
|
+
const owner = [];
|
|
23097
|
+
const ownsSeparator = new Set;
|
|
23098
|
+
for (const [id, event] of events.entries()) {
|
|
23099
|
+
if (event === "open")
|
|
23100
|
+
owner.push(id);
|
|
23101
|
+
else if (event === "separator") {
|
|
23102
|
+
if (owner.length > 0)
|
|
23103
|
+
ownsSeparator.add(owner[owner.length - 1]);
|
|
23104
|
+
} else if (owner.length > 0 && ownsSeparator.has(owner.pop()))
|
|
23105
|
+
return true;
|
|
23106
|
+
}
|
|
23107
|
+
if (opens === 0)
|
|
23108
|
+
return false;
|
|
23109
|
+
for (let i = 0;i + 2 < text.length; i++) {
|
|
23110
|
+
if ((text[i + 1] === "{" || text[i + 1] === "}") && QUOTE_MARK.test(text[i]) && QUOTE_MARK.test(text[i + 2]))
|
|
23111
|
+
return true;
|
|
23112
|
+
}
|
|
23113
|
+
return false;
|
|
23114
|
+
}
|
|
23115
|
+
var ZSH_DANGEROUS_COMMANDS = new Set([
|
|
23116
|
+
"zmodload",
|
|
23117
|
+
"emulate",
|
|
23118
|
+
"sysopen",
|
|
23119
|
+
"sysread",
|
|
23120
|
+
"syswrite",
|
|
23121
|
+
"sysseek",
|
|
23122
|
+
"zpty",
|
|
23123
|
+
"ztcp",
|
|
23124
|
+
"zsocket",
|
|
23125
|
+
"mapfile",
|
|
23126
|
+
"zf_rm",
|
|
23127
|
+
"zf_mv",
|
|
23128
|
+
"zf_ln",
|
|
23129
|
+
"zf_chmod",
|
|
23130
|
+
"zf_chown",
|
|
23131
|
+
"zf_mkdir",
|
|
23132
|
+
"zf_rmdir",
|
|
23133
|
+
"zf_chgrp"
|
|
23134
|
+
]);
|
|
23135
|
+
var ZSH_PRECOMMAND_MODIFIERS = new Set(["command", "builtin", "noglob", "nocorrect"]);
|
|
23136
|
+
var PROGRAM_AFTER_PREFIXES = new RegExp(`^\\s*(?:(?:[A-Za-z_]\\w*=\\S*|${[...ZSH_PRECOMMAND_MODIFIERS].join("|")})\\s+)*(\\S+)([\\s\\S]*)$`);
|
|
23137
|
+
function runsZshBuiltin(text) {
|
|
23138
|
+
const named = PROGRAM_AFTER_PREFIXES.exec(text);
|
|
23139
|
+
if (named === null)
|
|
23140
|
+
return false;
|
|
23141
|
+
const [, program, rest] = named;
|
|
23142
|
+
if (ZSH_DANGEROUS_COMMANDS.has(program))
|
|
23143
|
+
return true;
|
|
23144
|
+
return program === "fc" && rest.split(/\s+/).some((option) => option[0] === "-" && option.indexOf("e", 1) !== -1);
|
|
23145
|
+
}
|
|
23146
|
+
var occurrences = (s, ch) => {
|
|
23147
|
+
let n = 0;
|
|
23148
|
+
for (const c of s)
|
|
23149
|
+
if (c === ch)
|
|
23150
|
+
n++;
|
|
23151
|
+
return n;
|
|
23152
|
+
};
|
|
23153
|
+
var unescapedOccurrences = (s, ch) => {
|
|
23154
|
+
let n = 0;
|
|
23155
|
+
for (let i = 0;i < s.length; i++)
|
|
23156
|
+
if (s[i] === ch && s[i - 1] !== "\\")
|
|
23157
|
+
n++;
|
|
23158
|
+
return n;
|
|
23159
|
+
};
|
|
23160
|
+
function unbalancedWordNearSeparator(lx, bare) {
|
|
23161
|
+
if (!(bare.includes(";") || bare.includes("&&") || bare.includes("||")))
|
|
23162
|
+
return false;
|
|
23163
|
+
if (lx.unterminated)
|
|
23164
|
+
return true;
|
|
23165
|
+
let start = -1;
|
|
23166
|
+
for (let i = 0;i <= lx.text.length; i++) {
|
|
23167
|
+
const cut = i === lx.text.length || isBare(lx, i) && (isBlank(lx.text[i]) || ";&|<>()".includes(lx.text[i]));
|
|
23168
|
+
if (!cut) {
|
|
23169
|
+
if (start === -1)
|
|
23170
|
+
start = i;
|
|
23171
|
+
continue;
|
|
23172
|
+
}
|
|
23173
|
+
if (start === -1)
|
|
23174
|
+
continue;
|
|
23175
|
+
const word = shellWords(lx.text.slice(start, i), false, "broad")[0]?.word ?? "";
|
|
23176
|
+
start = -1;
|
|
23177
|
+
if (occurrences(word, "{") !== occurrences(word, "}") || occurrences(word, "(") !== occurrences(word, ")") || occurrences(word, "[") !== occurrences(word, "]") || unescapedOccurrences(word, '"') % 2 !== 0 || unescapedOccurrences(word, "'") % 2 !== 0) {
|
|
23178
|
+
return true;
|
|
23179
|
+
}
|
|
23180
|
+
}
|
|
23181
|
+
return false;
|
|
23182
|
+
}
|
|
23183
|
+
var SUBSTITUTION_PATTERNS = [
|
|
23184
|
+
/<\(/,
|
|
23185
|
+
/>\(/,
|
|
23186
|
+
/=\(/,
|
|
23187
|
+
/(?:^|[\s;&|])=[a-zA-Z_]/,
|
|
23188
|
+
/\$\(/,
|
|
23189
|
+
/\$\{/,
|
|
23190
|
+
/\$\[/,
|
|
23191
|
+
/~\[/,
|
|
23192
|
+
/\(e:/,
|
|
23193
|
+
/\(\+/,
|
|
23194
|
+
/\}\s*always\s*\{/,
|
|
23195
|
+
/<#/
|
|
23196
|
+
];
|
|
23197
|
+
var PRE_CHECKS = {
|
|
23198
|
+
unreadable: [
|
|
23199
|
+
(s) => s.text.includes("\r"),
|
|
23200
|
+
(s) => CONTROL_CHARACTERS.test(s.text) || UNICODE_WHITESPACE.test(s.text),
|
|
23201
|
+
(s) => startsMidway(s.text)
|
|
23202
|
+
],
|
|
23203
|
+
hidesAWord: [
|
|
23204
|
+
(s) => flagSpelledWithQuotes(s.lx, s.base),
|
|
23205
|
+
(s) => hashInsideWord(s.bareWithMarks),
|
|
23206
|
+
(s) => commentHoldsQuoteMark(s.lx),
|
|
23207
|
+
(s) => quotedNewlineBeforeCommentLine(s.lx),
|
|
23208
|
+
(s) => singleQuoteEndsInBackslash(s.lx),
|
|
23209
|
+
(s) => unbalancedWordNearSeparator(s.lx, s.bare)
|
|
23210
|
+
],
|
|
23211
|
+
smugglesAnOperator: [
|
|
23212
|
+
(s) => lineBreakStartsCommand(s.bare),
|
|
23213
|
+
(s) => s.cleaned.includes("<") || s.cleaned.includes(">"),
|
|
23214
|
+
(s) => variableBesideRedirectionOrPipe(s.cleaned),
|
|
23215
|
+
(s) => escapesBlankOrOperator(s.lx),
|
|
23216
|
+
(s) => separatorInsideQuoteMarks(s.outsideSingle)
|
|
23217
|
+
],
|
|
23218
|
+
expandsAtRunTime: [
|
|
23219
|
+
(s) => hasLiveBacktick(s.lx),
|
|
23220
|
+
(s) => SUBSTITUTION_PATTERNS.some((pattern) => pattern.test(s.outsideSingle)),
|
|
23221
|
+
(s) => hasBraceExpansion(s.bare, s.text),
|
|
23222
|
+
(s) => mentionsIfs(s.text)
|
|
23223
|
+
],
|
|
23224
|
+
reachesBeyondItsArguments: [
|
|
23225
|
+
(s) => jqReachesBeyondItsFilter(s.text, s.base),
|
|
23226
|
+
(s) => runsZshBuiltin(s.text),
|
|
23227
|
+
(s) => readsProcessEnvironment(s.text)
|
|
23228
|
+
]
|
|
23229
|
+
};
|
|
23230
|
+
function passesSecurityValidators(command) {
|
|
23231
|
+
const program = /^[^ ]*/.exec(command)[0];
|
|
23232
|
+
const lx = lex(command);
|
|
23233
|
+
const views = viewsOf(lx, /^jq$/.test(program));
|
|
23234
|
+
const scanned = { ...views, text: command, lx, base: program, cleaned: withoutHarmlessRedirections(views.bare) };
|
|
23235
|
+
return Object.values(PRE_CHECKS).every((group) => group.every((fires) => !fires(scanned)));
|
|
23236
|
+
}
|
|
23237
|
+
var PARAMETER_START = /[A-Za-z_@*#?!$0-9-]/;
|
|
23238
|
+
function expandsWhenRun(text) {
|
|
23239
|
+
const lx = lex(text);
|
|
23240
|
+
for (let i = 0;i < text.length; i++) {
|
|
23241
|
+
if (lx.role[i] !== 0 /* Text */)
|
|
23242
|
+
continue;
|
|
23243
|
+
const ch = text[i];
|
|
23244
|
+
if (lx.quoting[i] === 0 /* None */ && (ch === "*" || ch === "?" || ch === "[" || ch === "]"))
|
|
23245
|
+
return true;
|
|
23246
|
+
const next = text[i + 1];
|
|
23247
|
+
if (ch === "$" && lx.quoting[i] !== 1 /* Single */ && next !== undefined && PARAMETER_START.test(next))
|
|
23248
|
+
return true;
|
|
23249
|
+
}
|
|
23250
|
+
return false;
|
|
23251
|
+
}
|
|
23252
|
+
function takesPatterns(simple) {
|
|
23253
|
+
const [first, second] = simple.words.map((w) => w.value);
|
|
23254
|
+
return ["grep", "rg", "fd", "fdfind", "find", "sed"].includes(first ?? "") || first === "git" && second === "grep";
|
|
23255
|
+
}
|
|
23256
|
+
function keptBackslashMisleads(simple) {
|
|
23257
|
+
const patterns = takesPatterns(simple);
|
|
23258
|
+
return simple.words.some((word) => {
|
|
23259
|
+
if (!word.value.startsWith("\\"))
|
|
23260
|
+
return false;
|
|
23261
|
+
const broad = shellWords(word.raw, false, "broad")[0]?.word ?? "";
|
|
23262
|
+
if (broad.startsWith("\\"))
|
|
23263
|
+
return false;
|
|
23264
|
+
const after = word.value[1];
|
|
23265
|
+
return !patterns || after !== undefined && "-+{}".includes(after);
|
|
23266
|
+
});
|
|
23267
|
+
}
|
|
23268
|
+
var GIT_CONFIGURING_OPTION = /\s(?:-c|--exec-path|--config-env)[\s=]/;
|
|
23269
|
+
function matchesReadOnlyPattern(simple) {
|
|
23270
|
+
if (simple.words.some((w) => w.value.startsWith("-") && w.raw.includes("\\")))
|
|
23271
|
+
return false;
|
|
23272
|
+
const matched = READ_ONLY_REGEXES.some((regex) => regex.test(simple.text)) || findOnlyLists(simple);
|
|
23273
|
+
return matched && !(simple.text.includes("git") && GIT_CONFIGURING_OPTION.test(simple.text));
|
|
23274
|
+
}
|
|
23275
|
+
function isSimpleCommandReadOnly(simple, platform) {
|
|
23276
|
+
const refused = containsVulnerableUncPath(simple.text, platform) || expandsWhenRun(simple.text) || keptBackslashMisleads(simple);
|
|
23277
|
+
return !refused && (isSafeViaFlagAllowlist(simple, platform) || matchesReadOnlyPattern(simple));
|
|
23278
|
+
}
|
|
23279
|
+
var takes = (kind, ...names) => Object.fromEntries(names.map((name) => [name, kind]));
|
|
23280
|
+
var GIT_REF_SELECTION = takes("none", "--all", "--branches", "--tags", "--remotes");
|
|
23281
|
+
var GIT_DATE_FILTERS = takes("string", "--since", "--after", "--until", "--before");
|
|
23282
|
+
var GIT_LOG_DISPLAY = { ...takes("none", "--oneline", "--graph", "--decorate", "--no-decorate", "--relative-date"), ...takes("string", "--date") };
|
|
23283
|
+
var GIT_COUNT = takes("number", "--max-count", "-n");
|
|
23284
|
+
var GIT_STAT = takes("none", "--stat", "--numstat", "--shortstat", "--name-only", "--name-status");
|
|
23285
|
+
var GIT_COLOR = takes("none", "--color", "--no-color");
|
|
23286
|
+
var GIT_PATCH = takes("none", "--patch", "-p", "--no-patch", "--no-ext-diff", "-s");
|
|
23287
|
+
var GIT_AUTHOR_FILTERS = takes("string", "--author", "--committer", "--grep");
|
|
23288
|
+
var REFLOG_WRITING_SUBCOMMANDS = new Set(["expire", "delete", "exists"]);
|
|
23289
|
+
var reflogWrites = (_text, args) => args.some((arg) => REFLOG_WRITING_SUBCOMMANDS.has(arg));
|
|
23290
|
+
function namesNewRef(args, flags, optionalValue) {
|
|
23291
|
+
let listing = false;
|
|
23292
|
+
let optionsOver = false;
|
|
23293
|
+
let lastOption = "";
|
|
23294
|
+
for (let i = 0;i < args.length; i++) {
|
|
23295
|
+
const token = args[i];
|
|
23296
|
+
if (token === "")
|
|
23297
|
+
continue;
|
|
23298
|
+
const word = optionsOver ? { form: "operand" } : readOptionWord(token);
|
|
23299
|
+
if (word.form === "end-of-options") {
|
|
23300
|
+
optionsOver = true;
|
|
23301
|
+
lastOption = "";
|
|
23302
|
+
} else if (word.form === "operand") {
|
|
23303
|
+
if (!listing && !optionalValue.has(lastOption))
|
|
23304
|
+
return true;
|
|
23305
|
+
} else {
|
|
23306
|
+
lastOption = word.form === "long" ? word.name : `-${word.letters}`;
|
|
23307
|
+
if (word.inline !== undefined)
|
|
23308
|
+
continue;
|
|
23309
|
+
if (lastOption === "--list" || word.form === "short" && word.letters.includes("l"))
|
|
23310
|
+
listing = true;
|
|
23311
|
+
const kind = kindOf(flags, lastOption);
|
|
23312
|
+
if (kind === "number" || kind === "string" || kind === "char")
|
|
23313
|
+
i++;
|
|
23314
|
+
}
|
|
23315
|
+
}
|
|
23316
|
+
return false;
|
|
23317
|
+
}
|
|
23318
|
+
var BRANCH_OPTIONAL_COMMIT = new Set(["--merged", "--no-merged"]);
|
|
23319
|
+
var GIT_TAG_FLAGS = {
|
|
23320
|
+
...takes("none", "-l", "--list", "--column", "--no-column", "-i", "--ignore-case"),
|
|
23321
|
+
...takes("number", "-n"),
|
|
23322
|
+
...takes("string", "--contains", "--no-contains", "--merged", "--no-merged", "--sort", "--format", "--points-at")
|
|
23323
|
+
};
|
|
23324
|
+
var GIT_BRANCH_FLAGS = {
|
|
23325
|
+
...takes("none", "-l", "--list", "-a", "--all", "-r", "--remotes", "-v", "-vv", "--verbose", "--color", "--no-color", "--column", "--no-column", "--no-abbrev", "--merged", "--no-merged", "--show-current", "-i", "--ignore-case"),
|
|
23326
|
+
...takes("attached", "--abbrev"),
|
|
23327
|
+
...takes("string", "--contains", "--no-contains", "--points-at", "--sort")
|
|
23328
|
+
};
|
|
23329
|
+
var BASE64_FLAGS = {
|
|
23330
|
+
...takes("none", "-d", "-D", "--decode", "--ignore-garbage", "-h", "--help", "--version"),
|
|
23331
|
+
...takes("number", "-b", "--break", "-w", "--wrap"),
|
|
23332
|
+
...takes("string", "-i", "--input")
|
|
23333
|
+
};
|
|
23334
|
+
var DATE_FLAGS = {
|
|
23335
|
+
...takes("string", "-d", "--date", "-r", "--reference"),
|
|
23336
|
+
...takes("attached", "--iso-8601", "--rfc-3339"),
|
|
23337
|
+
...takes("none", "-u", "--utc", "--universal", "-I", "-R", "--rfc-email", "--debug", "--help", "--version")
|
|
23338
|
+
};
|
|
23339
|
+
function dateSetsClock(_text, args) {
|
|
23340
|
+
return operandsOf(args, DATE_FLAGS).some((operand) => !operand.startsWith("+"));
|
|
23341
|
+
}
|
|
23342
|
+
var TPUT_DANGEROUS_CAPABILITIES = new Set([
|
|
23343
|
+
"init",
|
|
23344
|
+
"reset",
|
|
23345
|
+
"rs1",
|
|
23346
|
+
"rs2",
|
|
23347
|
+
"rs3",
|
|
23348
|
+
"is1",
|
|
23349
|
+
"is2",
|
|
23350
|
+
"is3",
|
|
23351
|
+
"iprog",
|
|
23352
|
+
"if",
|
|
23353
|
+
"rf",
|
|
23354
|
+
"clear",
|
|
23355
|
+
"flash",
|
|
23356
|
+
"mc0",
|
|
23357
|
+
"mc4",
|
|
23358
|
+
"mc5",
|
|
23359
|
+
"mc5i",
|
|
23360
|
+
"mc5p",
|
|
23361
|
+
"pfkey",
|
|
23362
|
+
"pfloc",
|
|
23363
|
+
"pfx",
|
|
23364
|
+
"pfxl",
|
|
23365
|
+
"smcup",
|
|
23366
|
+
"rmcup"
|
|
23367
|
+
]);
|
|
23368
|
+
var TPUT_FLAGS = { ...takes("string", "-T"), ...takes("none", "-V", "-x") };
|
|
23369
|
+
function tputChangesTerminal(_text, args) {
|
|
23370
|
+
const { options, operands } = partitionArguments(args, TPUT_FLAGS);
|
|
23371
|
+
const readsStdin = options.some((option) => !option.startsWith("--") && option.split("=")[0].includes("S"));
|
|
23372
|
+
return readsStdin || operands.some((operand) => TPUT_DANGEROUS_CAPABILITIES.has(operand));
|
|
23373
|
+
}
|
|
23374
|
+
var REMOTE_NAME = /^[a-zA-Z0-9_-]+$/;
|
|
23375
|
+
function remoteShowReachesBeyondOneRemote(_text, args) {
|
|
23376
|
+
let names = 0;
|
|
23377
|
+
for (const arg of args) {
|
|
23378
|
+
if (arg === "-n")
|
|
23379
|
+
continue;
|
|
23380
|
+
if (!REMOTE_NAME.test(arg))
|
|
23381
|
+
return true;
|
|
23382
|
+
names++;
|
|
23383
|
+
}
|
|
23384
|
+
return names !== 1;
|
|
23385
|
+
}
|
|
23386
|
+
var REMOTE_LISTING_OPTIONS = new Set(["-v", "--verbose"]);
|
|
23387
|
+
var remoteDoesMoreThanList = (_text, args) => !args.every((arg) => REMOTE_LISTING_OPTIONS.has(arg));
|
|
23388
|
+
var psPrintsEnvironments = (_text, args) => args.some((arg) => /^[a-zA-Z]+$/.test(arg) && arg.includes("e"));
|
|
23389
|
+
var lsofWritesMountSupplement = (_text, args) => args.some((arg) => arg.slice(0, 2) === "+m");
|
|
23390
|
+
var pyrightWatches = (_text, args) => args.includes("--watch") || args.includes("-w");
|
|
23391
|
+
var FD_FLAGS = {
|
|
23392
|
+
...takes("none", "-h", "--help", "-V", "--version", "-H", "--hidden", "-I", "--no-ignore", "--no-ignore-vcs", "--no-ignore-parent", "-s", "--case-sensitive", "-i", "--ignore-case", "-g", "--glob", "--regex", "-F", "--fixed-strings", "-a", "--absolute-path", "-L", "--follow", "-p", "--full-path", "-0", "--print0", "-1", "-q", "--quiet", "--show-errors", "--strip-cwd-prefix", "--one-file-system", "--prune", "--no-require-git"),
|
|
23393
|
+
...takes("number", "-d", "--max-depth", "--min-depth", "--exact-depth", "-j", "--threads", "--max-results", "--batch-size"),
|
|
23394
|
+
...takes("string", "-t", "--type", "-e", "--extension", "-S", "--size", "--changed-within", "--changed-before", "-o", "--owner", "-E", "--exclude", "--ignore-file", "-c", "--color", "--max-buffer-time", "--search-path", "--base-directory", "--path-separator", "--hyperlink", "--and", "--format")
|
|
23395
|
+
};
|
|
23396
|
+
var CHECKSUM_FLAGS = takes("none", "-b", "--binary", "-t", "--text", "-c", "--check", "--ignore-missing", "--quiet", "--status", "--strict", "-w", "--warn", "--tag", "-z", "--zero", "--help", "--version");
|
|
23397
|
+
var COMMAND_SPECS = [
|
|
23398
|
+
[
|
|
23399
|
+
"xargs",
|
|
23400
|
+
{
|
|
23401
|
+
flags: { ...takes("{}", "-I"), ...takes("number", "-n", "-P", "-L", "-s"), ...takes("EOF", "-E"), ...takes("none", "-0", "-t", "-r", "-x"), ...takes("char", "-d") }
|
|
23402
|
+
}
|
|
23403
|
+
],
|
|
23404
|
+
[
|
|
23405
|
+
"git diff",
|
|
23406
|
+
{
|
|
23407
|
+
flags: {
|
|
23408
|
+
...GIT_STAT,
|
|
23409
|
+
...GIT_COLOR,
|
|
23410
|
+
...takes("none", "--dirstat", "--summary", "--patch-with-stat", "--word-diff", "--color-words", "--no-renames", "--no-ext-diff", "--check", "--full-index", "--binary", "--break-rewrites", "--find-renames", "--find-copies", "--find-copies-harder", "--irreversible-delete", "--histogram", "--patience", "--minimal", "--ignore-space-at-eol", "--ignore-space-change", "--ignore-all-space", "--ignore-blank-lines", "--function-context", "--exit-code", "--quiet", "--cached", "--staged", "--pickaxe-regex", "--pickaxe-all", "--no-index", "-p", "-u", "-s", "-M", "-C", "-B", "-D", "-l", "-R"),
|
|
23411
|
+
...takes("string", "--word-diff-regex", "--ws-error-highlight", "--diff-algorithm", "--relative", "--diff-filter", "-S", "-G", "-O"),
|
|
23412
|
+
...takes("number", "--abbrev", "--inter-hunk-context")
|
|
23413
|
+
}
|
|
23414
|
+
}
|
|
23415
|
+
],
|
|
23416
|
+
[
|
|
23417
|
+
"git log",
|
|
23418
|
+
{
|
|
23419
|
+
flags: {
|
|
23420
|
+
...GIT_LOG_DISPLAY,
|
|
23421
|
+
...GIT_REF_SELECTION,
|
|
23422
|
+
...GIT_DATE_FILTERS,
|
|
23423
|
+
...GIT_COUNT,
|
|
23424
|
+
...GIT_STAT,
|
|
23425
|
+
...GIT_COLOR,
|
|
23426
|
+
...GIT_PATCH,
|
|
23427
|
+
...GIT_AUTHOR_FILTERS,
|
|
23428
|
+
...takes("none", "--abbrev-commit", "--full-history", "--dense", "--sparse", "--simplify-merges", "--ancestry-path", "--source", "--first-parent", "--merges", "--no-merges", "--reverse", "--walk-reflogs", "--no-min-parents", "--no-max-parents", "--follow", "--no-walk", "--left-right", "--cherry-mark", "--cherry-pick", "--boundary", "--topo-order", "--date-order", "--author-date-order", "--pickaxe-regex", "--pickaxe-all"),
|
|
23429
|
+
...takes("number", "--skip", "--max-age", "--min-age"),
|
|
23430
|
+
...takes("string", "--pretty", "--format", "--diff-filter", "-S", "-G")
|
|
23431
|
+
}
|
|
23432
|
+
}
|
|
23433
|
+
],
|
|
23434
|
+
[
|
|
23435
|
+
"git show",
|
|
23436
|
+
{
|
|
23437
|
+
flags: {
|
|
23438
|
+
...GIT_LOG_DISPLAY,
|
|
23439
|
+
...GIT_STAT,
|
|
23440
|
+
...GIT_COLOR,
|
|
23441
|
+
...GIT_PATCH,
|
|
23442
|
+
...takes("none", "--abbrev-commit", "--word-diff", "--color-words", "--first-parent", "--raw", "-m", "--quiet"),
|
|
23443
|
+
...takes("string", "--word-diff-regex", "--pretty", "--format", "--diff-filter")
|
|
23444
|
+
}
|
|
23445
|
+
}
|
|
23446
|
+
],
|
|
23447
|
+
[
|
|
23448
|
+
"git shortlog",
|
|
23449
|
+
{
|
|
23450
|
+
flags: {
|
|
23451
|
+
...GIT_REF_SELECTION,
|
|
23452
|
+
...GIT_DATE_FILTERS,
|
|
23453
|
+
...takes("none", "-s", "--summary", "-n", "--numbered", "-e", "--email", "-c", "--committer", "--no-merges"),
|
|
23454
|
+
...takes("string", "--group", "--format", "--author")
|
|
23455
|
+
}
|
|
23456
|
+
}
|
|
23457
|
+
],
|
|
23458
|
+
["git reflog", { respectsDoubleDash: false, flags: { ...GIT_LOG_DISPLAY, ...GIT_REF_SELECTION, ...GIT_DATE_FILTERS, ...GIT_COUNT, ...GIT_AUTHOR_FILTERS }, dangerous: reflogWrites }],
|
|
23459
|
+
["git stash list", { respectsDoubleDash: false, flags: { ...GIT_LOG_DISPLAY, ...GIT_REF_SELECTION, ...GIT_COUNT } }],
|
|
23460
|
+
[
|
|
23461
|
+
"git ls-remote",
|
|
23462
|
+
{
|
|
23463
|
+
respectsDoubleDash: false,
|
|
23464
|
+
flags: {
|
|
23465
|
+
...takes("none", "--branches", "-b", "--tags", "-t", "--heads", "-h", "--refs", "--quiet", "-q", "--exit-code", "--get-url", "--symref"),
|
|
23466
|
+
...takes("string", "--sort")
|
|
23467
|
+
}
|
|
23468
|
+
}
|
|
23469
|
+
],
|
|
23470
|
+
[
|
|
23471
|
+
"git status",
|
|
23472
|
+
{
|
|
23473
|
+
flags: {
|
|
23474
|
+
...takes("none", "--short", "-s", "--branch", "-b", "--porcelain", "--long", "--verbose", "-v", "--ignored", "--column", "--no-column", "--ahead-behind", "--no-ahead-behind", "--renames", "--no-renames"),
|
|
23475
|
+
...takes("string", "--untracked-files", "-u", "--ignore-submodules", "--find-renames", "-M")
|
|
23476
|
+
}
|
|
23477
|
+
}
|
|
23478
|
+
],
|
|
23479
|
+
[
|
|
23480
|
+
"git blame",
|
|
23481
|
+
{
|
|
23482
|
+
flags: {
|
|
23483
|
+
...GIT_COLOR,
|
|
23484
|
+
...takes("string", "-L", "--date", "--ignore-rev", "--ignore-revs-file"),
|
|
23485
|
+
...takes("none", "--porcelain", "-p", "--line-porcelain", "--incremental", "--root", "--show-stats", "--show-name", "--show-number", "-n", "--show-email", "-e", "-f", "-w", "-M", "-C", "--score-debug", "-s", "-l", "-t"),
|
|
23486
|
+
...takes("number", "--abbrev")
|
|
23487
|
+
}
|
|
23488
|
+
}
|
|
23489
|
+
],
|
|
23490
|
+
[
|
|
23491
|
+
"git ls-files",
|
|
23492
|
+
{
|
|
23493
|
+
flags: {
|
|
23494
|
+
...takes("none", "--cached", "-c", "--deleted", "-d", "--modified", "-m", "--others", "-o", "--ignored", "-i", "--stage", "-s", "--killed", "-k", "--unmerged", "-u", "--directory", "--no-empty-directory", "--eol", "--full-name", "--debug", "-z", "-t", "-v", "-f", "--exclude-standard", "--error-unmatch", "--recurse-submodules"),
|
|
23495
|
+
...takes("number", "--abbrev"),
|
|
23496
|
+
...takes("string", "--exclude", "-x", "--exclude-from", "-X", "--exclude-per-directory")
|
|
23497
|
+
}
|
|
23498
|
+
}
|
|
23499
|
+
],
|
|
23500
|
+
[
|
|
23501
|
+
"git config --get",
|
|
23502
|
+
{
|
|
23503
|
+
flags: {
|
|
23504
|
+
...takes("none", "--local", "--global", "--system", "--worktree", "--bool", "--int", "--bool-or-int", "--path", "--expiry-date", "-z", "--null", "--name-only", "--show-origin", "--show-scope"),
|
|
23505
|
+
...takes("string", "--default", "--type")
|
|
23506
|
+
}
|
|
23507
|
+
}
|
|
23508
|
+
],
|
|
23509
|
+
[
|
|
23510
|
+
"git remote show",
|
|
23511
|
+
{
|
|
23512
|
+
flags: takes("none", "-n"),
|
|
23513
|
+
dangerous: remoteShowReachesBeyondOneRemote
|
|
23514
|
+
}
|
|
23515
|
+
],
|
|
23516
|
+
["git remote", { flags: takes("none", "-v", "--verbose"), dangerous: remoteDoesMoreThanList }],
|
|
23517
|
+
["git merge-base", { flags: takes("none", "--is-ancestor", "--fork-point", "--octopus", "--independent", "--all") }],
|
|
23518
|
+
[
|
|
23519
|
+
"git rev-parse",
|
|
23520
|
+
{
|
|
23521
|
+
flags: {
|
|
23522
|
+
...takes("none", "--verify", "--abbrev-ref", "--symbolic", "--symbolic-full-name", "--show-toplevel", "--show-cdup", "--show-prefix", "--git-dir", "--git-common-dir", "--absolute-git-dir", "--show-superproject-working-tree", "--is-inside-work-tree", "--is-inside-git-dir", "--is-bare-repository", "--is-shallow-repository", "--is-shallow-update", "--path-prefix"),
|
|
23523
|
+
...takes("string", "--short")
|
|
23524
|
+
}
|
|
23525
|
+
}
|
|
23526
|
+
],
|
|
23527
|
+
[
|
|
23528
|
+
"git rev-list",
|
|
23529
|
+
{
|
|
23530
|
+
flags: {
|
|
23531
|
+
...GIT_REF_SELECTION,
|
|
23532
|
+
...GIT_DATE_FILTERS,
|
|
23533
|
+
...GIT_COUNT,
|
|
23534
|
+
...GIT_AUTHOR_FILTERS,
|
|
23535
|
+
...takes("none", "--count", "--reverse", "--first-parent", "--ancestry-path", "--merges", "--no-merges", "--no-min-parents", "--no-max-parents", "--walk-reflogs", "--oneline", "--abbrev-commit", "--full-history", "--dense", "--sparse", "--source", "--graph"),
|
|
23536
|
+
...takes("number", "--min-parents", "--max-parents", "--skip", "--max-age", "--min-age", "--abbrev"),
|
|
23537
|
+
...takes("string", "--pretty", "--format")
|
|
23538
|
+
}
|
|
23539
|
+
}
|
|
23540
|
+
],
|
|
23541
|
+
[
|
|
23542
|
+
"git describe",
|
|
23543
|
+
{
|
|
23544
|
+
flags: {
|
|
23545
|
+
...takes("none", "--tags", "--long", "--always", "--contains", "--first-match", "--exact-match", "--dirty", "--broken"),
|
|
23546
|
+
...takes("string", "--match", "--exclude"),
|
|
23547
|
+
...takes("number", "--abbrev", "--candidates")
|
|
23548
|
+
}
|
|
23549
|
+
}
|
|
23550
|
+
],
|
|
23551
|
+
["git cat-file", { flags: takes("none", "-t", "-s", "-p", "-e", "--batch-check", "--allow-undetermined-type") }],
|
|
23552
|
+
[
|
|
23553
|
+
"git for-each-ref",
|
|
23554
|
+
{
|
|
23555
|
+
flags: {
|
|
23556
|
+
...takes("string", "--format", "--sort", "--contains", "--no-contains", "--merged", "--no-merged", "--points-at"),
|
|
23557
|
+
...takes("number", "--count")
|
|
23558
|
+
}
|
|
23559
|
+
}
|
|
23560
|
+
],
|
|
23561
|
+
[
|
|
23562
|
+
"git grep",
|
|
23563
|
+
{
|
|
23564
|
+
flags: {
|
|
23565
|
+
...takes("string", "-e"),
|
|
23566
|
+
...takes("none", "-E", "--extended-regexp", "-G", "--basic-regexp", "-F", "--fixed-strings", "-P", "--perl-regexp", "-i", "--ignore-case", "-v", "--invert-match", "-w", "--word-regexp", "-n", "--line-number", "-c", "--count", "-l", "--files-with-matches", "-L", "--files-without-match", "-h", "-H", "--heading", "--break", "--full-name", "--color", "--no-color", "-o", "--only-matching", "--and", "--or", "--not", "--untracked", "--no-index", "--recurse-submodules", "--cached", "-q", "--quiet"),
|
|
23567
|
+
...takes("number", "-A", "--after-context", "-B", "--before-context", "-C", "--context", "--max-depth", "--threads")
|
|
23568
|
+
}
|
|
23569
|
+
}
|
|
23570
|
+
],
|
|
23571
|
+
[
|
|
23572
|
+
"git stash show",
|
|
23573
|
+
{
|
|
23574
|
+
respectsDoubleDash: false,
|
|
23575
|
+
flags: {
|
|
23576
|
+
...GIT_STAT,
|
|
23577
|
+
...GIT_COLOR,
|
|
23578
|
+
...GIT_PATCH,
|
|
23579
|
+
...takes("none", "--word-diff"),
|
|
23580
|
+
...takes("string", "--word-diff-regex", "--diff-filter"),
|
|
23581
|
+
...takes("number", "--abbrev")
|
|
23582
|
+
}
|
|
23583
|
+
}
|
|
23584
|
+
],
|
|
23585
|
+
["git worktree list", { flags: { ...takes("none", "--porcelain", "-v", "--verbose"), ...takes("string", "--expire") } }],
|
|
23586
|
+
["git tag", { flags: GIT_TAG_FLAGS, dangerous: (_text, args) => namesNewRef(args, GIT_TAG_FLAGS, new Set) }],
|
|
23587
|
+
["git branch", { flags: GIT_BRANCH_FLAGS, dangerous: (_text, args) => namesNewRef(args, GIT_BRANCH_FLAGS, BRANCH_OPTIONAL_COMMIT) }],
|
|
23588
|
+
[
|
|
23589
|
+
"file",
|
|
23590
|
+
{
|
|
23591
|
+
flags: {
|
|
23592
|
+
...takes("none", "--brief", "-b", "--mime", "-i", "--mime-type", "--mime-encoding", "--apple", "--check-encoding", "-c", "--print0", "-0", "--help", "--version", "-v", "--no-dereference", "-h", "--dereference", "-L", "--keep-going", "-k", "--list", "-l", "--no-buffer", "-n", "--preserve-date", "-p", "--raw", "-r", "-s", "--special-files", "--uncompress", "-z"),
|
|
23593
|
+
...takes("string", "--exclude", "--exclude-quiet", "-f", "-F", "--separator", "--magic-file", "-m")
|
|
23594
|
+
}
|
|
23595
|
+
}
|
|
23596
|
+
],
|
|
23597
|
+
[
|
|
23598
|
+
"sed",
|
|
23599
|
+
{
|
|
23600
|
+
flags: {
|
|
23601
|
+
...takes("string", "--expression", "-e"),
|
|
23602
|
+
...takes("none", "--quiet", "--silent", "-n", "--regexp-extended", "-r", "--posix", "-E", "--zero-terminated", "-z", "--separate", "-s", "--unbuffered", "-u", "--debug", "--help", "--version"),
|
|
23603
|
+
...takes("number", "--line-length", "-l")
|
|
23604
|
+
},
|
|
23605
|
+
dangerous: (text, args) => !sedIsAllowed(text, args)
|
|
23606
|
+
}
|
|
23607
|
+
],
|
|
23608
|
+
[
|
|
23609
|
+
"sort",
|
|
23610
|
+
{
|
|
23611
|
+
flags: {
|
|
23612
|
+
...takes("none", "--ignore-leading-blanks", "-b", "--dictionary-order", "-d", "--ignore-case", "-f", "--general-numeric-sort", "-g", "--human-numeric-sort", "-h", "--ignore-nonprinting", "-i", "--month-sort", "-M", "--numeric-sort", "-n", "--random-sort", "-R", "--reverse", "-r", "--stable", "-s", "--unique", "-u", "--version-sort", "-V", "--zero-terminated", "-z", "--check", "-c", "--check-char-order", "-C", "--merge", "-m", "--help", "--version"),
|
|
23613
|
+
...takes("string", "--sort", "--key", "-k", "--field-separator", "-t", "--buffer-size", "-S"),
|
|
23614
|
+
...takes("number", "--parallel", "--batch-size")
|
|
23615
|
+
}
|
|
23616
|
+
}
|
|
23617
|
+
],
|
|
23618
|
+
["man", { flags: { ...takes("none", "-a", "--all", "-d", "-f", "--whatis", "-h", "-k", "--apropos", "-w"), ...takes("string", "-l", "-S", "-s") } }],
|
|
23619
|
+
["help", { flags: takes("none", "-d", "-m", "-s") }],
|
|
23620
|
+
["netstat", { flags: { ...takes("none", "-a", "-L", "-l", "-n", "-g", "-i", "-s", "-r", "-m", "-v"), ...takes("string", "-f", "-I") } }],
|
|
23621
|
+
[
|
|
23622
|
+
"ps",
|
|
23623
|
+
{
|
|
23624
|
+
flags: {
|
|
23625
|
+
...takes("none", "-e", "-A", "-a", "-d", "-N", "--deselect", "-f", "-F", "-l", "-j", "-y", "-w", "-ww", "-c", "-H", "--forest", "--headers", "--no-headers", "-L", "-T", "-m", "--help", "--info", "-V", "--version"),
|
|
23626
|
+
...takes("number", "--width"),
|
|
23627
|
+
...takes("string", "-n", "--sort", "-C", "-G", "-g", "-p", "--pid", "-q", "--quick-pid", "-s", "--sid", "-t", "--tty", "-U", "-u", "--user")
|
|
23628
|
+
},
|
|
23629
|
+
dangerous: psPrintsEnvironments
|
|
23630
|
+
}
|
|
23631
|
+
],
|
|
23632
|
+
[
|
|
23633
|
+
"base64",
|
|
23634
|
+
{
|
|
23635
|
+
respectsDoubleDash: false,
|
|
23636
|
+
flags: BASE64_FLAGS,
|
|
23637
|
+
dangerous: (_text, args) => operandsOf(args, BASE64_FLAGS).length > 1
|
|
23638
|
+
}
|
|
23639
|
+
],
|
|
23640
|
+
[
|
|
23641
|
+
"grep",
|
|
23642
|
+
{
|
|
23643
|
+
flags: {
|
|
23644
|
+
...takes("string", "-e", "--regexp", "-f", "--file", "--color", "--colour", "--label", "--group-separator", "--binary-files", "-D", "--devices", "-d", "--directories", "--exclude", "--exclude-from", "--exclude-dir", "--include"),
|
|
23645
|
+
...takes("none", "-F", "--fixed-strings", "-G", "--basic-regexp", "-E", "--extended-regexp", "-P", "--perl-regexp", "-i", "--ignore-case", "--no-ignore-case", "-v", "--invert-match", "-w", "--word-regexp", "-x", "--line-regexp", "-c", "--count", "-L", "--files-without-match", "-l", "--files-with-matches", "-o", "--only-matching", "-q", "--quiet", "--silent", "-s", "--no-messages", "-b", "--byte-offset", "-H", "--with-filename", "-h", "--no-filename", "-n", "--line-number", "-T", "--initial-tab", "-u", "--unix-byte-offsets", "-Z", "--null", "-z", "--null-data", "--no-group-separator", "-a", "--text", "-r", "--recursive", "-R", "--dereference-recursive", "--line-buffered", "-U", "--binary", "--help", "-V", "--version"),
|
|
23646
|
+
...takes("number", "-m", "--max-count", "-A", "--after-context", "-B", "--before-context", "-C", "--context")
|
|
23647
|
+
}
|
|
23648
|
+
}
|
|
23649
|
+
],
|
|
23650
|
+
[
|
|
23651
|
+
"rg",
|
|
23652
|
+
{
|
|
23653
|
+
flags: {
|
|
23654
|
+
...takes("string", "-e", "--regexp", "-f", "-g", "--glob", "-t", "--type", "-T", "--type-not", "--color"),
|
|
23655
|
+
...takes("none", "-i", "--ignore-case", "-S", "--smart-case", "-F", "--fixed-strings", "-w", "--word-regexp", "-v", "--invert-match", "-c", "--count", "-l", "--files-with-matches", "--files-without-match", "-n", "--line-number", "-o", "--only-matching", "-H", "-h", "--heading", "--no-heading", "-q", "--quiet", "--column", "--type-list", "--hidden", "--no-ignore", "-u", "-a", "--text", "-z", "-L", "--follow", "--json", "--stats", "--help", "--version", "--debug", "--"),
|
|
23656
|
+
...takes("number", "-A", "--after-context", "-B", "--before-context", "-C", "--context", "-m", "--max-count", "-d", "--max-depth")
|
|
23657
|
+
}
|
|
23658
|
+
}
|
|
23659
|
+
],
|
|
23660
|
+
["sha256sum", { flags: CHECKSUM_FLAGS }],
|
|
23661
|
+
["sha1sum", { flags: CHECKSUM_FLAGS }],
|
|
23662
|
+
["md5sum", { flags: CHECKSUM_FLAGS }],
|
|
23663
|
+
[
|
|
23664
|
+
"tree",
|
|
23665
|
+
{
|
|
23666
|
+
respectsDoubleDash: false,
|
|
23667
|
+
flags: {
|
|
23668
|
+
...takes("none", "-a", "-d", "-l", "-f", "-x", "--gitignore", "--ignore-case", "--matchdirs", "--metafirst", "--prune", "--info", "--noreport", "-q", "-N", "-Q", "-p", "-u", "-g", "-s", "-h", "--si", "--du", "-D", "-F", "--inodes", "--device", "-v", "-t", "-c", "-U", "-r", "--dirsfirst", "--filesfirst", "-i", "-A", "-S", "-n", "-C", "-X", "-J", "--nolinks", "--hyperlink", "--fromfile", "--fromtabfile", "--fflinks", "--help", "--version"),
|
|
23669
|
+
...takes("number", "-L", "--filelimit"),
|
|
23670
|
+
...takes("string", "-P", "-I", "--gitfile", "--infofile", "--charset", "--timefmt", "--sort", "-H", "--hintro", "--houtro", "-T", "--scheme", "--authority")
|
|
23671
|
+
}
|
|
23672
|
+
}
|
|
23673
|
+
],
|
|
23674
|
+
[
|
|
23675
|
+
"date",
|
|
23676
|
+
{
|
|
23677
|
+
flags: DATE_FLAGS,
|
|
23678
|
+
dangerous: dateSetsClock
|
|
23679
|
+
}
|
|
23680
|
+
],
|
|
23681
|
+
[
|
|
23682
|
+
"hostname",
|
|
23683
|
+
{
|
|
23684
|
+
flags: takes("none", "-f", "--fqdn", "--long", "-s", "--short", "-i", "--ip-address", "-I", "--all-ip-addresses", "-a", "--alias", "-d", "--domain", "-A", "--all-fqdns", "-v", "--verbose", "-h", "--help", "-V", "--version"),
|
|
23685
|
+
pattern: /^hostname(?:\s+(?:-[a-zA-Z]|--[a-zA-Z-]+))*\s*$/
|
|
23686
|
+
}
|
|
23687
|
+
],
|
|
23688
|
+
[
|
|
23689
|
+
"info",
|
|
23690
|
+
{
|
|
23691
|
+
flags: {
|
|
23692
|
+
...takes("string", "-f", "--file", "-d", "--directory", "-n", "--node", "-k", "--apropos"),
|
|
23693
|
+
...takes("none", "-a", "--all", "-w", "--where", "--location", "--show-options", "--vi-keys", "--subnodes", "-h", "--help", "--usage", "--version")
|
|
23694
|
+
}
|
|
23695
|
+
}
|
|
23696
|
+
],
|
|
23697
|
+
[
|
|
23698
|
+
"lsof",
|
|
23699
|
+
{
|
|
23700
|
+
respectsDoubleDash: false,
|
|
23701
|
+
flags: {
|
|
23702
|
+
...takes("none", "-?", "-h", "-v", "-a", "-b", "-C", "-l", "-n", "-N", "-O", "-P", "-Q", "-R", "-t", "-U", "-V", "-X", "-H", "-E", "-F", "-g", "-i", "-K", "-L", "-o", "-r", "-s", "-S", "-T", "-x"),
|
|
23703
|
+
...takes("string", "-A", "-c", "-d", "-e", "-k", "-p", "-u")
|
|
23704
|
+
},
|
|
23705
|
+
dangerous: lsofWritesMountSupplement
|
|
23706
|
+
}
|
|
23707
|
+
],
|
|
23708
|
+
[
|
|
23709
|
+
"pgrep",
|
|
23710
|
+
{
|
|
23711
|
+
flags: {
|
|
23712
|
+
...takes("string", "-d", "--delimiter", "-g", "--pgroup", "-G", "--group", "-O", "--older", "-P", "--parent", "-s", "--session", "-t", "--terminal", "-u", "--euid", "-U", "--uid", "-F", "--pidfile", "-r", "--runstates", "--ns", "--nslist"),
|
|
23713
|
+
...takes("none", "-l", "--list-name", "-a", "--list-full", "-v", "--inverse", "-w", "--lightweight", "-c", "--count", "-f", "--full", "-i", "--ignore-case", "-n", "--newest", "-o", "--oldest", "-x", "--exact", "-L", "--logpidfile", "--help", "-V", "--version")
|
|
23714
|
+
}
|
|
23715
|
+
}
|
|
23716
|
+
],
|
|
23717
|
+
["tput", { flags: TPUT_FLAGS, dangerous: tputChangesTerminal }],
|
|
23718
|
+
[
|
|
23719
|
+
"ss",
|
|
23720
|
+
{
|
|
23721
|
+
flags: {
|
|
23722
|
+
...takes("none", "-h", "--help", "-V", "--version", "-n", "--numeric", "-r", "--resolve", "-a", "--all", "-l", "--listening", "-o", "--options", "-e", "--extended", "-m", "--memory", "-p", "--processes", "-i", "--info", "-s", "--summary", "-4", "--ipv4", "-6", "--ipv6", "-0", "--packet", "-t", "--tcp", "-M", "--mptcp", "-S", "--sctp", "-u", "--udp", "-d", "--dccp", "-w", "--raw", "-x", "--unix", "--tipc", "--vsock", "-Z", "--context", "-z", "--contexts", "-b", "--bpf", "-E", "--events", "-H", "--no-header", "-O", "--oneline", "--tipcinfo", "--tos", "--cgroup", "--inet-sockopt"),
|
|
23723
|
+
...takes("string", "-f", "--family", "-A", "--query", "--socket")
|
|
23724
|
+
}
|
|
23725
|
+
}
|
|
23726
|
+
],
|
|
23727
|
+
["fd", { flags: FD_FLAGS }],
|
|
23728
|
+
["fdfind", { flags: FD_FLAGS }],
|
|
23729
|
+
[
|
|
23730
|
+
"pyright",
|
|
23731
|
+
{
|
|
23732
|
+
respectsDoubleDash: false,
|
|
23733
|
+
flags: {
|
|
23734
|
+
...takes("none", "--outputjson", "--stats", "--verbose", "--version", "--dependencies", "--warnings"),
|
|
23735
|
+
...takes("string", "--project", "-p", "--pythonversion", "--pythonplatform", "--typeshedpath", "--venvpath", "--level")
|
|
23736
|
+
},
|
|
23737
|
+
dangerous: pyrightWatches
|
|
23738
|
+
}
|
|
23739
|
+
],
|
|
23740
|
+
["docker logs", { flags: { ...takes("none", "--follow", "-f", "--timestamps", "-t", "--details"), ...takes("string", "--tail", "-n", "--since", "--until") } }],
|
|
23741
|
+
["docker inspect", { flags: { ...takes("string", "--format", "-f", "--type"), ...takes("none", "--size", "-s") } }]
|
|
23742
|
+
];
|
|
23743
|
+
var XARGS_SAFE_TARGETS = new Set(["echo", "printf", "wc", "grep", "head", "tail"]);
|
|
23744
|
+
function readOptionWord(token) {
|
|
23745
|
+
if (token === "--")
|
|
23746
|
+
return { form: "end-of-options" };
|
|
23747
|
+
if (token.length < 2 || !token.startsWith("-"))
|
|
23748
|
+
return { form: "operand" };
|
|
23749
|
+
const eq = token.indexOf("=");
|
|
23750
|
+
const head = eq === -1 ? token : token.slice(0, eq);
|
|
23751
|
+
const inline = eq === -1 ? undefined : token.slice(eq + 1);
|
|
23752
|
+
if (head.startsWith("--"))
|
|
23753
|
+
return inline === undefined ? { form: "long", name: head } : { form: "long", name: head, inline };
|
|
23754
|
+
const letters = head.slice(1);
|
|
23755
|
+
return inline === undefined ? { form: "short", letters } : { form: "short", letters, inline };
|
|
23756
|
+
}
|
|
23757
|
+
var looksLikeOption = (token) => token.length > 1 && token.startsWith("-");
|
|
23758
|
+
function kindOf(flags, name) {
|
|
23759
|
+
return Object.hasOwn(flags, name) ? flags[name] : undefined;
|
|
23760
|
+
}
|
|
23761
|
+
function valueFits(kind, value, flag, command) {
|
|
23762
|
+
switch (kind) {
|
|
23763
|
+
case "number":
|
|
23764
|
+
return /^\d+$/.test(value);
|
|
23765
|
+
case "string":
|
|
23766
|
+
case "attached":
|
|
23767
|
+
return !value.startsWith("-") || command === "git" && flag === "--sort" && /^-[a-zA-Z]/.test(value);
|
|
23768
|
+
case "char":
|
|
23769
|
+
return value.length === 1;
|
|
23770
|
+
case "{}":
|
|
23771
|
+
case "EOF":
|
|
23772
|
+
return value === kind;
|
|
23773
|
+
default:
|
|
23774
|
+
return false;
|
|
23775
|
+
}
|
|
23776
|
+
}
|
|
23777
|
+
function acceptOption(tokens, i, flags, command) {
|
|
23778
|
+
const word = readOptionWord(tokens[i]);
|
|
23779
|
+
if (word.form !== "long" && word.form !== "short")
|
|
23780
|
+
return null;
|
|
23781
|
+
const name = word.form === "long" ? word.name : `-${word.letters}`;
|
|
23782
|
+
const kind = kindOf(flags, name);
|
|
23783
|
+
if (kind !== undefined) {
|
|
23784
|
+
if (kind === "none")
|
|
23785
|
+
return word.inline === undefined ? 1 : null;
|
|
23786
|
+
if (kind === "attached")
|
|
23787
|
+
return word.inline !== undefined && valueFits(kind, word.inline, name, command) ? 1 : null;
|
|
23788
|
+
if (word.inline !== undefined)
|
|
23789
|
+
return valueFits(kind, word.inline, name, command) ? 1 : null;
|
|
23790
|
+
const value = tokens[i + 1];
|
|
23791
|
+
if (value === undefined || looksLikeOption(value))
|
|
23792
|
+
return null;
|
|
23793
|
+
return valueFits(kind, value, name, command) ? 2 : null;
|
|
23794
|
+
}
|
|
23795
|
+
if (word.form === "long" || word.inline !== undefined)
|
|
23796
|
+
return null;
|
|
23797
|
+
if (command === "git" && /^\d+$/.test(word.letters))
|
|
23798
|
+
return 1;
|
|
23799
|
+
if (command === "grep" || command === "rg") {
|
|
23800
|
+
const leading = kindOf(flags, `-${word.letters[0]}`);
|
|
23801
|
+
if ((leading === "number" || leading === "string") && /^\d+$/.test(word.letters.slice(1)))
|
|
23802
|
+
return 1;
|
|
23803
|
+
}
|
|
23804
|
+
for (const letter of word.letters) {
|
|
23805
|
+
if (kindOf(flags, `-${letter}`) !== "none")
|
|
23806
|
+
return null;
|
|
23807
|
+
}
|
|
23808
|
+
return 1;
|
|
23809
|
+
}
|
|
23810
|
+
function optionsAllowed(tokens, start, spec, command) {
|
|
23811
|
+
let i = start;
|
|
23812
|
+
while (i < tokens.length) {
|
|
23813
|
+
const word = readOptionWord(tokens[i]);
|
|
23814
|
+
if (word.form === "operand") {
|
|
23815
|
+
i++;
|
|
23816
|
+
continue;
|
|
23817
|
+
}
|
|
23818
|
+
if (word.form === "end-of-options") {
|
|
23819
|
+
if (spec.respectsDoubleDash !== false)
|
|
23820
|
+
return true;
|
|
23821
|
+
i++;
|
|
23822
|
+
continue;
|
|
23823
|
+
}
|
|
23824
|
+
const used = acceptOption(tokens, i, spec.flags, command);
|
|
23825
|
+
if (used === null)
|
|
23826
|
+
return false;
|
|
23827
|
+
i += used;
|
|
23828
|
+
}
|
|
23829
|
+
return true;
|
|
23830
|
+
}
|
|
23831
|
+
function xargsAllowed(tokens, start, spec) {
|
|
23832
|
+
let i = start;
|
|
23833
|
+
while (i < tokens.length) {
|
|
23834
|
+
const word = readOptionWord(tokens[i]);
|
|
23835
|
+
if (word.form === "end-of-options") {
|
|
23836
|
+
const target = tokens[i + 1];
|
|
23837
|
+
return target !== undefined && XARGS_SAFE_TARGETS.has(target);
|
|
23838
|
+
}
|
|
23839
|
+
if (word.form === "operand")
|
|
23840
|
+
return XARGS_SAFE_TARGETS.has(tokens[i]);
|
|
23841
|
+
const used = acceptOption(tokens, i, spec.flags, "xargs");
|
|
23842
|
+
if (used === null)
|
|
23843
|
+
return false;
|
|
23844
|
+
i += used;
|
|
23845
|
+
}
|
|
23846
|
+
return true;
|
|
23847
|
+
}
|
|
23848
|
+
function operandsOf(args, flags) {
|
|
23849
|
+
return partitionArguments(args, flags).operands;
|
|
23850
|
+
}
|
|
23851
|
+
function partitionArguments(args, flags) {
|
|
23852
|
+
const options = [];
|
|
23853
|
+
const operands = [];
|
|
23854
|
+
let optionsOver = false;
|
|
23855
|
+
for (let i = 0;i < args.length; i++) {
|
|
23856
|
+
const token = args[i];
|
|
23857
|
+
const word = optionsOver ? { form: "operand" } : readOptionWord(token);
|
|
23858
|
+
if (word.form === "end-of-options")
|
|
23859
|
+
optionsOver = true;
|
|
23860
|
+
else if (word.form === "operand")
|
|
23861
|
+
operands.push(token);
|
|
23862
|
+
else {
|
|
23863
|
+
options.push(token);
|
|
23864
|
+
const kind = word.inline === undefined ? kindOf(flags, word.form === "long" ? word.name : `-${word.letters}`) : undefined;
|
|
23865
|
+
if (kind === "number" || kind === "string" || kind === "char" || kind === "{}" || kind === "EOF")
|
|
23866
|
+
i++;
|
|
23867
|
+
}
|
|
23868
|
+
}
|
|
23869
|
+
return { options, operands };
|
|
23870
|
+
}
|
|
23871
|
+
var SPEC_LEADING_WORDS = COMMAND_SPECS.map(([name, spec]) => ({ leading: name.split(" "), spec }));
|
|
23872
|
+
function commandSpecFor(tokens, platform) {
|
|
23873
|
+
const entry = SPEC_LEADING_WORDS.find(({ leading }) => leading.every((word, k) => tokens[k] === word) && !(leading[0] === "xargs" && platform === "win32"));
|
|
23874
|
+
return entry && { spec: entry.spec, words: entry.leading.length };
|
|
23875
|
+
}
|
|
23876
|
+
var namesRemoteLocation = (token) => token.length > 0 && !token.startsWith("-") && (token.includes("://") || token.includes("@") || token.includes(":") || token.includes("$"));
|
|
23877
|
+
var expandsAtRunTime = (token) => token.includes("$") || token.includes("{") && (token.includes(",") || token.includes(".."));
|
|
23878
|
+
function isSafeViaFlagAllowlist(sub, platform) {
|
|
23879
|
+
const tokens = sub.words.map((w) => w.value);
|
|
23880
|
+
const match = commandSpecFor(tokens, platform);
|
|
23881
|
+
if (match === undefined)
|
|
23882
|
+
return false;
|
|
23883
|
+
const { spec, words } = match;
|
|
23884
|
+
const args = tokens.slice(words);
|
|
23885
|
+
if (args.some(expandsAtRunTime))
|
|
23886
|
+
return false;
|
|
23887
|
+
if (tokens[0] === "git" && tokens[1] === "ls-remote" && args.some(namesRemoteLocation))
|
|
23888
|
+
return false;
|
|
23889
|
+
const optionsOk = tokens[0] === "xargs" ? xargsAllowed(tokens, words, spec) : optionsAllowed(tokens, words, spec, tokens[0]);
|
|
23890
|
+
if (!optionsOk)
|
|
23891
|
+
return false;
|
|
23892
|
+
if (spec.pattern !== undefined) {
|
|
23893
|
+
if (!spec.pattern.test(sub.text))
|
|
23894
|
+
return false;
|
|
23895
|
+
} else if (sub.text.includes("`") || (tokens[0] === "rg" || tokens[0] === "grep") && /[\n\r]/.test(sub.text)) {
|
|
23896
|
+
return false;
|
|
23897
|
+
}
|
|
23898
|
+
return !(spec.dangerous?.(sub.text, args) ?? false);
|
|
23899
|
+
}
|
|
23900
|
+
var SED_QUIET = ["-n", "--quiet", "--silent"];
|
|
23901
|
+
var SED_PRINT_OPTIONS = { long: ["--quiet", "--silent", "--regexp-extended", "--zero-terminated", "--posix"], letters: "nErz" };
|
|
23902
|
+
var SED_SUBSTITUTE_OPTIONS = { long: ["--regexp-extended", "--posix"], letters: "Er" };
|
|
23903
|
+
function sedOptionsWithin(options, allowed) {
|
|
23904
|
+
return options.every((option) => option.startsWith("--") ? allowed.long.includes(option) : option.length > 1 && [...option.slice(1)].every((letter) => allowed.letters.includes(letter)));
|
|
23905
|
+
}
|
|
23906
|
+
var SED_PRINT_SCRIPT = /^(?:\d+(?:,\d+)?)?p\s*(?:;\s*(?:\d+(?:,\d+)?)?p\s*)*$/;
|
|
23907
|
+
function sedPrintScript(script) {
|
|
23908
|
+
const trimmed = script.trim();
|
|
23909
|
+
return !trimmed.includes(`
|
|
23910
|
+
`) && SED_PRINT_SCRIPT.test(trimmed);
|
|
23911
|
+
}
|
|
23912
|
+
function sedSubstituteScript(script) {
|
|
23913
|
+
const s = script.trim();
|
|
23914
|
+
if (!s.startsWith("s/") || occurrences(s, "/") !== 3)
|
|
23915
|
+
return false;
|
|
23916
|
+
const delimiters = [];
|
|
23917
|
+
for (let i = 0;i < s.length; i++) {
|
|
23918
|
+
if (s[i] === "\\") {
|
|
23919
|
+
if (s[i + 1] === "/")
|
|
23920
|
+
return false;
|
|
23921
|
+
i++;
|
|
23922
|
+
continue;
|
|
23923
|
+
}
|
|
23924
|
+
if (s[i] === "/")
|
|
23925
|
+
delimiters.push(i);
|
|
23926
|
+
}
|
|
23927
|
+
if (delimiters.length !== 3)
|
|
23928
|
+
return false;
|
|
23929
|
+
if (!/^[gpimIM]*[1-9]?[gpimIM]*$/.test(s.slice(delimiters[2] + 1)))
|
|
23930
|
+
return false;
|
|
23931
|
+
for (let i = 0;i < s.length; i++) {
|
|
23932
|
+
const ch = s[i];
|
|
23933
|
+
const code = ch.charCodeAt(0);
|
|
23934
|
+
if (code === 0 || code > 127)
|
|
23935
|
+
return false;
|
|
23936
|
+
if (`
|
|
23937
|
+
{}#;!~`.includes(ch))
|
|
23938
|
+
return false;
|
|
23939
|
+
if (ch === "\\" && s[i - 1] === "s")
|
|
23940
|
+
return false;
|
|
23941
|
+
if (ch === "\\" && "|#%@".includes(s[i + 1] ?? ""))
|
|
23942
|
+
return false;
|
|
23943
|
+
if (isBlank(ch) && "wWeE".includes(s[i + 1] ?? " "))
|
|
23944
|
+
return false;
|
|
23945
|
+
if (ch === ",") {
|
|
23946
|
+
let k = i + 1;
|
|
23947
|
+
while (isBlank(s[k]))
|
|
23948
|
+
k++;
|
|
23949
|
+
if (s[k] === "+" || s[k] === "-")
|
|
23950
|
+
return false;
|
|
23951
|
+
}
|
|
23952
|
+
}
|
|
23953
|
+
const transliterates = /y[^\\\n]/.test(s);
|
|
23954
|
+
return !(transliterates && /[wWeE]/.test(s));
|
|
23955
|
+
}
|
|
23956
|
+
function sedIsAllowed(text, args) {
|
|
23957
|
+
if (!text.startsWith("sed "))
|
|
23958
|
+
return false;
|
|
23959
|
+
const argumentText = text.slice(4);
|
|
23960
|
+
if (/-e[wWe]|-w[eE]/.test(argumentText))
|
|
23961
|
+
return false;
|
|
23962
|
+
const options = args.filter((a) => a.startsWith("-") && a !== "--");
|
|
23963
|
+
const operands = args.filter((a) => !a.startsWith("-"));
|
|
23964
|
+
const script = operands[0];
|
|
23965
|
+
if (script === undefined)
|
|
23966
|
+
return false;
|
|
23967
|
+
const quiet = options.some((o) => SED_QUIET.includes(o) || !o.startsWith("--") && o.includes("n"));
|
|
23968
|
+
if (quiet && sedOptionsWithin(options, SED_PRINT_OPTIONS))
|
|
23969
|
+
return sedPrintScript(script);
|
|
23970
|
+
return operands.length === 1 && sedOptionsWithin(options, SED_SUBSTITUTE_OPTIONS) && sedSubstituteScript(script);
|
|
23971
|
+
}
|
|
23972
|
+
var PLAIN_READ_ONLY_COMMANDS = [
|
|
23973
|
+
"docker ps",
|
|
23974
|
+
"docker images",
|
|
23975
|
+
"cal",
|
|
23976
|
+
"uptime",
|
|
23977
|
+
"cat",
|
|
23978
|
+
"head",
|
|
23979
|
+
"tail",
|
|
23980
|
+
"wc",
|
|
23981
|
+
"stat",
|
|
23982
|
+
"strings",
|
|
23983
|
+
"hexdump",
|
|
23984
|
+
"od",
|
|
23985
|
+
"nl",
|
|
23986
|
+
"id",
|
|
23987
|
+
"uname",
|
|
23988
|
+
"free",
|
|
23989
|
+
"df",
|
|
23990
|
+
"du",
|
|
23991
|
+
"locale",
|
|
23992
|
+
"groups",
|
|
23993
|
+
"nproc",
|
|
23994
|
+
"basename",
|
|
23995
|
+
"dirname",
|
|
23996
|
+
"realpath",
|
|
23997
|
+
"cut",
|
|
23998
|
+
"paste",
|
|
23999
|
+
"tr",
|
|
24000
|
+
"column",
|
|
24001
|
+
"tac",
|
|
24002
|
+
"rev",
|
|
24003
|
+
"fold",
|
|
24004
|
+
"expand",
|
|
24005
|
+
"unexpand",
|
|
24006
|
+
"fmt",
|
|
24007
|
+
"comm",
|
|
24008
|
+
"cmp",
|
|
24009
|
+
"numfmt",
|
|
24010
|
+
"readlink",
|
|
24011
|
+
"diff",
|
|
24012
|
+
"true",
|
|
24013
|
+
"false",
|
|
24014
|
+
"sleep",
|
|
24015
|
+
"which",
|
|
24016
|
+
"type",
|
|
24017
|
+
"expr",
|
|
24018
|
+
"test",
|
|
24019
|
+
"getconf",
|
|
24020
|
+
"seq",
|
|
24021
|
+
"tsort",
|
|
24022
|
+
"pr"
|
|
24023
|
+
];
|
|
24024
|
+
var PLAIN_ARGUMENTS = "(?:\\s|$)[^<>()$`|{}&;\\n\\r]*$";
|
|
24025
|
+
var FIND_ACTIONS = /-(?:delete|exec|execdir|ok|okdir|fprint0?|fls|fprintf)\b/;
|
|
24026
|
+
var FIND_FORBIDDEN_SYNTAX = "<>()$`|{}&;\n\r";
|
|
24027
|
+
function findOnlyLists(simple) {
|
|
24028
|
+
if (simple.words[0].raw !== "find")
|
|
24029
|
+
return false;
|
|
24030
|
+
const args = simple.text.slice("find".length);
|
|
24031
|
+
for (let i = 0;i < args.length; i++) {
|
|
24032
|
+
if (args[i] === "\\" && (args[i + 1] === "(" || args[i + 1] === ")")) {
|
|
24033
|
+
i++;
|
|
24034
|
+
continue;
|
|
24035
|
+
}
|
|
24036
|
+
if (FIND_FORBIDDEN_SYNTAX.includes(args[i]))
|
|
24037
|
+
return false;
|
|
24038
|
+
}
|
|
24039
|
+
return !FIND_ACTIONS.test(args) && simple.words.every((w) => !FIND_ACTIONS.test(w.value));
|
|
24040
|
+
}
|
|
24041
|
+
var READ_ONLY_REGEXES = [
|
|
24042
|
+
...PLAIN_READ_ONLY_COMMANDS.map((name) => new RegExp("^" + name + PLAIN_ARGUMENTS)),
|
|
24043
|
+
/^echo(?:\s+(?:'[^']*'|"[^"$<>\n\r]*"|[^|;&`$(){}><#\\!"'\s]+))*(?:\s+2>&1)?\s*$/,
|
|
24044
|
+
/^claude -h$/,
|
|
24045
|
+
/^claude --help$/,
|
|
24046
|
+
/^uniq(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+(?:=\S+)?|-[fsw]\s+\d+))*(?:\s|$)\s*$/,
|
|
24047
|
+
/^pwd$/,
|
|
24048
|
+
/^whoami$/,
|
|
24049
|
+
/^node -v$/,
|
|
24050
|
+
/^node --version$/,
|
|
24051
|
+
/^python --version$/,
|
|
24052
|
+
/^python3 --version$/,
|
|
24053
|
+
/^history(?:\s+\d+)?\s*$/,
|
|
24054
|
+
/^alias$/,
|
|
24055
|
+
/^arch(?:\s+(?:--help|-h))?\s*$/,
|
|
24056
|
+
/^ip addr$/,
|
|
24057
|
+
/^ifconfig(?:\s+[a-zA-Z][a-zA-Z0-9_-]*)?\s*$/,
|
|
24058
|
+
/^jq(?!\s+.*(?:-f\b|--from-file|--rawfile|--slurpfile|--run-tests|-L\b|--library-path|\benv\b|\$ENV\b))(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+(?:=\S+)?))*(?:\s+'[^'`]*'|\s+"[^"`]*"|\s+[^-\s'"][^\s]*)+\s*$/,
|
|
24059
|
+
/^cd(?:\s+(?:'[^']*'|"[^"]*"|[^\s;|&`$(){}><#\\]+))?$/,
|
|
24060
|
+
/^ls(?:\s+[^<>()$`|{}&;\n\r]*)?$/
|
|
24061
|
+
];
|
|
24062
|
+
|
|
24063
|
+
// src/tools/concurrency.ts
|
|
24064
|
+
var MAX_TOOL_CONCURRENCY = 10;
|
|
24065
|
+
var CONCURRENCY_SAFE_BUILTINS = new Set(["Read", "Glob", "Grep", "LSP", "WebFetch", "WebSearch", "Search", "Agent"]);
|
|
24066
|
+
function schedulingForCall(name, input, bash) {
|
|
24067
|
+
const descriptor = getRegisteredTool(name)?.descriptor;
|
|
24068
|
+
if (descriptor === undefined)
|
|
24069
|
+
return { kind: "serial" };
|
|
24070
|
+
if (descriptor.source === "builtin") {
|
|
24071
|
+
if (CONCURRENCY_SAFE_BUILTINS.has(descriptor.canonicalName))
|
|
24072
|
+
return { kind: "concurrent" };
|
|
24073
|
+
if (descriptor.canonicalName === "Bash" && bash !== undefined) {
|
|
24074
|
+
const command = typeof input === "object" && input !== null ? input.command : undefined;
|
|
24075
|
+
const escapes = typeof input === "object" && input !== null && input.dangerouslyDisableSandbox === true;
|
|
24076
|
+
if (typeof command === "string" && !escapes && isBashCommandReadOnly(command, bash))
|
|
24077
|
+
return { kind: "concurrent" };
|
|
24078
|
+
}
|
|
24079
|
+
return { kind: "serial" };
|
|
24080
|
+
}
|
|
24081
|
+
if (descriptor.source === "mcp" || descriptor.source === "sdk" || descriptor.source === "plugin") {
|
|
24082
|
+
if (descriptor.annotations?.readOnlyHint === true)
|
|
24083
|
+
return { kind: "concurrent" };
|
|
24084
|
+
if (descriptor.concurrencyLane !== undefined)
|
|
24085
|
+
return { kind: "lane", lane: descriptor.concurrencyLane };
|
|
24086
|
+
if (descriptor.concurrencySafe === true)
|
|
24087
|
+
return { kind: "concurrent" };
|
|
24088
|
+
}
|
|
24089
|
+
return { kind: "serial" };
|
|
24090
|
+
}
|
|
24091
|
+
var SDK_MCP_CANCEL_GRACE_MS = 5000;
|
|
24092
|
+
function createToolLaneTails() {
|
|
24093
|
+
return new Map;
|
|
24094
|
+
}
|
|
24095
|
+
function enterToolLane(lanes, lane, tail) {
|
|
24096
|
+
const previous = lanes.get(lane);
|
|
24097
|
+
const chained = previous === undefined ? tail : Promise.all([previous, tail]).then(() => {
|
|
24098
|
+
return;
|
|
24099
|
+
});
|
|
24100
|
+
lanes.set(lane, chained);
|
|
24101
|
+
chained.finally(() => {
|
|
24102
|
+
if (lanes.get(lane) === chained)
|
|
24103
|
+
lanes.delete(lane);
|
|
24104
|
+
});
|
|
24105
|
+
return previous;
|
|
24106
|
+
}
|
|
24107
|
+
|
|
22444
24108
|
// src/tools/read-state.ts
|
|
22445
|
-
import { isAbsolute as isAbsolute6, join as
|
|
24109
|
+
import { isAbsolute as isAbsolute6, join as join25, normalize as normalize3 } from "node:path";
|
|
22446
24110
|
function createSessionReadState(opts) {
|
|
22447
24111
|
const cwd = opts.cwd;
|
|
22448
24112
|
const reads = new Map;
|
|
22449
24113
|
function canonicalKey(p) {
|
|
22450
|
-
const abs = isAbsolute6(p) ? p :
|
|
24114
|
+
const abs = isAbsolute6(p) ? p : join25(cwd, p);
|
|
22451
24115
|
return resolveRealTarget(normalize3(abs));
|
|
22452
24116
|
}
|
|
22453
24117
|
return {
|
|
@@ -22554,6 +24218,9 @@ function withoutLoadedTools(block) {
|
|
|
22554
24218
|
const { loadedTools: _loaded, loadedToolDefinitions: _definitions, ...rest } = block;
|
|
22555
24219
|
return rest;
|
|
22556
24220
|
}
|
|
24221
|
+
function hostToolResultContent(blocks, icons) {
|
|
24222
|
+
return withHostSiteIcons(toolResultsForHost(blocks.map((b) => b.type === "tool_result" && b.loadedTools !== undefined ? withoutLoadedTools(b) : b)), icons);
|
|
24223
|
+
}
|
|
22557
24224
|
function mcpNamespaceFor(advertisedName, server) {
|
|
22558
24225
|
if (server === undefined)
|
|
22559
24226
|
return;
|
|
@@ -22722,7 +24389,7 @@ function raceInterrupt(p, interrupted) {
|
|
|
22722
24389
|
}
|
|
22723
24390
|
function buildBaselineDenyRules(resolvedWinterHome, brand, resolvedStoreHome) {
|
|
22724
24391
|
const absolute = [];
|
|
22725
|
-
const defaultHome = resolve12(
|
|
24392
|
+
const defaultHome = resolve12(join26(homedir(), (brand ?? WINTER_BRAND24).homeDirName));
|
|
22726
24393
|
if (resolvedWinterHome !== undefined && resolve12(resolvedWinterHome) !== defaultHome) {
|
|
22727
24394
|
const root = `/${escapeFileRulePathSegment(resolve12(resolvedWinterHome))}`;
|
|
22728
24395
|
for (const dir of ["run"]) {
|
|
@@ -22871,6 +24538,7 @@ async function runEngine2(opts) {
|
|
|
22871
24538
|
}
|
|
22872
24539
|
}
|
|
22873
24540
|
async function runEngineBody(opts, facetDisposers, registerBackgroundShellSweep) {
|
|
24541
|
+
const sessionLaneTails = opts.toolLaneTails ?? createToolLaneTails();
|
|
22874
24542
|
const {
|
|
22875
24543
|
config,
|
|
22876
24544
|
input,
|
|
@@ -23858,16 +25526,23 @@ ${escapeAttributionText(msg.body)}
|
|
|
23858
25526
|
continue;
|
|
23859
25527
|
const toolDefs = serverCfg.tools;
|
|
23860
25528
|
const toolNames = serverCfg.toolNames;
|
|
23861
|
-
|
|
25529
|
+
const toolLanes = serverCfg.toolLanes;
|
|
25530
|
+
const concurrentTools = serverCfg.concurrentTools;
|
|
25531
|
+
registerMcpServerTools(serverName, toolDefs, {
|
|
25532
|
+
deferredDefault: true,
|
|
25533
|
+
...toolNames !== undefined ? { toolNames } : {},
|
|
25534
|
+
...toolLanes !== undefined ? { toolLanes } : {},
|
|
25535
|
+
...concurrentTools !== undefined ? { concurrentTools } : {}
|
|
25536
|
+
});
|
|
23862
25537
|
sdkMcpServerNames.push(serverName);
|
|
23863
25538
|
const perServerTimeoutMs = serverCfg.timeout;
|
|
23864
25539
|
for (const tool of toolDefs) {
|
|
23865
25540
|
const canonicalName = toolNames !== undefined && Object.hasOwn(toolNames, tool.name) ? toolNames[tool.name] : `mcp__${serverName}__${tool.name}`;
|
|
23866
25541
|
replaceExecutor(canonicalName, {
|
|
23867
|
-
async execute(input) {
|
|
25542
|
+
async execute(input, ctx) {
|
|
23868
25543
|
const timeoutMs = perServerTimeoutMs ?? mcpEnvConfig.toolTimeoutMs ?? 120000;
|
|
23869
25544
|
try {
|
|
23870
|
-
const result = await bridge.request("sdk_mcp_call", { server: serverName, tool: tool.name, arguments: input && typeof input === "object" ? input : {} }, { timeoutMs });
|
|
25545
|
+
const result = await bridge.request("sdk_mcp_call", { server: serverName, tool: tool.name, arguments: input && typeof input === "object" ? input : {} }, { timeoutMs, ...ctx?.signal !== undefined ? { signal: ctx.signal, cancelGraceMs: SDK_MCP_CANCEL_GRACE_MS } : {} });
|
|
23871
25546
|
const text = (result.content ?? []).map((block) => typeof block.text === "string" ? block.text : JSON.stringify(block)).join(`
|
|
23872
25547
|
`);
|
|
23873
25548
|
return { output: text, ...result.isError === true ? { isError: true } : {} };
|
|
@@ -26153,34 +27828,77 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26153
27828
|
...callRecord.moved !== undefined ? { nativeState: callRecord.moved.nativeState } : {},
|
|
26154
27829
|
...generationEffort ?? {}
|
|
26155
27830
|
});
|
|
26156
|
-
const
|
|
27831
|
+
const slots = turn.calls.map(() => {
|
|
27832
|
+
return;
|
|
27833
|
+
});
|
|
26157
27834
|
const hostSiteIcons = new Map;
|
|
26158
27835
|
let toolThrowText = null;
|
|
27836
|
+
const throwTextByIndex = new Map;
|
|
27837
|
+
let lateFailure;
|
|
26159
27838
|
let structuredTerminated = false;
|
|
26160
27839
|
const truncatedByOutputLimit = turn.stopReason === "max_tokens";
|
|
26161
|
-
|
|
27840
|
+
const sentToHost = new Set;
|
|
27841
|
+
const sendResultToHost = (index) => {
|
|
27842
|
+
const block = slots[index];
|
|
27843
|
+
if (block === undefined || sentToHost.has(index))
|
|
27844
|
+
return;
|
|
27845
|
+
sentToHost.add(index);
|
|
27846
|
+
output.write({ type: "data", message: { type: "user", message: { content: hostToolResultContent([block], hostSiteIcons) } } });
|
|
27847
|
+
};
|
|
27848
|
+
const inFlight = new Set;
|
|
27849
|
+
const deferredPostToolEffects = new Map;
|
|
27850
|
+
const applyFinishedStops = () => {
|
|
27851
|
+
if (turnStop.request !== undefined)
|
|
27852
|
+
return;
|
|
27853
|
+
for (const index of [...deferredPostToolEffects.keys()].sort((a, b) => a - b)) {
|
|
27854
|
+
const stop = deferredPostToolEffects.get(index).stop;
|
|
27855
|
+
if (stop !== undefined) {
|
|
27856
|
+
turnStop.request = stop;
|
|
27857
|
+
return;
|
|
27858
|
+
}
|
|
27859
|
+
}
|
|
27860
|
+
};
|
|
27861
|
+
const settleConcurrent = async () => {
|
|
27862
|
+
while (inFlight.size > 0)
|
|
27863
|
+
await Promise.all([...inFlight]);
|
|
27864
|
+
for (const index of [...deferredPostToolEffects.keys()].sort((a, b) => a - b))
|
|
27865
|
+
deferredPostToolEffects.get(index).apply();
|
|
27866
|
+
deferredPostToolEffects.clear();
|
|
27867
|
+
};
|
|
27868
|
+
const deferPostToolEffects = (index, composite, hookName, apply) => {
|
|
27869
|
+
const prevent = composite.preventContinuation;
|
|
27870
|
+
deferredPostToolEffects.set(index, {
|
|
27871
|
+
apply,
|
|
27872
|
+
...prevent !== undefined ? { stop: { hookName, ...prevent.reason !== undefined ? { reason: prevent.reason } : {} } } : {}
|
|
27873
|
+
});
|
|
27874
|
+
};
|
|
27875
|
+
const processCall = async (emitted, index, mode) => {
|
|
27876
|
+
const record = (block) => {
|
|
27877
|
+
slots[index] = block;
|
|
27878
|
+
};
|
|
26162
27879
|
const resolvedName = currentToolName(emitted.name);
|
|
26163
27880
|
const call = resolvedName !== emitted.name ? { ...emitted, name: resolvedName } : emitted;
|
|
27881
|
+
applyFinishedStops();
|
|
26164
27882
|
const stoppedBy = currentTurnStop();
|
|
26165
27883
|
if (stoppedBy !== undefined) {
|
|
26166
|
-
|
|
26167
|
-
|
|
27884
|
+
record({ type: "tool_result", tool_use_id: call.id, content: `[not executed: the ${stoppedBy.hookName} hook stopped the turn]`, error: true });
|
|
27885
|
+
return "next";
|
|
26168
27886
|
}
|
|
26169
27887
|
if (truncatedByOutputLimit) {
|
|
26170
|
-
|
|
26171
|
-
|
|
27888
|
+
record({ type: "tool_result", tool_use_id: call.id, content: OUTPUT_LIMIT_TRUNCATED_CALL_TEXT, is_error: true });
|
|
27889
|
+
return "next";
|
|
26172
27890
|
}
|
|
26173
27891
|
if (structuredOutputActive && structuredOutput !== undefined && call.name === STRUCTURED_OUTPUT_TOOL_NAME) {
|
|
26174
27892
|
structuredOutputAttempts++;
|
|
26175
27893
|
const validation = structuredOutput.validate(outputFormatSchema, call.input);
|
|
26176
27894
|
if (validation.ok) {
|
|
26177
|
-
|
|
27895
|
+
record({ type: "tool_result", tool_use_id: call.id, content: "Structured output accepted." });
|
|
26178
27896
|
finalResult = { type: "result", subtype: "success", is_error: false, structured_output: validation.value };
|
|
26179
27897
|
structuredTerminated = true;
|
|
26180
|
-
|
|
27898
|
+
return "stop";
|
|
26181
27899
|
}
|
|
26182
27900
|
if (structuredOutputAttempts >= maxStructuredOutputAttempts) {
|
|
26183
|
-
|
|
27901
|
+
record({ type: "tool_result", tool_use_id: call.id, content: `Structured output validation failed: ${validation.errors.join("; ")}`, error: true });
|
|
26184
27902
|
finalResult = {
|
|
26185
27903
|
type: "result",
|
|
26186
27904
|
subtype: "error_max_structured_output_retries",
|
|
@@ -26189,26 +27907,26 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26189
27907
|
terminal_reason: "structured_output_retry_exhausted"
|
|
26190
27908
|
};
|
|
26191
27909
|
structuredTerminated = true;
|
|
26192
|
-
|
|
27910
|
+
return "stop";
|
|
26193
27911
|
}
|
|
26194
|
-
|
|
26195
|
-
|
|
27912
|
+
record({ type: "tool_result", tool_use_id: call.id, content: `Structured output validation failed: ${validation.errors.join("; ")}. Call ${STRUCTURED_OUTPUT_TOOL_NAME} again with a corrected value.`, error: true });
|
|
27913
|
+
return "next";
|
|
26196
27914
|
}
|
|
26197
27915
|
const callMcpServer = mcpServerIdentityForCall(call.name);
|
|
26198
27916
|
try {
|
|
26199
27917
|
const availabilityDescriptor = getRegisteredTool(call.name)?.descriptor;
|
|
26200
27918
|
if (availabilityDescriptor !== undefined && !isToolAvailable(availabilityDescriptor, { ...advertisedCfg, mode: policyStateStore.getState().mode })) {
|
|
26201
|
-
|
|
27919
|
+
record({
|
|
26202
27920
|
type: "tool_result",
|
|
26203
27921
|
tool_use_id: call.id,
|
|
26204
27922
|
content: `'${call.name}' is not available in this session's current configuration (WS-06 §1.5 availability) -- it is registered but excluded here, so it was not executed`,
|
|
26205
27923
|
error: true
|
|
26206
27924
|
});
|
|
26207
|
-
|
|
27925
|
+
return "next";
|
|
26208
27926
|
}
|
|
26209
27927
|
if (isDeferredAndUnloaded(call.name)) {
|
|
26210
27928
|
const excludedReason = aliasExclusionLive(call.name);
|
|
26211
|
-
|
|
27929
|
+
record(excludedReason !== undefined ? {
|
|
26212
27930
|
type: "tool_result",
|
|
26213
27931
|
tool_use_id: call.id,
|
|
26214
27932
|
content: `'${call.name}' is not available in this session: ${excludedReason}. It cannot be loaded with ToolSearch either -- the same exclusion removes it from the searchable pool.`,
|
|
@@ -26219,7 +27937,7 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26219
27937
|
content: `'${call.name}' is a deferred tool that has not been loaded this session yet -- use ToolSearch to select it before calling it (WS-09 §8.5)`,
|
|
26220
27938
|
loadFirst: true
|
|
26221
27939
|
});
|
|
26222
|
-
|
|
27940
|
+
return "next";
|
|
26223
27941
|
}
|
|
26224
27942
|
const permissionInput = typeof call.input === "object" && call.input !== null ? call.input : {};
|
|
26225
27943
|
const evalCtxForIdentity = makeEvalCtx();
|
|
@@ -26235,8 +27953,8 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26235
27953
|
const declaredIdentity = declaredMcpIdentity(call.name);
|
|
26236
27954
|
const notOffered = [...aliasPermissionIdentities(call.name, config.toolAliases, sessionBrand), ...declaredIdentity !== undefined ? [declaredIdentity] : []].some(probeRule("deny")) ? undefined : toolNotOfferedRefusal(call.name);
|
|
26237
27955
|
if (notOffered !== undefined) {
|
|
26238
|
-
|
|
26239
|
-
|
|
27956
|
+
record({ type: "tool_result", tool_use_id: call.id, content: notOffered, is_error: true });
|
|
27957
|
+
return "next";
|
|
26240
27958
|
}
|
|
26241
27959
|
const identityProbes = {
|
|
26242
27960
|
deniedByRule: probeRule("deny"),
|
|
@@ -26255,12 +27973,12 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26255
27973
|
const decisionRaced = await raceInterrupt(evaluateWithFreshPolicy(permissionCall), interruptSignal);
|
|
26256
27974
|
if (decisionRaced.kind === "interrupted") {
|
|
26257
27975
|
interrupted = true;
|
|
26258
|
-
|
|
27976
|
+
return "stop";
|
|
26259
27977
|
}
|
|
26260
27978
|
const decision = decisionRaced.value;
|
|
26261
27979
|
takeGatingHookComposites(call.id, call.name);
|
|
26262
27980
|
const denyCall = async (message, mechanism, ruleRef) => {
|
|
26263
|
-
|
|
27981
|
+
record({ type: "tool_result", tool_use_id: call.id, content: message, denied: true });
|
|
26264
27982
|
turnPermissionDenials.push({ tool_name: call.name, tool_use_id: call.id, tool_input: permissionCall.input });
|
|
26265
27983
|
output.write({
|
|
26266
27984
|
type: "data",
|
|
@@ -26288,7 +28006,7 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26288
28006
|
const deferMessage = decision.message ?? "a PreToolUse hook deferred this call for durable approval";
|
|
26289
28007
|
if (!approvalStore) {
|
|
26290
28008
|
await denyCall(`Denied: cannot defer -- no durable approval store is available for this session (${deferMessage})`, "hook");
|
|
26291
|
-
|
|
28009
|
+
return "next";
|
|
26292
28010
|
}
|
|
26293
28011
|
const requestId = randomUUID18();
|
|
26294
28012
|
const executedInput = decision.transformedInput ?? permissionCall.input;
|
|
@@ -26315,9 +28033,9 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26315
28033
|
} catch (err) {
|
|
26316
28034
|
const text = err instanceof Error ? err.message : String(err);
|
|
26317
28035
|
await denyCall(`Denied: failed to persist the durable approval record (${text})`, "hook");
|
|
26318
|
-
|
|
28036
|
+
return "next";
|
|
26319
28037
|
}
|
|
26320
|
-
|
|
28038
|
+
record({ type: "tool_result", tool_use_id: call.id, content: "[deferred]", deferred: true });
|
|
26321
28039
|
output.write({
|
|
26322
28040
|
type: "data",
|
|
26323
28041
|
message: {
|
|
@@ -26332,7 +28050,7 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26332
28050
|
uuid: randomUUID18()
|
|
26333
28051
|
}
|
|
26334
28052
|
});
|
|
26335
|
-
|
|
28053
|
+
return "next";
|
|
26336
28054
|
}
|
|
26337
28055
|
if (decision.decision !== "allow") {
|
|
26338
28056
|
const deniedMessage = decision.message ?? "Permission denied";
|
|
@@ -26340,9 +28058,9 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26340
28058
|
if (decision.interrupt === true) {
|
|
26341
28059
|
interrupted = true;
|
|
26342
28060
|
interruptCurrentTurn.current?.();
|
|
26343
|
-
|
|
28061
|
+
return "stop";
|
|
26344
28062
|
}
|
|
26345
|
-
|
|
28063
|
+
return "next";
|
|
26346
28064
|
}
|
|
26347
28065
|
if (decision.updatedPermissions) {
|
|
26348
28066
|
for (const update of decision.updatedPermissions) {
|
|
@@ -26373,18 +28091,47 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26373
28091
|
}
|
|
26374
28092
|
}
|
|
26375
28093
|
}
|
|
26376
|
-
|
|
26377
|
-
|
|
26378
|
-
|
|
26379
|
-
|
|
28094
|
+
if (interrupted || toolThrowText !== null || lateFailure !== undefined)
|
|
28095
|
+
return "stop";
|
|
28096
|
+
applyFinishedStops();
|
|
28097
|
+
const stoppedBeforeStart = currentTurnStop();
|
|
28098
|
+
if (stoppedBeforeStart !== undefined) {
|
|
28099
|
+
record({ type: "tool_result", tool_use_id: call.id, content: `[not executed: the ${stoppedBeforeStart.hookName} hook stopped the turn]`, error: true });
|
|
28100
|
+
return "next";
|
|
28101
|
+
}
|
|
28102
|
+
const laneTurn = mode.enterLane?.();
|
|
28103
|
+
mode.readyToExecute?.();
|
|
28104
|
+
if (laneTurn !== undefined) {
|
|
28105
|
+
const turnOfLane = await raceInterrupt(laneTurn, interruptSignal);
|
|
28106
|
+
if (turnOfLane.kind === "interrupted") {
|
|
28107
|
+
interrupted = true;
|
|
28108
|
+
return "stop";
|
|
28109
|
+
}
|
|
28110
|
+
if (interrupted || toolThrowText !== null || lateFailure !== undefined)
|
|
28111
|
+
return "stop";
|
|
28112
|
+
applyFinishedStops();
|
|
28113
|
+
const stoppedInLane = currentTurnStop();
|
|
28114
|
+
if (stoppedInLane !== undefined) {
|
|
28115
|
+
record({ type: "tool_result", tool_use_id: call.id, content: `[not executed: the ${stoppedInLane.hookName} hook stopped the turn]`, error: true });
|
|
28116
|
+
return "next";
|
|
28117
|
+
}
|
|
28118
|
+
}
|
|
28119
|
+
if (!mode.concurrent)
|
|
28120
|
+
toolReferenceCollector = [];
|
|
28121
|
+
const execution = tools.execute(executedCall, { signal: turnAbort.signal, ...decision.explicitApproval !== undefined ? { explicitApproval: decision.explicitApproval } : {} });
|
|
28122
|
+
mode.onExecution?.(execution);
|
|
28123
|
+
const raced = await raceInterrupt(execution, interruptSignal);
|
|
28124
|
+
const loadedTools = mode.concurrent ? [] : advertisedNamesFor(toolReferenceCollector);
|
|
28125
|
+
if (!mode.concurrent)
|
|
28126
|
+
toolReferenceCollector = undefined;
|
|
26380
28127
|
const loadedToolDefinitions = loadedDefinitionsFor(loadedTools);
|
|
26381
28128
|
const forkDefinitionsText = exactRequestLayout !== undefined ? forkLoadedDefinitionsText(loadedToolDefinitions) : "";
|
|
26382
28129
|
if (raced.kind === "interrupted") {
|
|
26383
28130
|
interrupted = true;
|
|
26384
|
-
|
|
28131
|
+
return "stop";
|
|
26385
28132
|
}
|
|
26386
28133
|
const resultBlocksOfCall = raced.value.blocks;
|
|
26387
|
-
|
|
28134
|
+
record({
|
|
26388
28135
|
type: "tool_result",
|
|
26389
28136
|
tool_use_id: call.id,
|
|
26390
28137
|
content: resultBlocksOfCall !== undefined ? forkDefinitionsText.length > 0 ? [...resultBlocksOfCall, { type: "text", text: forkDefinitionsText.trimStart() }] : [...resultBlocksOfCall] : forkDefinitionsText.length > 0 ? `${raced.value.output}${forkDefinitionsText}` : raced.value.output,
|
|
@@ -26407,57 +28154,154 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26407
28154
|
input: executedCall.input,
|
|
26408
28155
|
payload: { tool_response: raced.value.output }
|
|
26409
28156
|
});
|
|
26410
|
-
|
|
26411
|
-
|
|
26412
|
-
|
|
26413
|
-
|
|
28157
|
+
const postHookName = `${raced.value.isError === true ? "PostToolUseFailure" : "PostToolUse"}:${call.name}`;
|
|
28158
|
+
const applyPostToolEffects = () => {
|
|
28159
|
+
if (postToolUseHookOutcome.classifierContext !== undefined) {
|
|
28160
|
+
accumulatedClassifierContext.push(...postToolUseHookOutcome.classifierContext);
|
|
28161
|
+
}
|
|
28162
|
+
absorbHookComposite(postToolUseHookOutcome, { hookName: postHookName, context: true, toolUseID: call.id });
|
|
28163
|
+
};
|
|
28164
|
+
if (mode.concurrent)
|
|
28165
|
+
deferPostToolEffects(index, postToolUseHookOutcome, postHookName, applyPostToolEffects);
|
|
28166
|
+
else
|
|
28167
|
+
applyPostToolEffects();
|
|
26414
28168
|
if (postToolUseHookOutcome.transformedOutput !== undefined) {
|
|
26415
|
-
const
|
|
26416
|
-
if (
|
|
26417
|
-
|
|
28169
|
+
const own = slots[index];
|
|
28170
|
+
if (own !== undefined && own.type === "tool_result" && own.tool_use_id === call.id) {
|
|
28171
|
+
slots[index] = { ...own, content: toolOutputReplacement(postToolUseHookOutcome.transformedOutput) };
|
|
26418
28172
|
}
|
|
26419
28173
|
}
|
|
26420
28174
|
} catch (err) {
|
|
26421
28175
|
const text = err instanceof Error ? err.message : String(err);
|
|
26422
|
-
|
|
26423
|
-
toolThrowText
|
|
26424
|
-
|
|
28176
|
+
throwTextByIndex.set(index, text);
|
|
28177
|
+
if (toolThrowText === null) {
|
|
28178
|
+
finalResult = { type: "result", subtype: "error_during_execution", is_error: true, result: text };
|
|
28179
|
+
toolThrowText = text;
|
|
28180
|
+
}
|
|
28181
|
+
const failureOutcome = await fireObservationalHook("PostToolUseFailure", {
|
|
26425
28182
|
toolUseID: call.id,
|
|
26426
28183
|
toolName: postToolHookSubject("PostToolUseFailure", call.name),
|
|
26427
28184
|
...callMcpServer !== undefined ? { mcpServer: callMcpServer } : {},
|
|
26428
28185
|
input: typeof call.input === "object" && call.input !== null ? call.input : {},
|
|
26429
28186
|
payload: { error: text }
|
|
26430
|
-
})
|
|
28187
|
+
});
|
|
28188
|
+
const failureHookName = `PostToolUseFailure:${call.name}`;
|
|
28189
|
+
const applyFailureEffects = () => absorbHookComposite(failureOutcome, { hookName: failureHookName, context: true, toolUseID: call.id });
|
|
28190
|
+
if (mode.concurrent)
|
|
28191
|
+
deferPostToolEffects(index, failureOutcome, failureHookName, applyFailureEffects);
|
|
28192
|
+
else
|
|
28193
|
+
applyFailureEffects();
|
|
28194
|
+
return "stop";
|
|
28195
|
+
}
|
|
28196
|
+
return "next";
|
|
28197
|
+
};
|
|
28198
|
+
const bashReadOnlyContext = () => ({
|
|
28199
|
+
cwd: currentCwd,
|
|
28200
|
+
originalCwd: config.cwd,
|
|
28201
|
+
sandboxEnabled: sandboxSettingsForSession.enabled !== false && isSandboxAvailable()
|
|
28202
|
+
});
|
|
28203
|
+
for (let index = 0;index < turn.calls.length; index++) {
|
|
28204
|
+
const emitted = turn.calls[index];
|
|
28205
|
+
const scheduling = schedulingForCall(currentToolName(emitted.name), emitted.input, bashReadOnlyContext());
|
|
28206
|
+
if (scheduling.kind === "serial") {
|
|
28207
|
+
await settleConcurrent();
|
|
28208
|
+
} else {
|
|
28209
|
+
while (inFlight.size >= MAX_TOOL_CONCURRENCY)
|
|
28210
|
+
await Promise.race(inFlight);
|
|
28211
|
+
}
|
|
28212
|
+
if (interrupted || toolThrowText !== null || lateFailure !== undefined)
|
|
26431
28213
|
break;
|
|
28214
|
+
if (scheduling.kind === "serial") {
|
|
28215
|
+
try {
|
|
28216
|
+
const outcome = await processCall(emitted, index, { concurrent: false });
|
|
28217
|
+
sendResultToHost(index);
|
|
28218
|
+
if (outcome === "stop")
|
|
28219
|
+
break;
|
|
28220
|
+
} catch (error) {
|
|
28221
|
+
lateFailure = { error };
|
|
28222
|
+
break;
|
|
28223
|
+
}
|
|
28224
|
+
continue;
|
|
26432
28225
|
}
|
|
28226
|
+
let releaseLane;
|
|
28227
|
+
let laneExecution;
|
|
28228
|
+
const lane = scheduling.kind === "lane" ? scheduling.lane : undefined;
|
|
28229
|
+
const enterLane = lane !== undefined ? () => enterToolLane(sessionLaneTails, lane, new Promise((resolve) => releaseLane = resolve)) : undefined;
|
|
28230
|
+
let markReady;
|
|
28231
|
+
const ready = new Promise((resolve) => markReady = () => resolve("ready"));
|
|
28232
|
+
const settled = processCall(emitted, index, {
|
|
28233
|
+
concurrent: true,
|
|
28234
|
+
readyToExecute: markReady,
|
|
28235
|
+
...enterLane !== undefined ? { enterLane, onExecution: (execution) => {
|
|
28236
|
+
laneExecution = execution;
|
|
28237
|
+
} } : {}
|
|
28238
|
+
}).then((outcome) => {
|
|
28239
|
+
sendResultToHost(index);
|
|
28240
|
+
return outcome;
|
|
28241
|
+
}).catch((error) => {
|
|
28242
|
+
if (lateFailure === undefined)
|
|
28243
|
+
lateFailure = { error };
|
|
28244
|
+
return "stop";
|
|
28245
|
+
});
|
|
28246
|
+
const tracked = settled.finally(() => {
|
|
28247
|
+
inFlight.delete(tracked);
|
|
28248
|
+
const release = () => releaseLane?.();
|
|
28249
|
+
if (laneExecution !== undefined)
|
|
28250
|
+
laneExecution.then(release, release);
|
|
28251
|
+
else
|
|
28252
|
+
release();
|
|
28253
|
+
});
|
|
28254
|
+
inFlight.add(tracked);
|
|
28255
|
+
const first = await Promise.race([ready, settled]);
|
|
28256
|
+
if (first === "stop")
|
|
28257
|
+
break;
|
|
26433
28258
|
}
|
|
28259
|
+
await settleConcurrent();
|
|
26434
28260
|
if (toolThrowText !== null) {
|
|
26435
|
-
|
|
26436
|
-
|
|
26437
|
-
|
|
26438
|
-
|
|
26439
|
-
|
|
26440
|
-
|
|
28261
|
+
turn.calls.forEach((call, index) => {
|
|
28262
|
+
if (slots[index] === undefined)
|
|
28263
|
+
slots[index] = { type: "tool_result", tool_use_id: call.id, content: `[error: ${throwTextByIndex.get(index) ?? toolThrowText}]`, error: true };
|
|
28264
|
+
});
|
|
28265
|
+
}
|
|
28266
|
+
if (lateFailure !== undefined) {
|
|
28267
|
+
const failure = lateFailure.error;
|
|
28268
|
+
const text = failure instanceof Error ? failure.message : String(failure);
|
|
28269
|
+
turn.calls.forEach((call, index) => {
|
|
28270
|
+
if (slots[index] === undefined)
|
|
28271
|
+
slots[index] = { type: "tool_result", tool_use_id: call.id, content: `[error: ${text}]`, error: true };
|
|
28272
|
+
});
|
|
26441
28273
|
}
|
|
26442
28274
|
if (structuredTerminated) {
|
|
26443
|
-
|
|
26444
|
-
|
|
26445
|
-
|
|
26446
|
-
|
|
26447
|
-
}
|
|
26448
|
-
}
|
|
28275
|
+
turn.calls.forEach((call, index) => {
|
|
28276
|
+
if (slots[index] === undefined)
|
|
28277
|
+
slots[index] = { type: "tool_result", tool_use_id: call.id, content: "[not executed: the turn ended on a structured-output result]", error: true };
|
|
28278
|
+
});
|
|
26449
28279
|
}
|
|
26450
28280
|
if (interrupted) {
|
|
26451
|
-
|
|
26452
|
-
|
|
26453
|
-
|
|
26454
|
-
|
|
26455
|
-
|
|
28281
|
+
turn.calls.forEach((call, index) => {
|
|
28282
|
+
if (slots[index] === undefined)
|
|
28283
|
+
slots[index] = { type: "tool_result", tool_use_id: call.id, content: "[interrupted]", interrupted: true };
|
|
28284
|
+
});
|
|
28285
|
+
}
|
|
28286
|
+
turn.calls.forEach((call, index) => {
|
|
28287
|
+
if (slots[index] === undefined)
|
|
28288
|
+
slots[index] = { type: "tool_result", tool_use_id: call.id, content: "[not executed]", error: true };
|
|
28289
|
+
});
|
|
28290
|
+
const resultBlocks = slots;
|
|
28291
|
+
const unsent = resultBlocks.filter((_, index) => !sentToHost.has(index));
|
|
28292
|
+
if (unsent.length > 0) {
|
|
28293
|
+
try {
|
|
28294
|
+
output.write({ type: "data", message: { type: "user", message: { content: hostToolResultContent(unsent, hostSiteIcons) } } });
|
|
28295
|
+
} catch (error) {
|
|
28296
|
+
if (lateFailure === undefined)
|
|
28297
|
+
lateFailure = { error };
|
|
26456
28298
|
}
|
|
28299
|
+
resultBlocks.forEach((_, index) => sentToHost.add(index));
|
|
26457
28300
|
}
|
|
26458
|
-
output.write({ type: "data", message: { type: "user", message: { content: withHostSiteIcons(toolResultsForHost(resultBlocks.map((b) => b.type === "tool_result" && b.loadedTools !== undefined ? withoutLoadedTools(b) : b)), hostSiteIcons) } } });
|
|
26459
28301
|
messages.push({ role: "tool", content: resultBlocks });
|
|
26460
28302
|
await recordUser(resultBlocks);
|
|
28303
|
+
if (lateFailure !== undefined)
|
|
28304
|
+
throw lateFailure.error;
|
|
26461
28305
|
await flushPendingHookAttachments();
|
|
26462
28306
|
gatingHookComposites.clear();
|
|
26463
28307
|
if (finalResult)
|
|
@@ -26534,7 +28378,7 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
|
|
|
26534
28378
|
}
|
|
26535
28379
|
|
|
26536
28380
|
// src/provider/mock.ts
|
|
26537
|
-
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
28381
|
+
import { createHash as createHash2, randomUUID as randomUUID19 } from "node:crypto";
|
|
26538
28382
|
|
|
26539
28383
|
// src/compaction/summarizer.ts
|
|
26540
28384
|
var WINTER_SUMMARY_INSTRUCTION = "You are compacting a conversation so that it can continue with less context. " + "Summarize the conversation above as clear declarative statements of what is true and what was decided -- " + "not as a paraphrase of the most recent message and not as an acknowledgement. " + "Preserve every specific verbatim: numbers, names, file paths, identifiers, exact values, and any decision that was made or reversed. " + "Record work still outstanding as well as work completed. " + "Be concise but complete; never drop a fact to save words. " + "Output the summary text and nothing else.";
|
|
@@ -26719,7 +28563,7 @@ var TEST_PROVIDER_NAMES = new Set([
|
|
|
26719
28563
|
"readimage",
|
|
26720
28564
|
"calls"
|
|
26721
28565
|
]);
|
|
26722
|
-
var CALL_LINE = /^CALL\s+(\S+)(?:\s+(.*))?$/;
|
|
28566
|
+
var CALL_LINE = /^(\+?)CALL\s+(\S+)(?:\s+(.*))?$/;
|
|
26723
28567
|
function promptedCallsProvider() {
|
|
26724
28568
|
return {
|
|
26725
28569
|
async generate({ messages }) {
|
|
@@ -26734,13 +28578,21 @@ function promptedCallsProvider() {
|
|
|
26734
28578
|
}
|
|
26735
28579
|
if (at < 0)
|
|
26736
28580
|
return { kind: "text", text: "[]" };
|
|
26737
|
-
const
|
|
26738
|
-
|
|
28581
|
+
const rounds = [];
|
|
28582
|
+
for (const m of userMessageText(messages[at]).split(`
|
|
28583
|
+
`).map((line) => CALL_LINE.exec(line.trim())).filter((m) => m !== null)) {
|
|
28584
|
+
const call = { name: m[2], input: m[3] !== undefined && m[3].trim() !== "" ? JSON.parse(m[3]) : {} };
|
|
28585
|
+
if (m[1] === "+" && rounds.length > 0)
|
|
28586
|
+
rounds[rounds.length - 1].push(call);
|
|
28587
|
+
else
|
|
28588
|
+
rounds.push([call]);
|
|
28589
|
+
}
|
|
26739
28590
|
const after = messages.slice(at + 1);
|
|
26740
28591
|
const made = after.filter((m) => m.role === "assistant" && Array.isArray(m.content) && m.content.some((b) => b.type === "tool_use")).length;
|
|
26741
|
-
if (made <
|
|
26742
|
-
const
|
|
26743
|
-
|
|
28592
|
+
if (made < rounds.length) {
|
|
28593
|
+
const script = createHash2("sha256").update(userMessageText(messages[at])).digest("hex").slice(0, 6);
|
|
28594
|
+
const round = rounds[made];
|
|
28595
|
+
return { kind: "tool_use", calls: round.map((next, i) => ({ id: `calls-${script}-${at + 1}-${made + 1}${i === 0 ? "" : `-${i + 1}`}`, name: next.name, input: next.input })) };
|
|
26744
28596
|
}
|
|
26745
28597
|
const results = after.flatMap((m) => Array.isArray(m.content) ? m.content : []).filter((b) => b.type === "tool_result");
|
|
26746
28598
|
const named = new Map(after.flatMap((m) => m.role === "assistant" && Array.isArray(m.content) ? m.content : []).flatMap((b) => b.type === "tool_use" ? [[b.id, b.name]] : []));
|
|
@@ -27369,7 +29221,7 @@ function rebuildProviderMessages2(entries) {
|
|
|
27369
29221
|
|
|
27370
29222
|
// src/store/dialect.ts
|
|
27371
29223
|
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
27372
|
-
import { join as
|
|
29224
|
+
import { join as join27 } from "node:path";
|
|
27373
29225
|
import {
|
|
27374
29226
|
WinterCompatibilitySessionStore,
|
|
27375
29227
|
DIALECT_RECORD_ENTRY_TYPE,
|
|
@@ -27675,10 +29527,10 @@ class TranscriptWriter2 {
|
|
|
27675
29527
|
return entries;
|
|
27676
29528
|
}
|
|
27677
29529
|
}
|
|
27678
|
-
var RUNTIME_ENGINE_VERSION2 = "0.0.
|
|
29530
|
+
var RUNTIME_ENGINE_VERSION2 = "0.0.41";
|
|
27679
29531
|
function withPermissionJournal(writer, location) {
|
|
27680
29532
|
return {
|
|
27681
|
-
transcriptPath:
|
|
29533
|
+
transcriptPath: join27(location.winterHome, "projects", location.projectKey, `${location.sessionId}.jsonl`),
|
|
27682
29534
|
recordUserEntry: (content, opts) => writer.recordUserEntry(content, opts),
|
|
27683
29535
|
recordAssistantEntry: (content, opts) => writer.recordAssistantEntry(content, opts),
|
|
27684
29536
|
recordAttachmentEntry: (attachment) => writer.recordAttachmentEntry(attachment),
|
|
@@ -27706,7 +29558,7 @@ function buildWriter(opts) {
|
|
|
27706
29558
|
ctx: { sessionId: opts.sessionId, cwd: opts.cwd, version: RUNTIME_ENGINE_VERSION2, projectDirName: opts.projectKey },
|
|
27707
29559
|
initialParentUuid: opts.initialParentUuid,
|
|
27708
29560
|
...opts.initialConversationalUuids !== undefined ? { initialConversationalUuids: opts.initialConversationalUuids } : {},
|
|
27709
|
-
providerStateSink: createFileProviderStateSink(providerStateSidecarPath(
|
|
29561
|
+
providerStateSink: createFileProviderStateSink(providerStateSidecarPath(join27(opts.winterHome, "projects", opts.projectKey, `${opts.sessionId}.jsonl`)))
|
|
27710
29562
|
});
|
|
27711
29563
|
return withPermissionJournal(writer, { winterHome: opts.winterHome, projectKey: opts.projectKey, sessionId: opts.sessionId });
|
|
27712
29564
|
}
|
|
@@ -27719,7 +29571,7 @@ function buildChildTranscriptWriter(opts) {
|
|
|
27719
29571
|
key: { projectKey: opts.projectKey, sessionId: opts.parentSessionId, subpath: childTranscriptSubpath(opts.agentId) },
|
|
27720
29572
|
ctx: { sessionId: opts.parentSessionId, cwd: opts.cwd, version: RUNTIME_ENGINE_VERSION2, projectDirName: opts.projectKey },
|
|
27721
29573
|
sidechain: { agentId: opts.agentId, parentToolUseId: opts.parentToolUseId },
|
|
27722
|
-
...opts.winterHome !== undefined ? { providerStateSink: createFileProviderStateSink(providerStateSidecarPath(
|
|
29574
|
+
...opts.winterHome !== undefined ? { providerStateSink: createFileProviderStateSink(providerStateSidecarPath(join27(opts.winterHome, "projects", opts.projectKey, opts.parentSessionId, `${childTranscriptSubpath(opts.agentId)}.jsonl`))) } : {}
|
|
27723
29575
|
});
|
|
27724
29576
|
}
|
|
27725
29577
|
var CHILD_SUBKEY_PATTERN = /^subagents\/agent-(.+)$/;
|
|
@@ -28401,4 +30253,4 @@ function selectClassifierRoute2(config, descriptorOf) {
|
|
|
28401
30253
|
return { kind: "worker-eligible" };
|
|
28402
30254
|
}
|
|
28403
30255
|
|
|
28404
|
-
export { ChildResumeModeIncomparableError, resolveChildResumeMode, ensureDefaultMessagingRuntimeRegistered, buildContinuationChain, AGENT_TOOL_CANONICAL_NAME, computeActiveSlotSet, resolveSlotToProvider, createRpcBridge2, shellWords, escapeRegExpLiteral, validatePermissionRuleString, registerTool2, getRegisteredTool, listRegisteredTools, rebrandStandingServerTools, mcpServerHasRegistrations, onCompaction2, STRUCTURED_OUTPUT_TOOL_NAME, looksLikeCommand, matchFileRule, resolveFileRuleAbsolutePath, resolveFileRuleAbsoluteGlobText, resolvesWithinPluginRoot, buildWorkflowWorkerSeatbeltProfile2, capBytes, neutralizeReminderTags, readWhole, readCappedLinesAndBytes, registerAttachmentRenderer, attachmentsIn, registerChildEngineFactory, rawToRuleValue, sourceRule, parseFrontmatter, parseAgentDefinitionFile, allowedAgentTypesFromTools, validateAgentDefinition, WinterPathsError2, sessionTempDir2, ensureTasksDir2, resolveProjectDirName2, buildForkDirectiveText, buildForkInitialMessages, gitInstructionsEnabled, isUserInvocable, buildSkillListing, registerPluginAgents, clearPluginAgents, registerSkillSessionRuntime, clearSkillSessionRuntime, buildHookEntriesFromSettings, defaultTrustSource, formatValidationErrors, createSchemaValidatorCache, killAllTaskProcessGroups, runGit, listWorktrees, canonicalAliases, WINTER_CANONICAL_ALIASES, DEFAULT_SKILL_BODY_BYTES, skillNameError, pluginNameError, capBytes2, parseSkillFile, validateSkillsOption, isSkillEnabled, autoSkillPermissionEntries, setHostWorkflowWorkerCommand, listWorkflowsForListing, buildWorkflowSkillPrompt, WORKFLOW_SANDBOX_REFUSED_EXIT_CODE2, DEFAULT_CONTEXT_WINDOW_TOKENS2, ProviderTurnError, isProviderTurnError, createContextAccountant2, runEngine2, WINTER_SUMMARY_INSTRUCTION, WINTER_PREFIX_SUMMARY_INSTRUCTION, CARRIED_SUMMARY_NOTE, retainedExchangesNote, buildSummaryInstruction, redactForSummary, summarize, summarizeOverPrefix, recordedProviderSystems2, resetRecordedProviderSystems2, echoProvider2, scriptedProvider2, stubExecutor2, P5_FIXTURE_SKILL_NAME2, P5_WORKFLOW_SCRIPT2, isTestProviderName2, testProviderForNamespace, testProviderByName2, SUBAGENT_CHILD_PROBE_TEXT2, MCP_SDK_TEST_SERVER_NAME2, MCP_SDK_TEST_TOOL_NAME2, BGTASK_TEST_TOOL_NAME2, registerBgTaskTestTool2, ResumeTargetError2, ResumeTruncationError2, findContinueTarget2, findResumeTarget2, toDialectEntries2, truncateAt2, rebuildProviderMessages2, userEntry2, winterMessageIdFor2, assistantEntry2, CLAUDE_COMPACT_SUMMARY_PREAMBLE2, claudeCompactBoundaryEntry2, claudeCompactSummaryEntry2, TranscriptWriterError2, TranscriptWriter2, RUNTIME_ENGINE_VERSION2, childTranscriptSubpath, buildChildTranscriptWriter, listChildAgentIds, resolveEngineSession2, resolveProductionWinterHome2, resolveProductionStoreHome, resolveSessionProvider, redactCredentialRef, createProviderContext, providerCredentialRef2, storeProviderCredential2, deleteProviderCredential2, validateProviderCredential2, CLASSIFIER_TOOL_NAME2, CLASSIFIER_VERDICT_SCHEMA2, CLASSIFIER_NO_VERDICT_REASONS2, DEFAULT_MAX_CONTEXT_CHARS2, CLASSIFIER_SYSTEM_PROMPT2, DEFAULT_CLASSIFIER_TIMEOUT_MS2, createModelClassifier2, selectClassifierRoute2 };
|
|
30256
|
+
export { ChildResumeModeIncomparableError, resolveChildResumeMode, ensureDefaultMessagingRuntimeRegistered, buildContinuationChain, AGENT_TOOL_CANONICAL_NAME, computeActiveSlotSet, resolveSlotToProvider, createRpcBridge2, shellWords, escapeRegExpLiteral, validatePermissionRuleString, registerTool2, getRegisteredTool, listRegisteredTools, rebrandStandingServerTools, mcpServerHasRegistrations, onCompaction2, STRUCTURED_OUTPUT_TOOL_NAME, looksLikeCommand, matchFileRule, resolveFileRuleAbsolutePath, resolveFileRuleAbsoluteGlobText, resolvesWithinPluginRoot, buildWorkflowWorkerSeatbeltProfile2, capBytes, neutralizeReminderTags, readWhole, readCappedLinesAndBytes, registerAttachmentRenderer, attachmentsIn, registerChildEngineFactory, rawToRuleValue, sourceRule, parseFrontmatter, parseAgentDefinitionFile, allowedAgentTypesFromTools, validateAgentDefinition, WinterPathsError2, sessionTempDir2, ensureTasksDir2, resolveProjectDirName2, buildForkDirectiveText, buildForkInitialMessages, gitInstructionsEnabled, isUserInvocable, buildSkillListing, registerPluginAgents, clearPluginAgents, registerSkillSessionRuntime, clearSkillSessionRuntime, buildHookEntriesFromSettings, defaultTrustSource, formatValidationErrors, createSchemaValidatorCache, killAllTaskProcessGroups, runGit, listWorktrees, canonicalAliases, WINTER_CANONICAL_ALIASES, DEFAULT_SKILL_BODY_BYTES, skillNameError, pluginNameError, capBytes2, parseSkillFile, validateSkillsOption, isSkillEnabled, autoSkillPermissionEntries, setHostWorkflowWorkerCommand, listWorkflowsForListing, buildWorkflowSkillPrompt, WORKFLOW_SANDBOX_REFUSED_EXIT_CODE2, createToolLaneTails, DEFAULT_CONTEXT_WINDOW_TOKENS2, ProviderTurnError, isProviderTurnError, createContextAccountant2, runEngine2, WINTER_SUMMARY_INSTRUCTION, WINTER_PREFIX_SUMMARY_INSTRUCTION, CARRIED_SUMMARY_NOTE, retainedExchangesNote, buildSummaryInstruction, redactForSummary, summarize, summarizeOverPrefix, recordedProviderSystems2, resetRecordedProviderSystems2, echoProvider2, scriptedProvider2, stubExecutor2, P5_FIXTURE_SKILL_NAME2, P5_WORKFLOW_SCRIPT2, isTestProviderName2, testProviderForNamespace, testProviderByName2, SUBAGENT_CHILD_PROBE_TEXT2, MCP_SDK_TEST_SERVER_NAME2, MCP_SDK_TEST_TOOL_NAME2, BGTASK_TEST_TOOL_NAME2, registerBgTaskTestTool2, ResumeTargetError2, ResumeTruncationError2, findContinueTarget2, findResumeTarget2, toDialectEntries2, truncateAt2, rebuildProviderMessages2, userEntry2, winterMessageIdFor2, assistantEntry2, CLAUDE_COMPACT_SUMMARY_PREAMBLE2, claudeCompactBoundaryEntry2, claudeCompactSummaryEntry2, TranscriptWriterError2, TranscriptWriter2, RUNTIME_ENGINE_VERSION2, childTranscriptSubpath, buildChildTranscriptWriter, listChildAgentIds, resolveEngineSession2, resolveProductionWinterHome2, resolveProductionStoreHome, resolveSessionProvider, redactCredentialRef, createProviderContext, providerCredentialRef2, storeProviderCredential2, deleteProviderCredential2, validateProviderCredential2, CLASSIFIER_TOOL_NAME2, CLASSIFIER_VERDICT_SCHEMA2, CLASSIFIER_NO_VERDICT_REASONS2, DEFAULT_MAX_CONTEXT_CHARS2, CLASSIFIER_SYSTEM_PROMPT2, DEFAULT_CLASSIFIER_TIMEOUT_MS2, createModelClassifier2, selectClassifierRoute2 };
|