@sema-agent/core 7.29.0 → 7.30.1
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 +393 -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/secret-env.js +2 -1
- 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/lsp/node-lsp-manager.d.ts +3 -0
- package/dist/engine/lsp/node-lsp-manager.js +5 -3
- 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 +38 -54
- package/dist/shell/lex.js +239 -286
- 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 +131 -117
- package/dist/tools/fs/bash-readonly-classifier.js +404 -272
- package/dist/tools/fs/shell-read-check.js +3 -3
- package/dist/tools/fs/shell-read-establish.d.ts +1 -1
- package/dist/tools/fs/shell-read-establish.js +5 -33
- package/dist/tools/fs/shell-read-identity.d.ts +13 -0
- package/dist/tools/fs/shell-read-identity.js +39 -0
- package/dist/tools/fs/shell-read-judge.d.ts +8 -0
- package/dist/tools/fs/shell-read-judge.js +7 -0
- package/dist/tools/fs/shell-read-plan.d.ts +15 -6
- package/dist/tools/fs/shell-read-plan.js +171 -195
- package/dist/tools/fs/shell-read-word.d.ts +64 -0
- package/dist/tools/fs/shell-read-word.js +94 -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
- package/wire-changes/core@7.30.1.json +154 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { lexShell, PARSE_FAILURE_SENTENCE,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { lexShell, PARSE_FAILURE_SENTENCE, substitutionsInHeredocBody, literalTildeSpelling, } from "../../shell/lex.js";
|
|
2
|
+
import { compoundArrayElements, dropDefinitionHeads, expandsOf, readOfText, readsOf, rewritten, spelledWithHome, isArithmeticBody, unreadableSentenceOf } 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,29 @@ export const READ_CANDIDATE_PROVENANCES = [
|
|
|
16
18
|
];
|
|
17
19
|
const NESTING_MAX = 4;
|
|
18
20
|
const BASE_CANDIDATE_MAX = 256;
|
|
19
|
-
function
|
|
20
|
-
for (const segment of lexed.segments) {
|
|
21
|
-
for (const token of segment.tokens) {
|
|
22
|
-
const word = token.kind === "word" ? token : token.kind === "redirect" ? token.target : undefined;
|
|
23
|
-
if (word?.unresolved !== undefined && UNRESOLVED_VIEW[word.unresolved] === "refuse")
|
|
24
|
-
return UNRESOLVED_SENTENCE[word.unresolved];
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
29
|
-
export function planShellReads(command, decl, depth = 0) {
|
|
21
|
+
export function planShellReads(command, decl, depth = 0, homeRebound = false, arithmetic = false) {
|
|
30
22
|
const shape = { grouped: false, backgrounded: false, strayRedirection: false };
|
|
31
23
|
if (depth > NESTING_MAX)
|
|
32
24
|
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" });
|
|
25
|
+
const lexed = lexShell(command);
|
|
35
26
|
if ("parseFailure" in lexed)
|
|
36
27
|
return { segments: [], unreadable: PARSE_FAILURE_SENTENCE[lexed.parseFailure.reason], shape };
|
|
37
|
-
const
|
|
38
|
-
const
|
|
28
|
+
const home = homeRebound || homeMayBeRebound(command) ? undefined : decl.homeDir;
|
|
29
|
+
const unreadable = unreadableSentenceOf(lexed, command, !arithmetic);
|
|
30
|
+
const nestedPlan = (text, arithmetic = false) => planShellReads(text, decl, depth + 1, home === undefined, arithmetic);
|
|
39
31
|
const projected = lexed.segments.map((segment) => projectSegment(segment));
|
|
40
|
-
const facts = projected.map((p, si) => segmentFacts(lexed.segments[si], p, decl, nestedPlan));
|
|
32
|
+
const facts = projected.map((p, si) => segmentFacts(lexed.segments[si], p, decl, home, nestedPlan));
|
|
41
33
|
shape.grouped = projected.some((p) => p.grouped);
|
|
42
34
|
shape.backgrounded = lexed.segments.some((s) => s.connector === "&") || facts.some((f) => f.backgrounds === true);
|
|
43
|
-
shape.strayRedirection = projected.some((p) => p.
|
|
35
|
+
shape.strayRedirection = projected.some((p) => p.argv.length === 0 && p.redirects.length > 0);
|
|
44
36
|
const basesOf = facts.map(() => new Set());
|
|
45
37
|
const unmodelled = facts.map(() => false);
|
|
46
38
|
let candidates = [{ base: decl.cwd, skippedCd: -1 }];
|
|
47
39
|
let baseLost = false;
|
|
48
40
|
let floorBases;
|
|
49
|
-
const loseBase = (reachable) => {
|
|
41
|
+
const loseBase = (reachable, floorTarget) => {
|
|
50
42
|
baseLost = true;
|
|
51
|
-
floorBases ??= [...new Set(reachable.map((c) => c.base))];
|
|
43
|
+
floorBases ??= [...new Set([...reachable.map((c) => c.base), ...(floorTarget !== undefined ? [floorTarget] : [])])];
|
|
52
44
|
};
|
|
53
45
|
let andRunStart = 0;
|
|
54
46
|
let crossedAllAnd = true;
|
|
@@ -84,7 +76,7 @@ export function planShellReads(command, decl, depth = 0) {
|
|
|
84
76
|
if (move === undefined || baseLost)
|
|
85
77
|
return;
|
|
86
78
|
if (typeof move.target === "string" || move.target.expands !== false) {
|
|
87
|
-
loseBase(reachable);
|
|
79
|
+
loseBase(reachable, typeof move.target !== "string" ? move.target.floorSpelled : move.target === "home" ? decl.homeDir : undefined);
|
|
88
80
|
return;
|
|
89
81
|
}
|
|
90
82
|
const target = move.target.spelled;
|
|
@@ -176,11 +168,7 @@ export function planShellReads(command, decl, depth = 0) {
|
|
|
176
168
|
function projectSegment(segment) {
|
|
177
169
|
const tokens = [...segment.tokens];
|
|
178
170
|
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
|
-
}
|
|
171
|
+
dropDefinitionHeads(tokens);
|
|
184
172
|
const words = tokens.filter((t) => {
|
|
185
173
|
if (t.kind !== "word")
|
|
186
174
|
return false;
|
|
@@ -191,23 +179,22 @@ function projectSegment(segment) {
|
|
|
191
179
|
return true;
|
|
192
180
|
});
|
|
193
181
|
return {
|
|
194
|
-
words: wordsOf({ ...segment, tokens: words }),
|
|
195
182
|
argv: words,
|
|
196
183
|
redirects: tokens.filter((t) => t.kind === "redirect"),
|
|
197
184
|
grouped,
|
|
198
185
|
};
|
|
199
186
|
}
|
|
200
|
-
function segmentFacts(segment, p, decl, nestedPlan) {
|
|
201
|
-
const facts = segmentFactsRead(segment, p, decl, nestedPlan);
|
|
187
|
+
function segmentFacts(segment, p, decl, home, nestedPlan) {
|
|
188
|
+
const facts = segmentFactsRead(segment, p, decl, home, nestedPlan);
|
|
202
189
|
const unresolvedRaw = new Set();
|
|
203
190
|
for (const t of segment.tokens) {
|
|
204
191
|
const w = t.kind === "word" ? t : t.kind === "redirect" ? t.target : undefined;
|
|
205
|
-
if (w
|
|
192
|
+
if (w !== undefined && w.pieces.some((p) => p.literal === undefined && p.expansion === undefined))
|
|
206
193
|
unresolvedRaw.add(w.raw);
|
|
207
194
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const unsettle = (c) => (unresolvedRaw.has(c.raw) && c.expands !== "unresolvable" ? { ...c, expands: "unresolvable" } : c);
|
|
195
|
+
const homeWithheld = home === undefined && decl.homeDir !== undefined;
|
|
196
|
+
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 }; };
|
|
197
|
+
const unsettle = (c) => floor((unresolvedRaw.has(c.raw) || (homeWithheld && c.spelled.startsWith("~"))) && c.expands !== "unresolvable" ? { ...c, expands: "unresolvable" } : c);
|
|
211
198
|
const move = facts.baseMove;
|
|
212
199
|
return {
|
|
213
200
|
...facts,
|
|
@@ -215,10 +202,12 @@ function segmentFacts(segment, p, decl, nestedPlan) {
|
|
|
215
202
|
...(move !== undefined && typeof move.target !== "string" ? { baseMove: { target: unsettle(move.target) } } : {}),
|
|
216
203
|
};
|
|
217
204
|
}
|
|
218
|
-
function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
205
|
+
function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
219
206
|
const nested = [];
|
|
207
|
+
const arithmetic = segment.tokens.flatMap((t) => (t.kind === "word" ? t : t.kind === "redirect" ? t.target : undefined)?.pieces ?? []).flatMap((q) => (q.expansion?.kind === "arithmetic" && q.expansion.body !== undefined && isArithmeticBody(q.expansion.body) ? [q.expansion.body] : []));
|
|
208
|
+
const count = (list, body) => list.filter((b) => b === body).length;
|
|
220
209
|
for (const body of segment.substitutions)
|
|
221
|
-
nested.push(nestedPlan(body));
|
|
210
|
+
nested.push(nestedPlan(body, count(arithmetic, body) === count(segment.substitutions, body)));
|
|
222
211
|
let unreadableHeredoc = false;
|
|
223
212
|
for (const t of segment.tokens) {
|
|
224
213
|
if (t.kind !== "heredoc" || t.quoted)
|
|
@@ -228,12 +217,12 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
228
217
|
unreadableHeredoc = true;
|
|
229
218
|
continue;
|
|
230
219
|
}
|
|
231
|
-
for (const
|
|
232
|
-
nested.push(nestedPlan(body));
|
|
220
|
+
for (const s of inner)
|
|
221
|
+
nested.push(nestedPlan(s.body, s.kind === "arithmetic" && isArithmeticBody(s.body)));
|
|
233
222
|
}
|
|
234
223
|
if (unreadableHeredoc)
|
|
235
224
|
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));
|
|
225
|
+
const redirects = p.redirects.map((r) => redirectFact(r, home));
|
|
237
226
|
const reads = [];
|
|
238
227
|
for (const r of redirects)
|
|
239
228
|
if (r.direction === "in" && r.target !== undefined)
|
|
@@ -245,30 +234,30 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
245
234
|
redirects,
|
|
246
235
|
nested,
|
|
247
236
|
};
|
|
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.
|
|
237
|
+
const toks = readsOf(p.argv, home);
|
|
238
|
+
const head = toks[0]?.folded;
|
|
239
|
+
if (head === "coproc" && toks[0].raw === head && toks.length > 1) {
|
|
240
|
+
const tail = (from) => ({ argv: p.argv.slice(from), redirects: p.redirects, grouped: p.grouped });
|
|
241
|
+
const first = segmentFacts(segment, tail(1), decl, home, nestedPlan);
|
|
242
|
+
if (toks.length < 3)
|
|
254
243
|
return { ...first, backgrounds: true };
|
|
255
|
-
const second = segmentFacts(segment, tail(2), decl, nestedPlan);
|
|
244
|
+
const second = segmentFacts(segment, tail(2), decl, home, nestedPlan);
|
|
256
245
|
const seen = new Set(first.nested.map((n) => JSON.stringify(n.segments.map((sg) => sg.text))));
|
|
257
246
|
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 };
|
|
247
|
+
return { ...first, ...(second.reentry === "shell" ? { reentry: second.reentry } : {}), reads: [...first.reads, ...second.reads], nested: [...first.nested, ...extraNested], backgrounds: true };
|
|
259
248
|
}
|
|
260
|
-
if (head !== undefined && toks
|
|
249
|
+
if (head !== undefined && toks[0].raw === head && SHELL_BLOCK_WORDS.has(head)) {
|
|
261
250
|
if (head === "for" || head === "select")
|
|
262
251
|
return { ...base, empty: false, launcherChain: [], declines: [], reads, moveProvable: false, loopHead: { beats: literalBeats(toks) }, loopEnd: false };
|
|
263
252
|
if (head === "done")
|
|
264
253
|
return { ...base, empty: false, launcherChain: [], declines: [], reads, moveProvable: false, loopEnd: true };
|
|
265
254
|
return { ...base, empty: false, launcherChain: [], declines: [], reads, moveProvable: false, loopEnd: false };
|
|
266
255
|
}
|
|
267
|
-
const pos = readProgramPosition(
|
|
256
|
+
const pos = readProgramPosition(p.argv);
|
|
268
257
|
const written = pos.written;
|
|
269
258
|
if (written === undefined)
|
|
270
|
-
return { ...base, empty: toks.
|
|
271
|
-
const loopHead = pos.controlWords.some((i) => toks
|
|
259
|
+
return { ...base, empty: toks.length === 0 && redirects.length === 0 && nested.length === 0, launcherChain: [], declines: [], reads, moveProvable: false, loopEnd: false };
|
|
260
|
+
const loopHead = pos.controlWords.some((i) => toks[i].folded === "while" || toks[i].folded === "until") ? { beats: undefined } : undefined;
|
|
272
261
|
const launcherChain = pos.launchers.map((l) => l.name);
|
|
273
262
|
const launcherIndices = new Set(pos.launchers.map((l) => l.index));
|
|
274
263
|
const declines = [];
|
|
@@ -281,24 +270,23 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
281
270
|
const verb = program === undefined ? undefined : { name: program.name, basename: program.basename, listed };
|
|
282
271
|
const envOpens = basename !== undefined && !NO_PATH_OPERAND_COMMANDS.has(basename);
|
|
283
272
|
for (const k of pos.assignments)
|
|
284
|
-
pushAssignment(reads, toks
|
|
273
|
+
pushAssignment(reads, toks[k].word, "env_assignment", envOpens);
|
|
285
274
|
for (const l of pos.launchers) {
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
reads.push(bare(raw, folded, "program_path"));
|
|
275
|
+
const r = toks[l.index];
|
|
276
|
+
if (isPathShapedToken(r.folded))
|
|
277
|
+
reads.push(bare(r, "program_path"));
|
|
290
278
|
}
|
|
291
279
|
{
|
|
292
280
|
const controlIndices = new Set(pos.controlWords);
|
|
293
281
|
const assignmentIndices = new Set(pos.assignments);
|
|
294
|
-
const chainEnd = pos.program?.index ?? toks.
|
|
282
|
+
const chainEnd = pos.program?.index ?? toks.length;
|
|
295
283
|
const launcherValueIndices = new Set();
|
|
296
284
|
for (const l of pos.launchers) {
|
|
297
285
|
const row = LAUNCHER_TABLE.get(programBasename(l.name));
|
|
298
286
|
if (row === undefined)
|
|
299
287
|
continue;
|
|
300
288
|
for (let j = l.index + 1; j < chainEnd; j++) {
|
|
301
|
-
const w = toks
|
|
289
|
+
const w = toks[j].folded;
|
|
302
290
|
if (!w.startsWith("-") || w === "-")
|
|
303
291
|
break;
|
|
304
292
|
const arity = row.optionArity.get(w);
|
|
@@ -311,24 +299,24 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
311
299
|
for (let j = 0; j < chainEnd; j++) {
|
|
312
300
|
if (launcherIndices.has(j) || controlIndices.has(j) || assignmentIndices.has(j) || launcherValueIndices.has(j) || j === written)
|
|
313
301
|
continue;
|
|
314
|
-
const
|
|
315
|
-
const
|
|
302
|
+
const r = toks[j];
|
|
303
|
+
const word = r.folded;
|
|
316
304
|
if (word.startsWith("-") && word !== "-") {
|
|
317
305
|
for (const payload of attachedOptionPayloads(word))
|
|
318
|
-
reads.push(bare(
|
|
306
|
+
reads.push(bare(r, "unlisted_word", payload));
|
|
319
307
|
if (isPathShapedToken(word))
|
|
320
|
-
reads.push(bare(
|
|
308
|
+
reads.push(bare(r, "unlisted_word"));
|
|
321
309
|
continue;
|
|
322
310
|
}
|
|
323
|
-
if (
|
|
324
|
-
reads.push(
|
|
311
|
+
if (r.expands === "unresolvable") {
|
|
312
|
+
reads.push(bare(r, "unlisted_word"));
|
|
325
313
|
continue;
|
|
326
314
|
}
|
|
327
|
-
if (
|
|
328
|
-
pushAssignment(reads, word,
|
|
315
|
+
if (r.word.assignment !== undefined) {
|
|
316
|
+
pushAssignment(reads, r.word, "env_assignment", envOpens);
|
|
329
317
|
continue;
|
|
330
318
|
}
|
|
331
|
-
reads.push(bare(
|
|
319
|
+
reads.push(bare(r, "unlisted_word"));
|
|
332
320
|
}
|
|
333
321
|
}
|
|
334
322
|
let reentry;
|
|
@@ -349,7 +337,7 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
349
337
|
if (programPositionRunsShell(pos, SHELL_REENTRY_PROGRAM_RE)) {
|
|
350
338
|
reentry = "shell";
|
|
351
339
|
const first = pos.launchers[0]?.index ?? written;
|
|
352
|
-
const text = toks.
|
|
340
|
+
const text = toks.slice(first + 1).map((r) => r.folded).filter((w) => !w.startsWith("-") || w === "-").join(" ");
|
|
353
341
|
if (text.length > 0)
|
|
354
342
|
nested.push(nestedPlan(text));
|
|
355
343
|
return { ...base, empty: false, launcherChain, ...(verb !== undefined ? { verb } : {}), reentry, declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), loopEnd: false };
|
|
@@ -363,27 +351,27 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
363
351
|
unlistedWords(reads, toks, pos.launchers[0].index, launcherIndices, "unlisted_word");
|
|
364
352
|
return { ...base, empty: false, launcherChain, ...(reentry !== undefined ? { reentry } : {}), declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), loopEnd: false };
|
|
365
353
|
}
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
reads.push(bare(toks.raw[program.index], program.name, "program_path"));
|
|
354
|
+
const argReads = toks.slice(program.index + 1);
|
|
355
|
+
const args = argReads.map((r) => r.folded);
|
|
356
|
+
const texts = argReads.map((r) => (r.word.pieces.every((q) => q.literal !== undefined) ? r.word.pieces.map((q) => q.literal).join("") : r.folded));
|
|
357
|
+
const programRead = toks[program.index];
|
|
358
|
+
if (rewritten(programRead) || isPathShapedToken(programRead.folded))
|
|
359
|
+
reads.push(bare(programRead, "program_path"));
|
|
373
360
|
if (SHELL_REENTRY_PROGRAM_RE.test(basename)) {
|
|
374
361
|
reentry = "shell";
|
|
375
|
-
const text = reentryText(basename,
|
|
376
|
-
|
|
377
|
-
|
|
362
|
+
const text = reentryText(basename, texts);
|
|
363
|
+
for (const t of new Set([text, reentryText(basename, args)]))
|
|
364
|
+
if (t !== undefined)
|
|
365
|
+
nested.push(nestedPlan(t));
|
|
378
366
|
if (basename === "source" || basename === ".") {
|
|
379
|
-
const file =
|
|
367
|
+
const file = argReads.find((a) => !a.folded.startsWith("-") || a.folded === "-");
|
|
380
368
|
if (file !== undefined)
|
|
381
|
-
reads.push(bare(
|
|
369
|
+
reads.push(bare(file, "operand"));
|
|
382
370
|
}
|
|
383
371
|
else if (text === undefined) {
|
|
384
|
-
const file =
|
|
385
|
-
if (file !== undefined && file !== "-")
|
|
386
|
-
reads.push(bare(
|
|
372
|
+
const file = argReads.find((a) => !a.folded.startsWith("-") || a.folded === "-");
|
|
373
|
+
if (file !== undefined && file.folded !== "-")
|
|
374
|
+
reads.push(bare(file, "operand"));
|
|
387
375
|
}
|
|
388
376
|
return { ...base, empty: false, launcherChain, verb: verb, reentry, declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), loopEnd: false };
|
|
389
377
|
}
|
|
@@ -393,14 +381,14 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
393
381
|
const moveProvable = pos.controlWords.length === 0 && pos.launchers.length === 0 && pos.assignments.length === 0 && program.name === basename;
|
|
394
382
|
let baseMove;
|
|
395
383
|
if (basename === "cd") {
|
|
396
|
-
baseMove = cdMove(
|
|
384
|
+
baseMove = cdMove(argReads, reads);
|
|
397
385
|
}
|
|
398
386
|
else if (UNMODELLED_BASE_MOVERS.has(basename)) {
|
|
399
387
|
baseMove = { target: "unmodelled" };
|
|
400
388
|
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", program);
|
|
401
389
|
}
|
|
402
390
|
else if (listed) {
|
|
403
|
-
listedVerbCandidates(basename,
|
|
391
|
+
listedVerbCandidates(basename, argReads, reads);
|
|
404
392
|
}
|
|
405
393
|
else {
|
|
406
394
|
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", program);
|
|
@@ -409,15 +397,20 @@ function segmentFactsRead(segment, p, decl, nestedPlan) {
|
|
|
409
397
|
if (basename === "sed") {
|
|
410
398
|
const slot = sedScriptSlotFiles(args);
|
|
411
399
|
for (const f of slot.reads)
|
|
412
|
-
reads.push(bare(f,
|
|
400
|
+
reads.push(bare(readOfText(f), "script_slot_file"));
|
|
413
401
|
for (const f of slot.writes)
|
|
414
|
-
reads.push(bare(f,
|
|
402
|
+
reads.push(bare(readOfText(f), "write_redirect_target"));
|
|
415
403
|
for (const c of slot.commands)
|
|
416
404
|
nested.push(nestedPlan(c));
|
|
417
405
|
if (slot.commands.length > 0 || slot.executesPatternSpace)
|
|
418
406
|
reentry = "shell";
|
|
419
407
|
unreadProgramText = slot.unread;
|
|
420
408
|
}
|
|
409
|
+
const bodies = new Set([...codeBodies(basename, texts), ...codeBodies(basename, args)]);
|
|
410
|
+
if (bodies.size > 0)
|
|
411
|
+
reentry = "shell";
|
|
412
|
+
for (const body of bodies)
|
|
413
|
+
nested.push(nestedPlan(body));
|
|
421
414
|
return {
|
|
422
415
|
...base,
|
|
423
416
|
empty: false,
|
|
@@ -469,7 +462,7 @@ function dedupe(reads) {
|
|
|
469
462
|
const seen = new Set();
|
|
470
463
|
const out = [];
|
|
471
464
|
for (const c of reads) {
|
|
472
|
-
const key = `${c.provenance}\u0000${c.spelled}\u0000${c.expands}`;
|
|
465
|
+
const key = `${c.provenance}\u0000${c.spelled}\u0000${c.expands}\u0000${c.denyOnly === true}`;
|
|
473
466
|
if (seen.has(key))
|
|
474
467
|
continue;
|
|
475
468
|
seen.add(key);
|
|
@@ -477,15 +470,8 @@ function dedupe(reads) {
|
|
|
477
470
|
}
|
|
478
471
|
return out;
|
|
479
472
|
}
|
|
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;
|
|
473
|
+
function bare(r, provenance, spelled = r.folded) {
|
|
474
|
+
return { spelled, raw: r.raw, provenance, expands: r.expands };
|
|
489
475
|
}
|
|
490
476
|
function relativeSpelling(spelled) {
|
|
491
477
|
return !(isAbsolutePathForm(spelled) || spelled.startsWith("~"));
|
|
@@ -493,54 +479,67 @@ function relativeSpelling(spelled) {
|
|
|
493
479
|
function joinBase(base, target, homeDir) {
|
|
494
480
|
return resolveOperandLexically(base, target, homeDir);
|
|
495
481
|
}
|
|
496
|
-
function redirectFact(r) {
|
|
482
|
+
function redirectFact(r, home) {
|
|
497
483
|
if (r.target === undefined)
|
|
498
484
|
return { op: r.op, direction: "dup" };
|
|
499
485
|
if (r.op === "<")
|
|
500
|
-
return { op: r.op, direction: "in", target: bare(r.target
|
|
486
|
+
return { op: r.op, direction: "in", target: bare(readsOf([r.target], home)[0], "stdin_redirect") };
|
|
501
487
|
if (r.op === "<<<")
|
|
502
488
|
return { op: r.op, direction: "in" };
|
|
503
|
-
return { op: r.op, direction: "out", target: bare(r.target
|
|
489
|
+
return { op: r.op, direction: "out", target: bare(readsOf([r.target], home)[0], "write_redirect_target") };
|
|
504
490
|
}
|
|
505
|
-
function pushAssignment(reads,
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
491
|
+
function pushAssignment(reads, w, provenance, opensValue = true) {
|
|
492
|
+
const a = w.assignment;
|
|
493
|
+
if (a === undefined)
|
|
494
|
+
return;
|
|
495
|
+
const expandsTilde = a.value.expansions.some((p) => p.expansion?.kind === "tilde");
|
|
496
|
+
const value = expandsTilde ? a.value.folded : literalTildeSpelling(a.value.folded);
|
|
497
|
+
const settled = a.op === "=" && !expandsTilde;
|
|
498
|
+
const named = a.value.folded === "" || (a.op === "+=" ? expandsTilde : !settled) ? undefined : value;
|
|
499
|
+
if (a.value.folded === "" && settled)
|
|
509
500
|
return;
|
|
510
|
-
const v = { spelled:
|
|
511
|
-
const unsettled = provenance !== "env_assignment" ? { ...v, expands: "unresolvable" } : v.spelled.startsWith("~") && !v.spelled.includes(":") ?
|
|
512
|
-
if (
|
|
501
|
+
const v = { spelled: a.value.folded, raw: a.bare ? a.value.raw : w.raw, provenance };
|
|
502
|
+
const unsettled = provenance !== "env_assignment" ? { ...v, expands: "unresolvable" } : v.spelled.startsWith("~") && !v.spelled.includes(":") ? { ...v, expands: expandsOf(a.value) } : undefined;
|
|
503
|
+
if (!settled && opensValue && unsettled !== undefined)
|
|
513
504
|
reads.push(unsettled);
|
|
514
|
-
|
|
515
|
-
|
|
505
|
+
const substitutes = a.value.expansions.some((p) => p.expansion?.kind === "command" || p.expansion?.kind === "process" || p.expansion?.kind === "arithmetic");
|
|
506
|
+
if (named !== undefined && !substitutes)
|
|
507
|
+
reads.push({ spelled: named, raw: w.raw, provenance, expands: expandsOf(w) });
|
|
508
|
+
if (a.form === "compound")
|
|
509
|
+
for (const e of compoundArrayElements(a.value))
|
|
510
|
+
reads.push({ spelled: e.folded, raw: e.raw, provenance, expands: e.expands, ...(e.denyOnly === true ? { denyOnly: true } : {}) });
|
|
516
511
|
}
|
|
517
512
|
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.
|
|
513
|
+
const argv = program !== undefined ? { program: program.basename, from: program.index } : argvProgramOf(toks.map((r) => r.word));
|
|
514
|
+
const argvStart = argv?.from ?? toks.length;
|
|
520
515
|
const slotVerb = argv?.program;
|
|
521
516
|
const declaredNotPaths = ASSIGNMENT_VALUE_NOT_PATHS.has(slotVerb ?? "");
|
|
522
517
|
const noPathOperands = slotVerb !== undefined && NO_PATH_OPERAND_COMMANDS.has(slotVerb);
|
|
523
518
|
const permutes = slotVerb === undefined || !verbOptionsArePositionIndependent(slotVerb);
|
|
524
519
|
const expanding = new Set();
|
|
525
|
-
for (let j = from; j < toks.
|
|
520
|
+
for (let j = from; j < toks.length; j++) {
|
|
526
521
|
if (launcherIndices.has(j))
|
|
527
522
|
continue;
|
|
528
523
|
if (noPathOperands && j > argvStart)
|
|
529
524
|
break;
|
|
530
|
-
if (
|
|
525
|
+
if (toks[j].expands !== "unresolvable")
|
|
531
526
|
continue;
|
|
532
527
|
expanding.add(j);
|
|
533
|
-
reads.push(
|
|
528
|
+
reads.push(bare(toks[j], j === argvStart ? "program_path" : provenance));
|
|
529
|
+
if (j < argvStart)
|
|
530
|
+
pushAssignment(reads, toks[j].word, "env_assignment", slotVerb !== undefined && !noPathOperands);
|
|
531
|
+
else if (j > argvStart && !declaredNotPaths)
|
|
532
|
+
pushAssignment(reads, toks[j].word, provenance);
|
|
534
533
|
}
|
|
535
534
|
const positional = [];
|
|
536
535
|
let stdinOperand = false;
|
|
537
536
|
let endOfOptions = false;
|
|
538
537
|
let sawArgvOperand = false;
|
|
539
|
-
for (let j = from; j < toks.
|
|
538
|
+
for (let j = from; j < toks.length; j++) {
|
|
540
539
|
if (launcherIndices.has(j) || expanding.has(j))
|
|
541
540
|
continue;
|
|
542
|
-
const
|
|
543
|
-
const
|
|
541
|
+
const r = toks[j];
|
|
542
|
+
const word = r.folded;
|
|
544
543
|
if (j > from && !endOfOptions && word === "--") {
|
|
545
544
|
endOfOptions = true;
|
|
546
545
|
continue;
|
|
@@ -553,43 +552,43 @@ function unlistedWords(reads, toks, from, launcherIndices, provenance, program)
|
|
|
553
552
|
if (optionShaped && j > argvStart) {
|
|
554
553
|
const slot = slotVerb === undefined ? undefined : readVerbOptionSlot(slotVerb, word);
|
|
555
554
|
if (sawArgvOperand && permutes) {
|
|
556
|
-
reads.push(bare(
|
|
555
|
+
reads.push(bare(r, provenance));
|
|
557
556
|
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(
|
|
557
|
+
const ahead = toks[j + 1];
|
|
558
|
+
if (ahead !== undefined && ahead.expands !== "unresolvable")
|
|
559
|
+
for (const c of slotValueCandidates(ahead.folded, slot.kind))
|
|
560
|
+
reads.push(bare(ahead, "option_value", c));
|
|
562
561
|
}
|
|
563
562
|
}
|
|
564
563
|
if (slot !== undefined && slot.form !== "unexplained" && !(slot.form === "separated" && sawArgvOperand && permutes)) {
|
|
565
564
|
if (slot.form === "attached") {
|
|
566
565
|
for (const c of slotValueCandidates(literalTildeSpelling(slot.value), slot.kind))
|
|
567
|
-
reads.push(bare(
|
|
566
|
+
reads.push(bare(r, "option_value", c));
|
|
568
567
|
}
|
|
569
568
|
else if (slot.form === "separated") {
|
|
570
569
|
j++;
|
|
571
|
-
const value = toks
|
|
570
|
+
const value = toks[j];
|
|
572
571
|
if (value !== undefined && !expanding.has(j)) {
|
|
573
|
-
const named = slotValueCandidates(value, slot.kind);
|
|
572
|
+
const named = slotValueCandidates(value.folded, slot.kind);
|
|
574
573
|
for (const c of named)
|
|
575
|
-
reads.push(bare(
|
|
574
|
+
reads.push(bare(value, "option_value", c));
|
|
576
575
|
if (named.length > 0)
|
|
577
|
-
positional.push(
|
|
576
|
+
positional.push(value);
|
|
578
577
|
}
|
|
579
578
|
}
|
|
580
579
|
continue;
|
|
581
580
|
}
|
|
582
581
|
for (const payload of attachedOptionPayloads(word))
|
|
583
|
-
reads.push(bare(
|
|
582
|
+
reads.push(bare(r, provenance, payload));
|
|
584
583
|
if (isPathShapedToken(word))
|
|
585
|
-
reads.push(bare(
|
|
584
|
+
reads.push(bare(r, provenance));
|
|
586
585
|
continue;
|
|
587
586
|
}
|
|
588
587
|
if (optionShaped) {
|
|
589
588
|
for (const payload of attachedOptionPayloads(word))
|
|
590
|
-
reads.push(bare(
|
|
589
|
+
reads.push(bare(r, provenance, payload));
|
|
591
590
|
if (isPathShapedToken(word))
|
|
592
|
-
reads.push(bare(
|
|
591
|
+
reads.push(bare(r, provenance));
|
|
593
592
|
continue;
|
|
594
593
|
}
|
|
595
594
|
if (j > argvStart) {
|
|
@@ -599,39 +598,38 @@ function unlistedWords(reads, toks, from, launcherIndices, provenance, program)
|
|
|
599
598
|
if (m === undefined || m.dashIsStdin === true)
|
|
600
599
|
stdinOperand = true;
|
|
601
600
|
else
|
|
602
|
-
positional.push(
|
|
601
|
+
positional.push(r);
|
|
603
602
|
}
|
|
604
603
|
else
|
|
605
|
-
positional.push(
|
|
604
|
+
positional.push(r);
|
|
606
605
|
}
|
|
607
|
-
reads.push(bare(
|
|
606
|
+
reads.push(bare(r, j === argvStart ? "program_path" : provenance));
|
|
608
607
|
if (j < argvStart)
|
|
609
|
-
pushAssignment(reads, word,
|
|
608
|
+
pushAssignment(reads, r.word, "env_assignment", slotVerb !== undefined && !noPathOperands);
|
|
610
609
|
else if (!declaredNotPaths)
|
|
611
|
-
pushAssignment(reads, word,
|
|
610
|
+
pushAssignment(reads, r.word, provenance);
|
|
612
611
|
}
|
|
613
|
-
if (slotVerb !== undefined && argv !== undefined && segmentSelectsRecursiveRead(slotVerb, toks.
|
|
614
|
-
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [
|
|
612
|
+
if (slotVerb !== undefined && argv !== undefined && segmentSelectsRecursiveRead(slotVerb, toks.slice(argvStart + 1).map((x) => x.folded))) {
|
|
613
|
+
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [readOfText(".")];
|
|
615
614
|
for (const root of roots)
|
|
616
|
-
reads.push(
|
|
615
|
+
reads.push(bare(root, "traversal_root"));
|
|
617
616
|
}
|
|
618
|
-
for (let j = from; j < toks.
|
|
617
|
+
for (let j = from; j < toks.length; j++) {
|
|
619
618
|
if (launcherIndices.has(j) || j === argvStart)
|
|
620
619
|
continue;
|
|
621
620
|
if (noPathOperands && j > argvStart)
|
|
622
621
|
break;
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
reads.push(bare(raw, toks.folded[j], provenance));
|
|
622
|
+
if (toks[j].expands === "glob")
|
|
623
|
+
reads.push(bare(toks[j], provenance));
|
|
626
624
|
}
|
|
627
625
|
}
|
|
628
626
|
function commandStringValue(options, toks, option) {
|
|
629
|
-
const at = toks.folded
|
|
627
|
+
const at = toks.findIndex((r) => r.folded === option);
|
|
630
628
|
if (at < 0)
|
|
631
629
|
return undefined;
|
|
632
630
|
for (const spelling of options) {
|
|
633
631
|
if (option === spelling) {
|
|
634
|
-
const value = toks
|
|
632
|
+
const value = toks[at + 1]?.folded;
|
|
635
633
|
return value === undefined ? undefined : { value, next: at + 2 };
|
|
636
634
|
}
|
|
637
635
|
if (spelling.startsWith("--") && option.startsWith(`${spelling}=`))
|
|
@@ -641,68 +639,46 @@ function commandStringValue(options, toks, option) {
|
|
|
641
639
|
}
|
|
642
640
|
return undefined;
|
|
643
641
|
}
|
|
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
642
|
function literalBeats(toks) {
|
|
666
|
-
const at = toks.folded
|
|
643
|
+
const at = toks.findIndex((r) => r.folded === "in");
|
|
667
644
|
if (at < 0)
|
|
668
645
|
return undefined;
|
|
669
|
-
const words = toks.
|
|
670
|
-
const raws = toks.raw.slice(at + 1);
|
|
646
|
+
const words = toks.slice(at + 1);
|
|
671
647
|
if (words.length === 0)
|
|
672
648
|
return undefined;
|
|
673
|
-
|
|
674
|
-
|
|
649
|
+
const only = words.length === 1 && words[0].word.pieces.length === 1 ? words[0].word.pieces[0].expansion : undefined;
|
|
650
|
+
if (only !== undefined) {
|
|
651
|
+
const m = only.kind === "command" ? /^\s*seq\s+(\d+)\s+(\d+)\s*$/.exec(only.body ?? "") : null;
|
|
675
652
|
if (m === null)
|
|
676
653
|
return undefined;
|
|
677
654
|
const beats = Number(m[2]) - Number(m[1]) + 1;
|
|
678
655
|
return beats >= 1 && beats <= POLL_LOOP_MAX_BEATS ? beats : undefined;
|
|
679
656
|
}
|
|
680
|
-
for (
|
|
681
|
-
if (
|
|
657
|
+
for (const w of words)
|
|
658
|
+
if (w.expands !== false)
|
|
682
659
|
return undefined;
|
|
683
|
-
}
|
|
684
660
|
return words.length <= POLL_LOOP_MAX_BEATS ? words.length : undefined;
|
|
685
661
|
}
|
|
686
|
-
function cdMove(args,
|
|
687
|
-
const
|
|
688
|
-
if (
|
|
662
|
+
function cdMove(args, reads) {
|
|
663
|
+
const target = args.find((t) => !t.folded.startsWith("-") || t.folded === "-");
|
|
664
|
+
if (target === undefined)
|
|
689
665
|
return { target: "home" };
|
|
690
|
-
|
|
691
|
-
if (target === "-")
|
|
666
|
+
if (target.folded === "-")
|
|
692
667
|
return { target: "previous" };
|
|
693
|
-
const c = bare(
|
|
668
|
+
const c = bare(target, "cd_target");
|
|
694
669
|
reads.push(c);
|
|
695
670
|
return { target: c };
|
|
696
671
|
}
|
|
697
|
-
function listedVerbCandidates(name,
|
|
672
|
+
function listedVerbCandidates(name, argReads, reads) {
|
|
698
673
|
if (NO_PATH_OPERAND_COMMANDS.has(name))
|
|
699
674
|
return;
|
|
675
|
+
const args = argReads.map((r) => r.folded);
|
|
700
676
|
const expanding = new Set();
|
|
701
|
-
|
|
702
|
-
if (!
|
|
677
|
+
argReads.forEach((r, k) => {
|
|
678
|
+
if (!rewritten(r))
|
|
703
679
|
return;
|
|
704
680
|
expanding.add(k);
|
|
705
|
-
reads.push({ spelled:
|
|
681
|
+
reads.push({ spelled: r.folded, raw: r.raw, provenance: "operand", expands: "unresolvable" });
|
|
706
682
|
});
|
|
707
683
|
const eoo = args.indexOf("--");
|
|
708
684
|
const firstOperandSlot = verbFirstOperandSlot(name);
|
|
@@ -713,7 +689,7 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
713
689
|
let endOfOptions = false;
|
|
714
690
|
const permutes = !verbOptionsArePositionIndependent(name);
|
|
715
691
|
const push = (k, text, provenance) => {
|
|
716
|
-
reads.push(bare(
|
|
692
|
+
reads.push(bare(argReads[k], provenance, text));
|
|
717
693
|
};
|
|
718
694
|
for (let k = 0; k < args.length; k++) {
|
|
719
695
|
const t = args[k];
|
|
@@ -747,7 +723,7 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
747
723
|
for (const c of named)
|
|
748
724
|
push(k, c, "option_value");
|
|
749
725
|
if (named.length > 0)
|
|
750
|
-
positional.push(
|
|
726
|
+
positional.push(argReads[k]);
|
|
751
727
|
}
|
|
752
728
|
}
|
|
753
729
|
continue;
|
|
@@ -767,7 +743,7 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
767
743
|
stdinOperand = true;
|
|
768
744
|
continue;
|
|
769
745
|
}
|
|
770
|
-
positional.push(
|
|
746
|
+
positional.push(argReads[k]);
|
|
771
747
|
continue;
|
|
772
748
|
}
|
|
773
749
|
if (inFirstOperandSlot) {
|
|
@@ -775,24 +751,24 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
|
|
|
775
751
|
for (const c of named)
|
|
776
752
|
push(k, c, "operand");
|
|
777
753
|
if (named.length > 0)
|
|
778
|
-
positional.push(
|
|
754
|
+
positional.push(argReads[k]);
|
|
779
755
|
continue;
|
|
780
756
|
}
|
|
781
|
-
positional.push(
|
|
757
|
+
positional.push(argReads[k]);
|
|
782
758
|
push(k, t, "operand");
|
|
783
759
|
if (!ASSIGNMENT_VALUE_NOT_PATHS.has(name)) {
|
|
784
|
-
pushAssignment(reads,
|
|
760
|
+
pushAssignment(reads, argReads[k].word, "operand");
|
|
785
761
|
}
|
|
786
762
|
}
|
|
787
763
|
for (let k = 0; k < args.length; k++) {
|
|
788
764
|
if (expanding.has(k))
|
|
789
765
|
continue;
|
|
790
|
-
if (
|
|
791
|
-
reads.push(bare(
|
|
766
|
+
if (argReads[k].expands === "glob")
|
|
767
|
+
reads.push(bare(argReads[k], "operand"));
|
|
792
768
|
}
|
|
793
769
|
if (segmentSelectsRecursiveRead(name, args)) {
|
|
794
|
-
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [
|
|
770
|
+
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [readOfText(".")];
|
|
795
771
|
for (const root of roots)
|
|
796
|
-
reads.push(
|
|
772
|
+
reads.push(bare(root, "traversal_root"));
|
|
797
773
|
}
|
|
798
774
|
}
|