@sema-agent/core 7.29.0 → 7.30.0
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/CHANGELOG.md +361 -0
- package/dist/agents/child-model-seat.d.ts +59 -7
- package/dist/agents/child-model-seat.js +33 -7
- package/dist/agents/cross-session-judge.d.ts +27 -5
- package/dist/agents/cross-session-judge.js +23 -12
- package/dist/agents/list-agents-tool.d.ts +31 -6
- package/dist/agents/list-agents-tool.js +66 -14
- package/dist/agents/peer-admission.d.ts +20 -8
- package/dist/agents/peer-admission.js +21 -12
- package/dist/agents/peer-directory.d.ts +29 -0
- package/dist/agents/peer-directory.js +20 -0
- package/dist/agents/peer-held-queue.d.ts +31 -4
- package/dist/agents/peer-held-queue.js +32 -1
- package/dist/agents/peer-session-drain.d.ts +91 -13
- package/dist/agents/peer-session-drain.js +409 -102
- package/dist/agents/read-inbox-tool.d.ts +22 -0
- package/dist/agents/read-inbox-tool.js +39 -0
- package/dist/agents/roster-store.d.ts +2 -4
- package/dist/agents/roster-store.js +1 -1
- package/dist/agents/send-message-tool.d.ts +4 -4
- package/dist/agents/send-message-tool.js +22 -2
- package/dist/agents/subagent.js +62 -44
- package/dist/agents/team-role.d.ts +34 -0
- package/dist/agents/team-role.js +17 -0
- package/dist/agents/verify.js +2 -2
- package/dist/core/auto-compaction.d.ts +42 -0
- package/dist/core/auto-compaction.js +35 -2
- package/dist/core/child-clamp-seats.d.ts +11 -0
- package/dist/core/child-clamp-seats.js +3 -0
- package/dist/core/context-edit.d.ts +3 -2
- package/dist/core/context-edit.js +6 -5
- package/dist/core/context-guard.d.ts +2 -1
- package/dist/core/context-guard.js +3 -2
- package/dist/core/context-settings.d.ts +103 -0
- package/dist/core/context-settings.js +60 -0
- package/dist/core/engine-notice.d.ts +11 -1
- package/dist/core/frame-settlement.d.ts +97 -0
- package/dist/core/frame-settlement.js +36 -0
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +10 -10
- package/dist/core/mailbox-store.d.ts +41 -7
- package/dist/core/mailbox-store.js +9 -3
- package/dist/core/parent-spec-seat.d.ts +14 -1
- package/dist/core/parent-spec-seat.js +6 -0
- package/dist/core/permission-rule-model.js +1 -1
- package/dist/core/roles.d.ts +20 -0
- package/dist/core/roles.js +35 -16
- package/dist/core/runner/assemble-result.d.ts +2 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/compaction-call-options.d.ts +26 -2
- package/dist/core/runner/compaction-call-options.js +9 -0
- package/dist/core/runner/compaction-seams.d.ts +4 -3
- package/dist/core/runner/compaction-seams.js +13 -6
- package/dist/core/runner/contracts.d.ts +56 -7
- package/dist/core/runner/decide-continuation.d.ts +2 -1
- package/dist/core/runner/decide-continuation.js +11 -10
- package/dist/core/runner/initial-run-state.js +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.js +9 -1
- package/dist/core/runner/prepare-config-doors.js +4 -1
- package/dist/core/runner/prepare-context-lane.d.ts +9 -2
- package/dist/core/runner/prepare-context-lane.js +15 -10
- package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
- package/dist/core/runner/prepare-delegation-surface.js +9 -3
- package/dist/core/runner/prepare-file-history.js +10 -8
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -0
- package/dist/core/runner/prepare-gate-stations.js +3 -1
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +6 -0
- package/dist/core/runner/prepare-prompt-inputs.js +2 -1
- package/dist/core/runner/prepare-task.js +22 -9
- package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -1
- package/dist/core/runner/prepare-wiring-manifest.js +6 -1
- package/dist/core/runner/retired-runner-deps.d.ts +3 -1
- package/dist/core/runner/retired-runner-deps.js +1 -0
- package/dist/core/runner/run-compaction-machinery.d.ts +4 -2
- package/dist/core/runner/run-compaction-machinery.js +5 -3
- package/dist/core/runner/run-harness-handlers.js +1 -1
- package/dist/core/runner/run-identity-wiring.js +19 -1
- package/dist/core/runner/run-leg.js +1 -1
- package/dist/core/runner/run-notification-lane.js +8 -2
- package/dist/core/runner/run-recovery-lanes.js +9 -5
- package/dist/core/runner/run-settle-and-teardown.d.ts +4 -22
- package/dist/core/runner/run-settle-and-teardown.js +6 -10
- package/dist/core/runner/run-stop-and-final-verify.js +1 -0
- package/dist/core/runner/run-terminal-adoption.js +5 -5
- package/dist/core/runner/run-turn-boundary.js +32 -5
- package/dist/core/runner/runtask.d.ts +8 -1
- package/dist/core/runner/runtask.js +32 -1
- package/dist/core/runner-deps.d.ts +44 -13
- package/dist/core/swappable-deps.d.ts +20 -4
- package/dist/core/swappable-deps.js +6 -1
- package/dist/core/task-event.d.ts +5 -0
- package/dist/core/task-notification.d.ts +144 -2
- package/dist/core/task-notification.js +154 -5
- package/dist/core/task-result.d.ts +14 -0
- package/dist/core/task-spec.d.ts +7 -0
- package/dist/core/tool-catalog-entries.js +2 -1
- package/dist/core/tool-conformance.js +1 -0
- package/dist/core/tool-policy.d.ts +9 -4
- package/dist/core/tool-spec.d.ts +14 -0
- package/dist/core/wiring-manifest.d.ts +12 -0
- package/dist/core/wiring-manifest.js +5 -1
- package/dist/engine/harness/agent-harness.d.ts +14 -1
- package/dist/engine/harness/agent-harness.js +28 -3
- package/dist/engine/harness/types.d.ts +3 -1
- package/dist/engine/llm/types.d.ts +8 -7
- package/dist/engine/llm/types.js +1 -1
- package/dist/engine/session/import-validate.js +4 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.js +7 -5
- package/dist/orchestration/run-workflow-tool.d.ts +4 -4
- package/dist/orchestration/workflow.d.ts +1 -1
- package/dist/orchestration/workflow.js +8 -5
- package/dist/shell/lex.d.ts +30 -51
- package/dist/shell/lex.js +237 -284
- package/dist/stores/cc/mailbox-store.js +3 -2
- package/dist/stores/file/corrupt-read-sink.d.ts +28 -2
- package/dist/stores/file/file-history-store.d.ts +2 -4
- package/dist/stores/file/file-history-store.js +1 -1
- package/dist/stores/file/fs-atomic.d.ts +16 -11
- package/dist/stores/file/fs-atomic.js +17 -6
- package/dist/stores/file/index.d.ts +5 -6
- package/dist/stores/file/index.js +1 -1
- package/dist/stores/file/mailbox-store.d.ts +4 -9
- package/dist/stores/file/mailbox-store.js +29 -30
- package/dist/stores/file/session-policy-store.d.ts +2 -0
- package/dist/stores/file/session-policy-store.js +1 -1
- package/dist/stores/file/session-store.d.ts +11 -7
- package/dist/stores/file/session-store.js +23 -16
- package/dist/stores/file/shared-ledger.js +3 -14
- package/dist/stores/file/tool-result-store.d.ts +2 -0
- package/dist/stores/file/tool-result-store.js +5 -2
- package/dist/stores/file/workflow-journal-store.js +14 -9
- package/dist/tools/fs/bash-program-position.d.ts +15 -24
- package/dist/tools/fs/bash-program-position.js +11 -29
- package/dist/tools/fs/bash-readonly-classifier.d.ts +125 -117
- package/dist/tools/fs/bash-readonly-classifier.js +400 -272
- package/dist/tools/fs/shell-read-check.js +3 -3
- package/dist/tools/fs/shell-read-establish.js +1 -1
- package/dist/tools/fs/shell-read-plan.d.ts +11 -6
- package/dist/tools/fs/shell-read-plan.js +167 -183
- package/dist/tools/fs/shell-read-word.d.ts +50 -0
- package/dist/tools/fs/shell-read-word.js +59 -0
- package/dist/tools/fs/shell-reentry-text.d.ts +10 -0
- package/dist/tools/fs/shell-reentry-text.js +73 -0
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +58 -8
- package/wire-changes/core@7.30.0.json +1821 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { lexShell, PARSE_FAILURE_SENTENCE, UNRESOLVED_SENTENCE,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { lexShell, PARSE_FAILURE_SENTENCE, UNRESOLVED_SENTENCE, substitutionsInHeredocBody, literalTildeSpelling, } from "../../shell/lex.js";
|
|
2
|
+
import { compoundArrayElements, dropDefinitionHeads, expandsOf, readOfText, readsOf, rewritten, spelledWithHome } from "./shell-read-word.js";
|
|
3
|
+
import { LAUNCHER_TABLE, SHELL_BLOCK_WORDS, programBasename, programPositionRunsShell, readProgramPosition, shellScanDeclineOf, } from "./bash-program-position.js";
|
|
4
|
+
import { ASSIGNMENT_VALUE_NOT_PATHS, INTERPRETER_INLINE_PROGRAMS, NO_PATH_OPERAND_COMMANDS, POLL_LOOP_MAX_BEATS, RECURSIVE_READ_FORMS, SHELL_REENTRY_PROGRAM_RE, UNMODELLED_BASE_MOVERS, argvProgramOf, homeMayBeRebound, attachedOptionPayloads, resolveOperandLexically, inlineProgramClause, interpreterKey, isPathShapedToken, readVerbOptionSlot, sedScriptSlotFiles, segmentSelectsRecursiveRead, slotValueCandidates, suppliesFirstOperandSlot, verbFirstOperandSlot, verbOptionsArePositionIndependent, } from "./bash-readonly-classifier.js";
|
|
4
5
|
import { isAbsolutePathForm } from "./safety.js";
|
|
6
|
+
import { codeBodies, reentryText } from "./shell-reentry-text.js";
|
|
5
7
|
export const READ_CANDIDATE_PROVENANCES = [
|
|
6
8
|
"operand",
|
|
7
9
|
"option_value",
|
|
@@ -16,39 +18,39 @@ export const READ_CANDIDATE_PROVENANCES = [
|
|
|
16
18
|
];
|
|
17
19
|
const NESTING_MAX = 4;
|
|
18
20
|
const BASE_CANDIDATE_MAX = 256;
|
|
19
|
-
function
|
|
21
|
+
function firstUnresolvedSentence(lexed) {
|
|
20
22
|
for (const segment of lexed.segments) {
|
|
21
23
|
for (const token of segment.tokens) {
|
|
22
24
|
const word = token.kind === "word" ? token : token.kind === "redirect" ? token.target : undefined;
|
|
23
|
-
if (word?.unresolved !== undefined
|
|
25
|
+
if (word?.unresolved !== undefined)
|
|
24
26
|
return UNRESOLVED_SENTENCE[word.unresolved];
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
return undefined;
|
|
28
30
|
}
|
|
29
|
-
export function planShellReads(command, decl, depth = 0) {
|
|
31
|
+
export function planShellReads(command, decl, depth = 0, homeRebound = false) {
|
|
30
32
|
const shape = { grouped: false, backgrounded: false, strayRedirection: false };
|
|
31
33
|
if (depth > NESTING_MAX)
|
|
32
34
|
return { segments: [], unreadable: `command text nested more than ${NESTING_MAX} levels deep`, shape };
|
|
33
|
-
const
|
|
34
|
-
const lexed = lexShell(foldHomeVariableSpelling(command, homeReassigned ? undefined : decl.homeDir), { mode: "lenient" });
|
|
35
|
+
const lexed = lexShell(command);
|
|
35
36
|
if ("parseFailure" in lexed)
|
|
36
37
|
return { segments: [], unreadable: PARSE_FAILURE_SENTENCE[lexed.parseFailure.reason], shape };
|
|
37
|
-
const
|
|
38
|
-
const
|
|
38
|
+
const home = homeRebound || homeMayBeRebound(command) ? undefined : decl.homeDir;
|
|
39
|
+
const unreadable = firstUnresolvedSentence(lexed);
|
|
40
|
+
const nestedPlan = (text) => planShellReads(text, decl, depth + 1, home === undefined);
|
|
39
41
|
const projected = lexed.segments.map((segment) => projectSegment(segment));
|
|
40
|
-
const facts = projected.map((p, si) => segmentFacts(lexed.segments[si], p, decl, nestedPlan));
|
|
42
|
+
const facts = projected.map((p, si) => segmentFacts(lexed.segments[si], p, decl, home, nestedPlan));
|
|
41
43
|
shape.grouped = projected.some((p) => p.grouped);
|
|
42
44
|
shape.backgrounded = lexed.segments.some((s) => s.connector === "&") || facts.some((f) => f.backgrounds === true);
|
|
43
|
-
shape.strayRedirection = projected.some((p) => p.
|
|
45
|
+
shape.strayRedirection = projected.some((p) => p.argv.length === 0 && p.redirects.length > 0);
|
|
44
46
|
const basesOf = facts.map(() => new Set());
|
|
45
47
|
const unmodelled = facts.map(() => false);
|
|
46
48
|
let candidates = [{ base: decl.cwd, skippedCd: -1 }];
|
|
47
49
|
let baseLost = false;
|
|
48
50
|
let floorBases;
|
|
49
|
-
const loseBase = (reachable) => {
|
|
51
|
+
const loseBase = (reachable, floorTarget) => {
|
|
50
52
|
baseLost = true;
|
|
51
|
-
floorBases ??= [...new Set(reachable.map((c) => c.base))];
|
|
53
|
+
floorBases ??= [...new Set([...reachable.map((c) => c.base), ...(floorTarget !== undefined ? [floorTarget] : [])])];
|
|
52
54
|
};
|
|
53
55
|
let andRunStart = 0;
|
|
54
56
|
let crossedAllAnd = true;
|
|
@@ -84,7 +86,7 @@ export function planShellReads(command, decl, depth = 0) {
|
|
|
84
86
|
if (move === undefined || baseLost)
|
|
85
87
|
return;
|
|
86
88
|
if (typeof move.target === "string" || move.target.expands !== false) {
|
|
87
|
-
loseBase(reachable);
|
|
89
|
+
loseBase(reachable, typeof move.target === "string" ? undefined : move.target.floorSpelled);
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
92
|
const target = move.target.spelled;
|
|
@@ -176,11 +178,7 @@ export function planShellReads(command, decl, depth = 0) {
|
|
|
176
178
|
function projectSegment(segment) {
|
|
177
179
|
const tokens = [...segment.tokens];
|
|
178
180
|
let grouped = tokens.some((t) => t.kind === "group");
|
|
179
|
-
|
|
180
|
-
const [a, b, c] = [tokens[k], tokens[k + 1], tokens[k + 2]];
|
|
181
|
-
if (a.kind === "word" && b.kind === "group" && b.op === "(" && c.kind === "group" && c.op === ")" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(a.folded))
|
|
182
|
-
tokens.splice(k, 3);
|
|
183
|
-
}
|
|
181
|
+
dropDefinitionHeads(tokens);
|
|
184
182
|
const words = tokens.filter((t) => {
|
|
185
183
|
if (t.kind !== "word")
|
|
186
184
|
return false;
|
|
@@ -191,23 +189,22 @@ function projectSegment(segment) {
|
|
|
191
189
|
return true;
|
|
192
190
|
});
|
|
193
191
|
return {
|
|
194
|
-
words: wordsOf({ ...segment, tokens: words }),
|
|
195
192
|
argv: words,
|
|
196
193
|
redirects: tokens.filter((t) => t.kind === "redirect"),
|
|
197
194
|
grouped,
|
|
198
195
|
};
|
|
199
196
|
}
|
|
200
|
-
function segmentFacts(segment, p, decl, nestedPlan) {
|
|
201
|
-
const facts = segmentFactsRead(segment, p, decl, nestedPlan);
|
|
197
|
+
function segmentFacts(segment, p, decl, home, nestedPlan) {
|
|
198
|
+
const facts = segmentFactsRead(segment, p, decl, home, nestedPlan);
|
|
202
199
|
const unresolvedRaw = new Set();
|
|
203
200
|
for (const t of segment.tokens) {
|
|
204
201
|
const w = t.kind === "word" ? t : t.kind === "redirect" ? t.target : undefined;
|
|
205
|
-
if (w
|
|
202
|
+
if (w !== undefined && w.pieces.some((p) => p.literal === undefined && p.expansion === undefined))
|
|
206
203
|
unresolvedRaw.add(w.raw);
|
|
207
204
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const unsettle = (c) => (unresolvedRaw.has(c.raw) && c.expands !== "unresolvable" ? { ...c, expands: "unresolvable" } : c);
|
|
205
|
+
const homeWithheld = home === undefined && decl.homeDir !== undefined;
|
|
206
|
+
const floor = (c) => { const f = c.expands === "unresolvable" && decl.homeDir !== undefined ? spelledWithHome(c.spelled, c.raw, decl.homeDir) : undefined; return f === undefined ? c : { ...c, floorSpelled: f }; };
|
|
207
|
+
const unsettle = (c) => floor((unresolvedRaw.has(c.raw) || (homeWithheld && c.spelled.startsWith("~"))) && c.expands !== "unresolvable" ? { ...c, expands: "unresolvable" } : c);
|
|
211
208
|
const move = facts.baseMove;
|
|
212
209
|
return {
|
|
213
210
|
...facts,
|
|
@@ -215,7 +212,7 @@ function segmentFacts(segment, p, decl, nestedPlan) {
|
|
|
215
212
|
...(move !== undefined && typeof move.target !== "string" ? { baseMove: { target: unsettle(move.target) } } : {}),
|
|
216
213
|
};
|
|
217
214
|
}
|
|
218
|
-
function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
215
|
+
function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
219
216
|
const nested = [];
|
|
220
217
|
for (const body of segment.substitutions)
|
|
221
218
|
nested.push(nestedPlan(body));
|
|
@@ -233,7 +230,7 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
233
230
|
}
|
|
234
231
|
if (unreadableHeredoc)
|
|
235
232
|
nested.push({ segments: [], unreadable: "a here-document body carries a substitution this lexer cannot delimit", shape: { grouped: false, backgrounded: false, strayRedirection: false } });
|
|
236
|
-
const redirects = p.redirects.map((r) => redirectFact(r));
|
|
233
|
+
const redirects = p.redirects.map((r) => redirectFact(r, home));
|
|
237
234
|
const reads = [];
|
|
238
235
|
for (const r of redirects)
|
|
239
236
|
if (r.direction === "in" && r.target !== undefined)
|
|
@@ -245,30 +242,30 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
245
242
|
redirects,
|
|
246
243
|
nested,
|
|
247
244
|
};
|
|
248
|
-
const toks = p.
|
|
249
|
-
const head = toks
|
|
250
|
-
if (head === "coproc" && toks
|
|
251
|
-
const tail = (from) => ({
|
|
252
|
-
const first = segmentFacts(segment, tail(1), decl, nestedPlan);
|
|
253
|
-
if (toks.
|
|
245
|
+
const toks = readsOf(p.argv, home);
|
|
246
|
+
const head = toks[0]?.folded;
|
|
247
|
+
if (head === "coproc" && toks[0].raw === head && toks.length > 1) {
|
|
248
|
+
const tail = (from) => ({ argv: p.argv.slice(from), redirects: p.redirects, grouped: p.grouped });
|
|
249
|
+
const first = segmentFacts(segment, tail(1), decl, home, nestedPlan);
|
|
250
|
+
if (toks.length < 3)
|
|
254
251
|
return { ...first, backgrounds: true };
|
|
255
|
-
const second = segmentFacts(segment, tail(2), decl, nestedPlan);
|
|
252
|
+
const second = segmentFacts(segment, tail(2), decl, home, nestedPlan);
|
|
256
253
|
const seen = new Set(first.nested.map((n) => JSON.stringify(n.segments.map((sg) => sg.text))));
|
|
257
254
|
const extraNested = second.nested.filter((n) => !seen.has(JSON.stringify(n.segments.map((sg) => sg.text))));
|
|
258
|
-
return { ...first, reads: [...first.reads, ...second.reads], nested: [...first.nested, ...extraNested], backgrounds: true };
|
|
255
|
+
return { ...first, ...(second.reentry === "shell" ? { reentry: second.reentry } : {}), reads: [...first.reads, ...second.reads], nested: [...first.nested, ...extraNested], backgrounds: true };
|
|
259
256
|
}
|
|
260
|
-
if (head !== undefined && toks
|
|
257
|
+
if (head !== undefined && toks[0].raw === head && SHELL_BLOCK_WORDS.has(head)) {
|
|
261
258
|
if (head === "for" || head === "select")
|
|
262
259
|
return { ...base, empty: false, launcherChain: [], declines: [], reads, moveProvable: false, loopHead: { beats: literalBeats(toks) }, loopEnd: false };
|
|
263
260
|
if (head === "done")
|
|
264
261
|
return { ...base, empty: false, launcherChain: [], declines: [], reads, moveProvable: false, loopEnd: true };
|
|
265
262
|
return { ...base, empty: false, launcherChain: [], declines: [], reads, moveProvable: false, loopEnd: false };
|
|
266
263
|
}
|
|
267
|
-
const pos = readProgramPosition(
|
|
264
|
+
const pos = readProgramPosition(p.argv);
|
|
268
265
|
const written = pos.written;
|
|
269
266
|
if (written === undefined)
|
|
270
|
-
return { ...base, empty: toks.
|
|
271
|
-
const loopHead = pos.controlWords.some((i) => toks
|
|
267
|
+
return { ...base, empty: toks.length === 0 && redirects.length === 0 && nested.length === 0, launcherChain: [], declines: [], reads, moveProvable: false, loopEnd: false };
|
|
268
|
+
const loopHead = pos.controlWords.some((i) => toks[i].folded === "while" || toks[i].folded === "until") ? { beats: undefined } : undefined;
|
|
272
269
|
const launcherChain = pos.launchers.map((l) => l.name);
|
|
273
270
|
const launcherIndices = new Set(pos.launchers.map((l) => l.index));
|
|
274
271
|
const declines = [];
|
|
@@ -281,24 +278,23 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
281
278
|
const verb = program === undefined ? undefined : { name: program.name, basename: program.basename, listed };
|
|
282
279
|
const envOpens = basename !== undefined && !NO_PATH_OPERAND_COMMANDS.has(basename);
|
|
283
280
|
for (const k of pos.assignments)
|
|
284
|
-
pushAssignment(reads, toks
|
|
281
|
+
pushAssignment(reads, toks[k].word, "env_assignment", envOpens);
|
|
285
282
|
for (const l of pos.launchers) {
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
reads.push(bare(raw, folded, "program_path"));
|
|
283
|
+
const r = toks[l.index];
|
|
284
|
+
if (isPathShapedToken(r.folded))
|
|
285
|
+
reads.push(bare(r, "program_path"));
|
|
290
286
|
}
|
|
291
287
|
{
|
|
292
288
|
const controlIndices = new Set(pos.controlWords);
|
|
293
289
|
const assignmentIndices = new Set(pos.assignments);
|
|
294
|
-
const chainEnd = pos.program?.index ?? toks.
|
|
290
|
+
const chainEnd = pos.program?.index ?? toks.length;
|
|
295
291
|
const launcherValueIndices = new Set();
|
|
296
292
|
for (const l of pos.launchers) {
|
|
297
293
|
const row = LAUNCHER_TABLE.get(programBasename(l.name));
|
|
298
294
|
if (row === undefined)
|
|
299
295
|
continue;
|
|
300
296
|
for (let j = l.index + 1; j < chainEnd; j++) {
|
|
301
|
-
const w = toks
|
|
297
|
+
const w = toks[j].folded;
|
|
302
298
|
if (!w.startsWith("-") || w === "-")
|
|
303
299
|
break;
|
|
304
300
|
const arity = row.optionArity.get(w);
|
|
@@ -311,24 +307,24 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
311
307
|
for (let j = 0; j < chainEnd; j++) {
|
|
312
308
|
if (launcherIndices.has(j) || controlIndices.has(j) || assignmentIndices.has(j) || launcherValueIndices.has(j) || j === written)
|
|
313
309
|
continue;
|
|
314
|
-
const
|
|
315
|
-
const
|
|
310
|
+
const r = toks[j];
|
|
311
|
+
const word = r.folded;
|
|
316
312
|
if (word.startsWith("-") && word !== "-") {
|
|
317
313
|
for (const payload of attachedOptionPayloads(word))
|
|
318
|
-
reads.push(bare(
|
|
314
|
+
reads.push(bare(r, "unlisted_word", payload));
|
|
319
315
|
if (isPathShapedToken(word))
|
|
320
|
-
reads.push(bare(
|
|
316
|
+
reads.push(bare(r, "unlisted_word"));
|
|
321
317
|
continue;
|
|
322
318
|
}
|
|
323
|
-
if (
|
|
324
|
-
reads.push(
|
|
319
|
+
if (r.expands === "unresolvable") {
|
|
320
|
+
reads.push(bare(r, "unlisted_word"));
|
|
325
321
|
continue;
|
|
326
322
|
}
|
|
327
|
-
if (
|
|
328
|
-
pushAssignment(reads, word,
|
|
323
|
+
if (r.word.assignment !== undefined) {
|
|
324
|
+
pushAssignment(reads, r.word, "env_assignment", envOpens);
|
|
329
325
|
continue;
|
|
330
326
|
}
|
|
331
|
-
reads.push(bare(
|
|
327
|
+
reads.push(bare(r, "unlisted_word"));
|
|
332
328
|
}
|
|
333
329
|
}
|
|
334
330
|
let reentry;
|
|
@@ -349,7 +345,7 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
349
345
|
if (programPositionRunsShell(pos, SHELL_REENTRY_PROGRAM_RE)) {
|
|
350
346
|
reentry = "shell";
|
|
351
347
|
const first = pos.launchers[0]?.index ?? written;
|
|
352
|
-
const text = toks.
|
|
348
|
+
const text = toks.slice(first + 1).map((r) => r.folded).filter((w) => !w.startsWith("-") || w === "-").join(" ");
|
|
353
349
|
if (text.length > 0)
|
|
354
350
|
nested.push(nestedPlan(text));
|
|
355
351
|
return { ...base, empty: false, launcherChain, ...(verb !== undefined ? { verb } : {}), reentry, declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), loopEnd: false };
|
|
@@ -363,27 +359,27 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
363
359
|
unlistedWords(reads, toks, pos.launchers[0].index, launcherIndices, "unlisted_word");
|
|
364
360
|
return { ...base, empty: false, launcherChain, ...(reentry !== undefined ? { reentry } : {}), declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), loopEnd: false };
|
|
365
361
|
}
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
reads.push(bare(toks.raw[program.index], program.name, "program_path"));
|
|
362
|
+
const argReads = toks.slice(program.index + 1);
|
|
363
|
+
const args = argReads.map((r) => r.folded);
|
|
364
|
+
const texts = argReads.map((r) => (r.word.pieces.every((q) => q.literal !== undefined) ? r.word.pieces.map((q) => q.literal).join("") : r.folded));
|
|
365
|
+
const programRead = toks[program.index];
|
|
366
|
+
if (rewritten(programRead) || isPathShapedToken(programRead.folded))
|
|
367
|
+
reads.push(bare(programRead, "program_path"));
|
|
373
368
|
if (SHELL_REENTRY_PROGRAM_RE.test(basename)) {
|
|
374
369
|
reentry = "shell";
|
|
375
|
-
const text = reentryText(basename,
|
|
376
|
-
|
|
377
|
-
|
|
370
|
+
const text = reentryText(basename, texts);
|
|
371
|
+
for (const t of new Set([text, reentryText(basename, args)]))
|
|
372
|
+
if (t !== undefined)
|
|
373
|
+
nested.push(nestedPlan(t));
|
|
378
374
|
if (basename === "source" || basename === ".") {
|
|
379
|
-
const file =
|
|
375
|
+
const file = argReads.find((a) => !a.folded.startsWith("-") || a.folded === "-");
|
|
380
376
|
if (file !== undefined)
|
|
381
|
-
reads.push(bare(
|
|
377
|
+
reads.push(bare(file, "operand"));
|
|
382
378
|
}
|
|
383
379
|
else if (text === undefined) {
|
|
384
|
-
const file =
|
|
385
|
-
if (file !== undefined && file !== "-")
|
|
386
|
-
reads.push(bare(
|
|
380
|
+
const file = argReads.find((a) => !a.folded.startsWith("-") || a.folded === "-");
|
|
381
|
+
if (file !== undefined && file.folded !== "-")
|
|
382
|
+
reads.push(bare(file, "operand"));
|
|
387
383
|
}
|
|
388
384
|
return { ...base, empty: false, launcherChain, verb: verb, reentry, declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), loopEnd: false };
|
|
389
385
|
}
|
|
@@ -393,14 +389,14 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
393
389
|
const moveProvable = pos.controlWords.length === 0 && pos.launchers.length === 0 && pos.assignments.length === 0 && program.name === basename;
|
|
394
390
|
let baseMove;
|
|
395
391
|
if (basename === "cd") {
|
|
396
|
-
baseMove = cdMove(
|
|
392
|
+
baseMove = cdMove(argReads, reads);
|
|
397
393
|
}
|
|
398
394
|
else if (UNMODELLED_BASE_MOVERS.has(basename)) {
|
|
399
395
|
baseMove = { target: "unmodelled" };
|
|
400
396
|
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", program);
|
|
401
397
|
}
|
|
402
398
|
else if (listed) {
|
|
403
|
-
listedVerbCandidates(basename,
|
|
399
|
+
listedVerbCandidates(basename, argReads, reads);
|
|
404
400
|
}
|
|
405
401
|
else {
|
|
406
402
|
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", program);
|
|
@@ -409,15 +405,20 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
409
405
|
if (basename === "sed") {
|
|
410
406
|
const slot = sedScriptSlotFiles(args);
|
|
411
407
|
for (const f of slot.reads)
|
|
412
|
-
reads.push(bare(f,
|
|
408
|
+
reads.push(bare(readOfText(f), "script_slot_file"));
|
|
413
409
|
for (const f of slot.writes)
|
|
414
|
-
reads.push(bare(f,
|
|
410
|
+
reads.push(bare(readOfText(f), "write_redirect_target"));
|
|
415
411
|
for (const c of slot.commands)
|
|
416
412
|
nested.push(nestedPlan(c));
|
|
417
413
|
if (slot.commands.length > 0 || slot.executesPatternSpace)
|
|
418
414
|
reentry = "shell";
|
|
419
415
|
unreadProgramText = slot.unread;
|
|
420
416
|
}
|
|
417
|
+
const bodies = new Set([...codeBodies(basename, texts), ...codeBodies(basename, args)]);
|
|
418
|
+
if (bodies.size > 0)
|
|
419
|
+
reentry = "shell";
|
|
420
|
+
for (const body of bodies)
|
|
421
|
+
nested.push(nestedPlan(body));
|
|
421
422
|
return {
|
|
422
423
|
...base,
|
|
423
424
|
empty: false,
|
|
@@ -477,15 +478,8 @@ function dedupe(reads) {
|
|
|
477
478
|
}
|
|
478
479
|
return out;
|
|
479
480
|
}
|
|
480
|
-
function bare(
|
|
481
|
-
return { spelled
|
|
482
|
-
}
|
|
483
|
-
function expandsOf(raw, folded) {
|
|
484
|
-
if (folded.includes(SUBSTITUTION_PLACEHOLDER) || hasUnquotedExpansionMetachar(raw) || /[`(]/.test(raw) || raw.includes(")"))
|
|
485
|
-
return "unresolvable";
|
|
486
|
-
if (hasUnquotedGlobMetachar(raw))
|
|
487
|
-
return "glob";
|
|
488
|
-
return false;
|
|
481
|
+
function bare(r, provenance, spelled = r.folded) {
|
|
482
|
+
return { spelled, raw: r.raw, provenance, expands: r.expands };
|
|
489
483
|
}
|
|
490
484
|
function relativeSpelling(spelled) {
|
|
491
485
|
return !(isAbsolutePathForm(spelled) || spelled.startsWith("~"));
|
|
@@ -493,54 +487,67 @@ function relativeSpelling(spelled) {
|
|
|
493
487
|
function joinBase(base, target, homeDir) {
|
|
494
488
|
return resolveOperandLexically(base, target, homeDir);
|
|
495
489
|
}
|
|
496
|
-
function redirectFact(r) {
|
|
490
|
+
function redirectFact(r, home) {
|
|
497
491
|
if (r.target === undefined)
|
|
498
492
|
return { op: r.op, direction: "dup" };
|
|
499
493
|
if (r.op === "<")
|
|
500
|
-
return { op: r.op, direction: "in", target: bare(r.target
|
|
494
|
+
return { op: r.op, direction: "in", target: bare(readsOf([r.target], home)[0], "stdin_redirect") };
|
|
501
495
|
if (r.op === "<<<")
|
|
502
496
|
return { op: r.op, direction: "in" };
|
|
503
|
-
return { op: r.op, direction: "out", target: bare(r.target
|
|
497
|
+
return { op: r.op, direction: "out", target: bare(readsOf([r.target], home)[0], "write_redirect_target") };
|
|
504
498
|
}
|
|
505
|
-
function pushAssignment(reads,
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
499
|
+
function pushAssignment(reads, w, provenance, opensValue = true) {
|
|
500
|
+
const a = w.assignment;
|
|
501
|
+
if (a === undefined)
|
|
502
|
+
return;
|
|
503
|
+
const expandsTilde = a.value.expansions.some((p) => p.expansion?.kind === "tilde");
|
|
504
|
+
const value = expandsTilde ? a.value.folded : literalTildeSpelling(a.value.folded);
|
|
505
|
+
const settled = a.op === "=" && !expandsTilde;
|
|
506
|
+
const named = a.value.folded === "" || (a.op === "+=" ? expandsTilde : !settled) ? undefined : value;
|
|
507
|
+
if (a.value.folded === "" && settled)
|
|
509
508
|
return;
|
|
510
|
-
const v = { spelled:
|
|
511
|
-
const unsettled = provenance !== "env_assignment" ? { ...v, expands: "unresolvable" } : v.spelled.startsWith("~") && !v.spelled.includes(":") ?
|
|
512
|
-
if (
|
|
509
|
+
const v = { spelled: a.value.folded, raw: a.bare ? a.value.raw : w.raw, provenance };
|
|
510
|
+
const unsettled = provenance !== "env_assignment" ? { ...v, expands: "unresolvable" } : v.spelled.startsWith("~") && !v.spelled.includes(":") ? { ...v, expands: expandsOf(a.value) } : undefined;
|
|
511
|
+
if (!settled && opensValue && unsettled !== undefined)
|
|
513
512
|
reads.push(unsettled);
|
|
514
|
-
|
|
515
|
-
|
|
513
|
+
const substitutes = a.value.expansions.some((p) => p.expansion?.kind === "command" || p.expansion?.kind === "process" || p.expansion?.kind === "arithmetic");
|
|
514
|
+
if (named !== undefined && !substitutes)
|
|
515
|
+
reads.push({ spelled: named, raw: w.raw, provenance, expands: expandsOf(w) });
|
|
516
|
+
if (a.form === "compound")
|
|
517
|
+
for (const e of compoundArrayElements(a.value))
|
|
518
|
+
reads.push({ spelled: e.folded, raw: e.raw, provenance, expands: e.expands });
|
|
516
519
|
}
|
|
517
520
|
function unlistedWords(reads, toks, from, launcherIndices, provenance, program) {
|
|
518
|
-
const argv = program !== undefined ? { program: program.basename, from: program.index } : argvProgramOf(toks);
|
|
519
|
-
const argvStart = argv?.from ?? toks.
|
|
521
|
+
const argv = program !== undefined ? { program: program.basename, from: program.index } : argvProgramOf(toks.map((r) => r.word));
|
|
522
|
+
const argvStart = argv?.from ?? toks.length;
|
|
520
523
|
const slotVerb = argv?.program;
|
|
521
524
|
const declaredNotPaths = ASSIGNMENT_VALUE_NOT_PATHS.has(slotVerb ?? "");
|
|
522
525
|
const noPathOperands = slotVerb !== undefined && NO_PATH_OPERAND_COMMANDS.has(slotVerb);
|
|
523
526
|
const permutes = slotVerb === undefined || !verbOptionsArePositionIndependent(slotVerb);
|
|
524
527
|
const expanding = new Set();
|
|
525
|
-
for (let j = from; j < toks.
|
|
528
|
+
for (let j = from; j < toks.length; j++) {
|
|
526
529
|
if (launcherIndices.has(j))
|
|
527
530
|
continue;
|
|
528
531
|
if (noPathOperands && j > argvStart)
|
|
529
532
|
break;
|
|
530
|
-
if (
|
|
533
|
+
if (toks[j].expands !== "unresolvable")
|
|
531
534
|
continue;
|
|
532
535
|
expanding.add(j);
|
|
533
|
-
reads.push(
|
|
536
|
+
reads.push(bare(toks[j], j === argvStart ? "program_path" : provenance));
|
|
537
|
+
if (j < argvStart)
|
|
538
|
+
pushAssignment(reads, toks[j].word, "env_assignment", slotVerb !== undefined && !noPathOperands);
|
|
539
|
+
else if (j > argvStart && !declaredNotPaths)
|
|
540
|
+
pushAssignment(reads, toks[j].word, provenance);
|
|
534
541
|
}
|
|
535
542
|
const positional = [];
|
|
536
543
|
let stdinOperand = false;
|
|
537
544
|
let endOfOptions = false;
|
|
538
545
|
let sawArgvOperand = false;
|
|
539
|
-
for (let j = from; j < toks.
|
|
546
|
+
for (let j = from; j < toks.length; j++) {
|
|
540
547
|
if (launcherIndices.has(j) || expanding.has(j))
|
|
541
548
|
continue;
|
|
542
|
-
const
|
|
543
|
-
const
|
|
549
|
+
const r = toks[j];
|
|
550
|
+
const word = r.folded;
|
|
544
551
|
if (j > from && !endOfOptions && word === "--") {
|
|
545
552
|
endOfOptions = true;
|
|
546
553
|
continue;
|
|
@@ -553,43 +560,43 @@ function unlistedWords(reads, toks, from, launcherIndices, provenance, program)
|
|
|
553
560
|
if (optionShaped && j > argvStart) {
|
|
554
561
|
const slot = slotVerb === undefined ? undefined : readVerbOptionSlot(slotVerb, word);
|
|
555
562
|
if (sawArgvOperand && permutes) {
|
|
556
|
-
reads.push(bare(
|
|
563
|
+
reads.push(bare(r, provenance));
|
|
557
564
|
if (slot !== undefined && slot.form === "separated") {
|
|
558
|
-
const ahead = toks
|
|
559
|
-
if (ahead !== undefined &&
|
|
560
|
-
for (const c of slotValueCandidates(ahead, slot.kind))
|
|
561
|
-
reads.push(bare(
|
|
565
|
+
const ahead = toks[j + 1];
|
|
566
|
+
if (ahead !== undefined && ahead.expands !== "unresolvable")
|
|
567
|
+
for (const c of slotValueCandidates(ahead.folded, slot.kind))
|
|
568
|
+
reads.push(bare(ahead, "option_value", c));
|
|
562
569
|
}
|
|
563
570
|
}
|
|
564
571
|
if (slot !== undefined && slot.form !== "unexplained" && !(slot.form === "separated" && sawArgvOperand && permutes)) {
|
|
565
572
|
if (slot.form === "attached") {
|
|
566
573
|
for (const c of slotValueCandidates(literalTildeSpelling(slot.value), slot.kind))
|
|
567
|
-
reads.push(bare(
|
|
574
|
+
reads.push(bare(r, "option_value", c));
|
|
568
575
|
}
|
|
569
576
|
else if (slot.form === "separated") {
|
|
570
577
|
j++;
|
|
571
|
-
const value = toks
|
|
578
|
+
const value = toks[j];
|
|
572
579
|
if (value !== undefined && !expanding.has(j)) {
|
|
573
|
-
const named = slotValueCandidates(value, slot.kind);
|
|
580
|
+
const named = slotValueCandidates(value.folded, slot.kind);
|
|
574
581
|
for (const c of named)
|
|
575
|
-
reads.push(bare(
|
|
582
|
+
reads.push(bare(value, "option_value", c));
|
|
576
583
|
if (named.length > 0)
|
|
577
|
-
positional.push(
|
|
584
|
+
positional.push(value);
|
|
578
585
|
}
|
|
579
586
|
}
|
|
580
587
|
continue;
|
|
581
588
|
}
|
|
582
589
|
for (const payload of attachedOptionPayloads(word))
|
|
583
|
-
reads.push(bare(
|
|
590
|
+
reads.push(bare(r, provenance, payload));
|
|
584
591
|
if (isPathShapedToken(word))
|
|
585
|
-
reads.push(bare(
|
|
592
|
+
reads.push(bare(r, provenance));
|
|
586
593
|
continue;
|
|
587
594
|
}
|
|
588
595
|
if (optionShaped) {
|
|
589
596
|
for (const payload of attachedOptionPayloads(word))
|
|
590
|
-
reads.push(bare(
|
|
597
|
+
reads.push(bare(r, provenance, payload));
|
|
591
598
|
if (isPathShapedToken(word))
|
|
592
|
-
reads.push(bare(
|
|
599
|
+
reads.push(bare(r, provenance));
|
|
593
600
|
continue;
|
|
594
601
|
}
|
|
595
602
|
if (j > argvStart) {
|
|
@@ -599,39 +606,38 @@ function unlistedWords(reads, toks, from, launcherIndices, provenance, program)
|
|
|
599
606
|
if (m === undefined || m.dashIsStdin === true)
|
|
600
607
|
stdinOperand = true;
|
|
601
608
|
else
|
|
602
|
-
positional.push(
|
|
609
|
+
positional.push(r);
|
|
603
610
|
}
|
|
604
611
|
else
|
|
605
|
-
positional.push(
|
|
612
|
+
positional.push(r);
|
|
606
613
|
}
|
|
607
|
-
reads.push(bare(
|
|
614
|
+
reads.push(bare(r, j === argvStart ? "program_path" : provenance));
|
|
608
615
|
if (j < argvStart)
|
|
609
|
-
pushAssignment(reads, word,
|
|
616
|
+
pushAssignment(reads, r.word, "env_assignment", slotVerb !== undefined && !noPathOperands);
|
|
610
617
|
else if (!declaredNotPaths)
|
|
611
|
-
pushAssignment(reads, word,
|
|
618
|
+
pushAssignment(reads, r.word, provenance);
|
|
612
619
|
}
|
|
613
|
-
if (slotVerb !== undefined && argv !== undefined && segmentSelectsRecursiveRead(slotVerb, toks.
|
|
614
|
-
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [
|
|
620
|
+
if (slotVerb !== undefined && argv !== undefined && segmentSelectsRecursiveRead(slotVerb, toks.slice(argvStart + 1).map((x) => x.folded))) {
|
|
621
|
+
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [readOfText(".")];
|
|
615
622
|
for (const root of roots)
|
|
616
|
-
reads.push(
|
|
623
|
+
reads.push(bare(root, "traversal_root"));
|
|
617
624
|
}
|
|
618
|
-
for (let j = from; j < toks.
|
|
625
|
+
for (let j = from; j < toks.length; j++) {
|
|
619
626
|
if (launcherIndices.has(j) || j === argvStart)
|
|
620
627
|
continue;
|
|
621
628
|
if (noPathOperands && j > argvStart)
|
|
622
629
|
break;
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
reads.push(bare(raw, toks.folded[j], provenance));
|
|
630
|
+
if (toks[j].expands === "glob")
|
|
631
|
+
reads.push(bare(toks[j], provenance));
|
|
626
632
|
}
|
|
627
633
|
}
|
|
628
634
|
function commandStringValue(options, toks, option) {
|
|
629
|
-
const at = toks.folded
|
|
635
|
+
const at = toks.findIndex((r) => r.folded === option);
|
|
630
636
|
if (at < 0)
|
|
631
637
|
return undefined;
|
|
632
638
|
for (const spelling of options) {
|
|
633
639
|
if (option === spelling) {
|
|
634
|
-
const value = toks
|
|
640
|
+
const value = toks[at + 1]?.folded;
|
|
635
641
|
return value === undefined ? undefined : { value, next: at + 2 };
|
|
636
642
|
}
|
|
637
643
|
if (spelling.startsWith("--") && option.startsWith(`${spelling}=`))
|
|
@@ -641,68 +647,46 @@ function commandStringValue(options, toks, option) {
|
|
|
641
647
|
}
|
|
642
648
|
return undefined;
|
|
643
649
|
}
|
|
644
|
-
function reentryText(basename, args) {
|
|
645
|
-
if (basename === "eval")
|
|
646
|
-
return args.length === 0 ? undefined : args.join(" ");
|
|
647
|
-
if (basename === "parallel")
|
|
648
|
-
return args.filter((a) => !a.startsWith("-")).join(" ") || undefined;
|
|
649
|
-
if (basename === "source" || basename === ".")
|
|
650
|
-
return undefined;
|
|
651
|
-
for (let k = 0; k < args.length; k++) {
|
|
652
|
-
const a = args[k];
|
|
653
|
-
if (a === "--")
|
|
654
|
-
return undefined;
|
|
655
|
-
if (!a.startsWith("-") || a === "-")
|
|
656
|
-
return undefined;
|
|
657
|
-
const c = a.indexOf("c");
|
|
658
|
-
if (a.startsWith("--"))
|
|
659
|
-
continue;
|
|
660
|
-
if (c > 0)
|
|
661
|
-
return a.length > c + 1 ? a.slice(c + 1) : args[k + 1];
|
|
662
|
-
}
|
|
663
|
-
return undefined;
|
|
664
|
-
}
|
|
665
650
|
function literalBeats(toks) {
|
|
666
|
-
const at = toks.folded
|
|
651
|
+
const at = toks.findIndex((r) => r.folded === "in");
|
|
667
652
|
if (at < 0)
|
|
668
653
|
return undefined;
|
|
669
|
-
const words = toks.
|
|
670
|
-
const raws = toks.raw.slice(at + 1);
|
|
654
|
+
const words = toks.slice(at + 1);
|
|
671
655
|
if (words.length === 0)
|
|
672
656
|
return undefined;
|
|
673
|
-
|
|
674
|
-
|
|
657
|
+
const only = words.length === 1 && words[0].word.pieces.length === 1 ? words[0].word.pieces[0].expansion : undefined;
|
|
658
|
+
if (only !== undefined) {
|
|
659
|
+
const m = only.kind === "command" ? /^\s*seq\s+(\d+)\s+(\d+)\s*$/.exec(only.body ?? "") : null;
|
|
675
660
|
if (m === null)
|
|
676
661
|
return undefined;
|
|
677
662
|
const beats = Number(m[2]) - Number(m[1]) + 1;
|
|
678
663
|
return beats >= 1 && beats <= POLL_LOOP_MAX_BEATS ? beats : undefined;
|
|
679
664
|
}
|
|
680
|
-
for (
|
|
681
|
-
if (
|
|
665
|
+
for (const w of words)
|
|
666
|
+
if (w.expands !== false)
|
|
682
667
|
return undefined;
|
|
683
|
-
}
|
|
684
668
|
return words.length <= POLL_LOOP_MAX_BEATS ? words.length : undefined;
|
|
685
669
|
}
|
|
686
|
-
function cdMove(args,
|
|
687
|
-
const
|
|
688
|
-
if (
|
|
670
|
+
function cdMove(args, reads) {
|
|
671
|
+
const target = args.find((t) => !t.folded.startsWith("-") || t.folded === "-");
|
|
672
|
+
if (target === undefined)
|
|
689
673
|
return { target: "home" };
|
|
690
|
-
|
|
691
|
-
if (target === "-")
|
|
674
|
+
if (target.folded === "-")
|
|
692
675
|
return { target: "previous" };
|
|
693
|
-
const c = bare(
|
|
676
|
+
const c = bare(target, "cd_target");
|
|
694
677
|
reads.push(c);
|
|
695
678
|
return { target: c };
|
|
696
679
|
}
|
|
697
|
-
function listedVerbCandidates(name,
|
|
680
|
+
function listedVerbCandidates(name, argReads, reads) {
|
|
698
681
|
if (NO_PATH_OPERAND_COMMANDS.has(name))
|
|
699
682
|
return;
|
|
683
|
+
const args = argReads.map((r) => r.folded);
|
|
700
684
|
const expanding = new Set();
|
|
701
|
-
|
|
702
|
-
if (!
|
|
685
|
+
argReads.forEach((r, k) => {
|
|
686
|
+
if (!rewritten(r))
|
|
703
687
|
return;
|
|
704
688
|
expanding.add(k);
|
|
705
|
-
reads.push({ spelled:
|
|
689
|
+
reads.push({ spelled: r.folded, raw: r.raw, provenance: "operand", expands: "unresolvable" });
|
|
706
690
|
});
|
|
707
691
|
const eoo = args.indexOf("--");
|
|
708
692
|
const firstOperandSlot = verbFirstOperandSlot(name);
|
|
@@ -713,7 +697,7 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
713
697
|
let endOfOptions = false;
|
|
714
698
|
const permutes = !verbOptionsArePositionIndependent(name);
|
|
715
699
|
const push = (k, text, provenance) => {
|
|
716
|
-
reads.push(bare(
|
|
700
|
+
reads.push(bare(argReads[k], provenance, text));
|
|
717
701
|
};
|
|
718
702
|
for (let k = 0; k < args.length; k++) {
|
|
719
703
|
const t = args[k];
|
|
@@ -747,7 +731,7 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
747
731
|
for (const c of named)
|
|
748
732
|
push(k, c, "option_value");
|
|
749
733
|
if (named.length > 0)
|
|
750
|
-
positional.push(
|
|
734
|
+
positional.push(argReads[k]);
|
|
751
735
|
}
|
|
752
736
|
}
|
|
753
737
|
continue;
|
|
@@ -767,7 +751,7 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
767
751
|
stdinOperand = true;
|
|
768
752
|
continue;
|
|
769
753
|
}
|
|
770
|
-
positional.push(
|
|
754
|
+
positional.push(argReads[k]);
|
|
771
755
|
continue;
|
|
772
756
|
}
|
|
773
757
|
if (inFirstOperandSlot) {
|
|
@@ -775,24 +759,24 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
775
759
|
for (const c of named)
|
|
776
760
|
push(k, c, "operand");
|
|
777
761
|
if (named.length > 0)
|
|
778
|
-
positional.push(
|
|
762
|
+
positional.push(argReads[k]);
|
|
779
763
|
continue;
|
|
780
764
|
}
|
|
781
|
-
positional.push(
|
|
765
|
+
positional.push(argReads[k]);
|
|
782
766
|
push(k, t, "operand");
|
|
783
767
|
if (!ASSIGNMENT_VALUE_NOT_PATHS.has(name)) {
|
|
784
|
-
pushAssignment(reads,
|
|
768
|
+
pushAssignment(reads, argReads[k].word, "operand");
|
|
785
769
|
}
|
|
786
770
|
}
|
|
787
771
|
for (let k = 0; k < args.length; k++) {
|
|
788
772
|
if (expanding.has(k))
|
|
789
773
|
continue;
|
|
790
|
-
if (
|
|
791
|
-
reads.push(bare(
|
|
774
|
+
if (argReads[k].expands === "glob")
|
|
775
|
+
reads.push(bare(argReads[k], "operand"));
|
|
792
776
|
}
|
|
793
777
|
if (segmentSelectsRecursiveRead(name, args)) {
|
|
794
|
-
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [
|
|
778
|
+
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [readOfText(".")];
|
|
795
779
|
for (const root of roots)
|
|
796
|
-
reads.push(
|
|
780
|
+
reads.push(bare(root, "traversal_root"));
|
|
797
781
|
}
|
|
798
782
|
}
|