@sema-agent/core 7.45.0 → 7.47.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.
Files changed (139) hide show
  1. package/CHANGELOG.md +298 -1
  2. package/dist/agents/extra-tool-names.d.ts +65 -0
  3. package/dist/agents/extra-tool-names.js +124 -0
  4. package/dist/agents/subagent.d.ts +17 -5
  5. package/dist/agents/subagent.js +33 -25
  6. package/dist/agents/tool-filter.d.ts +17 -1
  7. package/dist/agents/tool-filter.js +7 -0
  8. package/dist/core/agent-config-dir.d.ts +20 -0
  9. package/dist/core/agent-config-dir.js +49 -0
  10. package/dist/core/allow-entry.d.ts +6 -4
  11. package/dist/core/allow-entry.js +6 -5
  12. package/dist/core/ask-origin.d.ts +35 -12
  13. package/dist/core/ask-origin.js +24 -7
  14. package/dist/core/checkpoint-store.d.ts +39 -2
  15. package/dist/core/effective-path-target.d.ts +136 -4
  16. package/dist/core/effective-path-target.js +110 -2
  17. package/dist/core/engine-notice.d.ts +12 -4
  18. package/dist/core/gate-fold.js +5 -2
  19. package/dist/core/gate-lanes.js +11 -4
  20. package/dist/core/gate-outcome.d.ts +4 -2
  21. package/dist/core/gate-outcome.js +2 -2
  22. package/dist/core/governance-codes.d.ts +3 -1
  23. package/dist/core/governance-codes.js +3 -0
  24. package/dist/core/hooks.d.ts +3 -0
  25. package/dist/core/path-rule-binding.d.ts +65 -0
  26. package/dist/core/path-rule-binding.js +99 -0
  27. package/dist/core/permission-rule-model.d.ts +59 -24
  28. package/dist/core/permission-rule-model.js +48 -44
  29. package/dist/core/permission-rule-provider.d.ts +7 -0
  30. package/dist/core/permission-rule-provider.js +10 -3
  31. package/dist/core/permission-rule-store.d.ts +8 -0
  32. package/dist/core/permission-rule-store.js +6 -2
  33. package/dist/core/permission-rule-sync.js +2 -2
  34. package/dist/core/permission-rules.d.ts +26 -45
  35. package/dist/core/permission-rules.js +77 -57
  36. package/dist/core/runner/child-tree.d.ts +97 -0
  37. package/dist/core/runner/child-tree.js +104 -0
  38. package/dist/core/runner/construction-doors.d.ts +5 -0
  39. package/dist/core/runner/construction-doors.js +6 -0
  40. package/dist/core/runner/contracts.d.ts +46 -0
  41. package/dist/core/runner/gate-exit.d.ts +4 -1
  42. package/dist/core/runner/gate-exit.js +5 -1
  43. package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
  44. package/dist/core/runner/permission-rule-lanes.js +18 -12
  45. package/dist/core/runner/persisted-path-rows.d.ts +31 -7
  46. package/dist/core/runner/persisted-path-rows.js +31 -12
  47. package/dist/core/runner/prepare-ask-lane.d.ts +4 -0
  48. package/dist/core/runner/prepare-ask-lane.js +4 -2
  49. package/dist/core/runner/prepare-execution-env.d.ts +5 -2
  50. package/dist/core/runner/prepare-execution-env.js +10 -3
  51. package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
  52. package/dist/core/runner/prepare-gate-stations.js +2 -1
  53. package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
  54. package/dist/core/runner/prepare-hands-readface.js +11 -11
  55. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
  56. package/dist/core/runner/prepare-inherited-gate.js +8 -2
  57. package/dist/core/runner/prepare-park-ask.d.ts +3 -0
  58. package/dist/core/runner/prepare-park-ask.js +5 -3
  59. package/dist/core/runner/prepare-policy-chain.d.ts +14 -2
  60. package/dist/core/runner/prepare-policy-chain.js +13 -5
  61. package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
  62. package/dist/core/runner/prepare-suspend-saga.js +7 -1
  63. package/dist/core/runner/prepare-task.js +37 -18
  64. package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
  65. package/dist/core/runner/prepare-turn-wiring.js +2 -1
  66. package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
  67. package/dist/core/runner/prepare-workspace-restore.js +1 -0
  68. package/dist/core/runner/resume-apply.js +17 -3
  69. package/dist/core/runner/resume-checkpoint-screen.js +13 -0
  70. package/dist/core/runner/run-leg.js +5 -1
  71. package/dist/core/runner/runtask.js +2 -2
  72. package/dist/core/runner/sub-agent-deny-lists.d.ts +1 -1
  73. package/dist/core/runner/write-protection-station.d.ts +3 -2
  74. package/dist/core/runner/write-protection-station.js +1 -0
  75. package/dist/core/runner-deps.d.ts +14 -0
  76. package/dist/core/sensitive-path-policy.d.ts +8 -0
  77. package/dist/core/sensitive-path-policy.js +18 -2
  78. package/dist/core/shell-wrapper-projection.d.ts +11 -0
  79. package/dist/core/shell-wrapper-projection.js +56 -0
  80. package/dist/core/shell-wrapper-table.d.ts +144 -34
  81. package/dist/core/shell-wrapper-table.js +40 -20
  82. package/dist/core/synthetic-read-verdict.d.ts +3 -0
  83. package/dist/core/synthetic-read-verdict.js +3 -1
  84. package/dist/core/tool-catalog-entries.d.ts +21 -0
  85. package/dist/core/tool-catalog-entries.js +12 -2
  86. package/dist/core/tool-face.d.ts +10 -1
  87. package/dist/core/tool-name-readings.d.ts +8 -0
  88. package/dist/core/tool-name-readings.js +2 -0
  89. package/dist/core/tool-policy.d.ts +40 -17
  90. package/dist/core/tool-policy.js +11 -9
  91. package/dist/core/tool-registry.d.ts +9 -0
  92. package/dist/core/tool-registry.js +10 -0
  93. package/dist/core/tool-spec.d.ts +3 -2
  94. package/dist/core/write-protect.d.ts +14 -3
  95. package/dist/core/write-protect.js +41 -10
  96. package/dist/index.d.ts +6 -4
  97. package/dist/index.js +5 -3
  98. package/dist/orchestration/run-spec.js +8 -7
  99. package/dist/orchestration/workflow.js +1 -1
  100. package/dist/shell/lex.d.ts +22 -0
  101. package/dist/shell/lex.js +75 -13
  102. package/dist/tools/fs/bash-program-position.d.ts +14 -90
  103. package/dist/tools/fs/bash-program-position.js +41 -74
  104. package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
  105. package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
  106. package/dist/tools/fs/index.d.ts +3 -2
  107. package/dist/tools/fs/program-read-model.d.ts +711 -0
  108. package/dist/tools/fs/program-read-model.js +1259 -0
  109. package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
  110. package/dist/tools/fs/program-read-model.rows.js +624 -0
  111. package/dist/tools/fs/read-deny-home.d.ts +19 -1
  112. package/dist/tools/fs/read-deny-home.js +62 -24
  113. package/dist/tools/fs/read-deny.d.ts +54 -14
  114. package/dist/tools/fs/read-deny.js +104 -50
  115. package/dist/tools/fs/removal-targets.d.ts +7 -6
  116. package/dist/tools/fs/removal-targets.js +34 -24
  117. package/dist/tools/fs/safety.d.ts +3 -0
  118. package/dist/tools/fs/safety.js +10 -3
  119. package/dist/tools/fs/shell-read-argv.d.ts +86 -0
  120. package/dist/tools/fs/shell-read-argv.js +388 -0
  121. package/dist/tools/fs/shell-read-bindings.d.ts +300 -0
  122. package/dist/tools/fs/shell-read-bindings.js +755 -0
  123. package/dist/tools/fs/shell-read-check.js +23 -15
  124. package/dist/tools/fs/shell-read-establish.js +82 -8
  125. package/dist/tools/fs/shell-read-judge.d.ts +11 -1
  126. package/dist/tools/fs/shell-read-judge.js +9 -1
  127. package/dist/tools/fs/shell-read-plan.d.ts +33 -8
  128. package/dist/tools/fs/shell-read-plan.js +309 -407
  129. package/dist/tools/fs/shell-read-word.d.ts +60 -26
  130. package/dist/tools/fs/shell-read-word.js +47 -37
  131. package/dist/tools/fs/shell-read-write-targets.d.ts +15 -64
  132. package/dist/tools/fs/shell-read-write-targets.js +85 -137
  133. package/dist/tools/fs/shell-reentry-text.d.ts +136 -6
  134. package/dist/tools/fs/shell-reentry-text.js +203 -53
  135. package/dist/tools/monitor.d.ts +3 -3
  136. package/package.json +1 -1
  137. package/test/export-surface.snapshot.json +25 -5
  138. package/wire-changes/core@7.46.0.json +1522 -0
  139. package/wire-changes/core@7.47.0.json +412 -0
@@ -0,0 +1,1259 @@
1
+ import { literalTildeSpelling } from "../../shell/lex.js";
2
+ import { PROGRAM_ROWS } from "./program-read-model.rows.js";
3
+ export const DATUM_FORMS = Object.freeze(["count", "pattern", "name-pattern", "label", "message", "delimiter"]);
4
+ export const PATH_VALUE_FORMS = Object.freeze(["indirect", "form", "header", "url"]);
5
+ export const OPTION_MODES = Object.freeze(["banner", "interactive", "names-program", "follows", "repeats", "quiet", "forced"]);
6
+ export const ARG_ROLE_KINDS = Object.freeze(["path", "mount-source", "object-path", "program-text", "program-file", "shell-text", "command", "assignment", "binds-name", "entry-probe", "datum"]);
7
+ export const PATH_EFFECTS = Object.freeze(["read", "names", "write", "create", "edit-in-place"]);
8
+ export const WRITING_EFFECTS = new Set(["write", "create", "edit-in-place"]);
9
+ const ROWS_BY_KEY = new Map(PROGRAM_ROWS.map((r) => [r.key, r]));
10
+ export function programRow(name) {
11
+ const exact = ROWS_BY_KEY.get(name);
12
+ if (exact !== undefined)
13
+ return exact;
14
+ const stripped = name.replace(/\d+(?:\.\d+)*$/, "");
15
+ const row = stripped === name ? undefined : ROWS_BY_KEY.get(stripped);
16
+ return row?.versioned === true ? row : undefined;
17
+ }
18
+ export function programRows() {
19
+ return PROGRAM_ROWS;
20
+ }
21
+ export const LAUNCHER_NAMES = new Set(PROGRAM_ROWS.filter((r) => r.launcher !== undefined).map((r) => r.key));
22
+ export const BLOCK_WORD_NAMES = new Set(PROGRAM_ROWS.filter((r) => r.syntax === "block").map((r) => r.key));
23
+ export function runsShellText(name) {
24
+ return programRow(name)?.reentry?.kind === "shell";
25
+ }
26
+ export function feedsArgvFromStdin(name) {
27
+ return programRow(name)?.reentry?.kind === "argv";
28
+ }
29
+ export function streamDefaultProgram(name) {
30
+ const r = programRow(name)?.reentry;
31
+ return r?.kind === "argv" ? r.defaultProgram : undefined;
32
+ }
33
+ export function opensNoOperand(name) {
34
+ const rest = programRow(name)?.operands?.rest;
35
+ return rest?.kind === "datum" || rest?.kind === "entry-probe";
36
+ }
37
+ export function evaluatesOperands(name) {
38
+ return programRow(name)?.operands?.evaluates === true;
39
+ }
40
+ export function assignmentArgumentsAreNotPaths(name) {
41
+ return programRow(name)?.operands?.assignmentArguments === "not-paths";
42
+ }
43
+ export function isDeclarationBuiltin(name) {
44
+ return programRow(name)?.builtin === "declaration";
45
+ }
46
+ export function declaredAttributes(row, args) {
47
+ const out = new Set(row?.assigns !== undefined ? [row.assigns] : []);
48
+ for (const s of selectedOptions(row, args))
49
+ if (s.assigns !== undefined)
50
+ out.add(s.assigns);
51
+ if (row === undefined)
52
+ return out;
53
+ if (readArgRoles(row, args).some((e) => e.kind === "option" && e.reading === "speculative"))
54
+ out.add("unsettled");
55
+ const plus = row.grammars.find((g) => g.plusShort !== undefined)?.plusShort;
56
+ if (plus === undefined)
57
+ return out;
58
+ const end = args.indexOf("--");
59
+ for (const a of end < 0 ? args : args.slice(0, end)) {
60
+ if (/^\+./.test(a) && [...a.slice(1)].some((ch) => plus[ch] === undefined || plus[ch]?.assigns === "unsettled"))
61
+ out.add("unsettled");
62
+ }
63
+ return out;
64
+ }
65
+ export function isInertBuiltin(name) {
66
+ const b = programRow(name)?.builtin;
67
+ return b === "inert" || b === "declaration";
68
+ }
69
+ export function movesBaseUnfollowed(name) {
70
+ return programRow(name)?.movesBase === "unfollowed";
71
+ }
72
+ export function longOptionNameOf(tok) {
73
+ if (!tok.startsWith("--") || tok.length === 2)
74
+ return undefined;
75
+ const body = tok.slice(2);
76
+ const eq = body.indexOf("=");
77
+ const name = eq >= 0 ? body.slice(0, eq) : body;
78
+ return name.length > 0 ? name : undefined;
79
+ }
80
+ export function isLongOptionAbbrevOf(name, full) {
81
+ return full.startsWith(name);
82
+ }
83
+ const MERGED = new WeakMap();
84
+ function mergedTable(row, table) {
85
+ let byTable = MERGED.get(row);
86
+ if (byTable === undefined) {
87
+ byTable = new Map();
88
+ MERGED.set(row, byTable);
89
+ }
90
+ const cached = byTable.get(table);
91
+ if (cached !== undefined)
92
+ return cached;
93
+ const out = new Map();
94
+ const names = new Set(row.grammars.flatMap((g) => Object.keys(g[table] ?? {})));
95
+ for (const name of names) {
96
+ const specs = row.grammars.map((g) => g[table]?.[name]).filter((s) => s !== undefined);
97
+ const arities = new Set(specs.map((s) => s.arity));
98
+ const widest = specs.reduce((a, b) => (roleRank(b.value) > roleRank(a.value) ? b : a));
99
+ out.set(name, { arity: arities.size === 1 ? specs[0].arity : "disputed", spec: widest, takesValueEverywhere: specs.every((s) => s.arity === 1), ownsRestEverywhere: specs.every((s) => s.arity !== 0), takesValueSomewhere: specs.some((s) => s.arity === 1) });
100
+ }
101
+ byTable.set(table, out);
102
+ return out;
103
+ }
104
+ function preciseRole(role) {
105
+ if (role === undefined)
106
+ return false;
107
+ return role.kind === "path" || role.kind === "datum" || role.kind === "mount-source" || role.kind === "object-path" || role.kind === "program-text" || role.kind === "program-file";
108
+ }
109
+ export const READ_LANGUAGES = new Set(["sed"]);
110
+ const PROGRAM_TEXT_OPENS = {
111
+ sed: "parsed",
112
+ arithmetic: "arithmetic",
113
+ jq: ["import", "include"],
114
+ awk: ["getline", "system", "ARGV", "ARGC", "@", "(", "|"],
115
+ bc: "never",
116
+ };
117
+ export function programTextOpensOf(language) {
118
+ return PROGRAM_TEXT_OPENS[language] ?? "any";
119
+ }
120
+ export function programTextMayOpen(language, text) {
121
+ const opens = programTextOpensOf(language);
122
+ if (opens === "any")
123
+ return true;
124
+ if (typeof opens === "string")
125
+ return false;
126
+ return opens.some((t) => (/^\w+$/.test(t) ? new RegExp(`(?<![\\w$])${t}(?!\\w)`).test(text) : text.includes(t)));
127
+ }
128
+ function roleRank(role) {
129
+ if (role?.kind !== "path")
130
+ return 0;
131
+ switch (role.valueForm) {
132
+ case "indirect": return 5;
133
+ case undefined: return 4;
134
+ case "form": return 3;
135
+ case "header": return 2;
136
+ case "url": return 1;
137
+ }
138
+ }
139
+ function viewTable(row, table, view) {
140
+ const out = new Map();
141
+ for (const [name, m] of mergedTable(row, table)) {
142
+ const role = m.spec.value;
143
+ const spec = m.spec;
144
+ if (view === "roles") {
145
+ if (m.arity === 0)
146
+ out.set(name, { arity: 0, spec });
147
+ else if (m.arity === 1)
148
+ out.set(name, { arity: 1, spec, ...(role !== undefined ? { role } : {}) });
149
+ else if (m.arity === "suffix")
150
+ out.set(name, { arity: "suffix", spec, ...(role !== undefined ? { role } : {}) });
151
+ else if (m.arity === "attached" || (m.arity === "disputed" && table === "long"))
152
+ out.set(name, { arity: "attached", spec, ...(role !== undefined ? { role } : {}) });
153
+ continue;
154
+ }
155
+ if (m.arity === 0)
156
+ out.set(name, { arity: 0, spec });
157
+ else if (m.arity === "disputed") {
158
+ if (table === "long" && preciseRole(role))
159
+ out.set(name, { arity: "attached", role: role, spec });
160
+ }
161
+ else if (m.arity === 1 && preciseRole(role))
162
+ out.set(name, { arity: 1, role: role, spec });
163
+ else if (m.arity === "attached" && table === "long" && preciseRole(role))
164
+ out.set(name, { arity: "attached", role: role, spec });
165
+ }
166
+ return out;
167
+ }
168
+ function readOptionIn(row, tok, view, next) {
169
+ if (!tok.startsWith("-") || tok === "-" || tok === "--")
170
+ return { form: "unexplained" };
171
+ if (tok.startsWith("--")) {
172
+ const long = longOptionNameOf(tok);
173
+ if (long === undefined)
174
+ return { form: "unexplained" };
175
+ const longs = viewTable(row, "long", view);
176
+ const eq = tok.indexOf("=");
177
+ const attached = eq >= 0 ? tok.slice(eq + 1) : undefined;
178
+ const withValue = (role, spec) => (attached !== undefined ? { form: "attached", value: attached, role, ...(spec !== undefined ? { spec } : {}) } : { form: "separated", role, ...(spec !== undefined ? { spec } : {}) });
179
+ const exact = longs.get(long);
180
+ if (exact !== undefined) {
181
+ if (exact.arity === 1)
182
+ return withValue(exact.role, exact.spec);
183
+ if (exact.arity === "attached")
184
+ return attached !== undefined ? { form: "attached", value: attached, role: exact.role, spec: exact.spec } : { form: "no-value" };
185
+ return attached === undefined ? { form: "no-value" } : { form: "unexplained" };
186
+ }
187
+ const reach = [...longs.entries()].filter(([full]) => isLongOptionAbbrevOf(long, full));
188
+ const valueNames = reach.filter(([, s]) => s.arity === 1 || (attached !== undefined && s.arity === "attached"));
189
+ const plainNames = reach.filter(([, s]) => s.arity === 0 || (attached === undefined && s.arity === "attached"));
190
+ if (valueNames.length === 0)
191
+ return plainNames.length > 0 && attached === undefined ? { form: "no-value" } : { form: "unexplained" };
192
+ const roles = valueNames.map(([, s]) => s.role);
193
+ const only = valueNames.length === 1 ? valueNames[0][1].spec : undefined;
194
+ if (attached !== undefined)
195
+ return { form: "attached", value: attached, role: roles.reduce((a, b) => (roleRank(b) > roleRank(a) ? b : a)), ...(only !== undefined ? { spec: only } : {}) };
196
+ if (plainNames.length > 0 || new Set(roles.map(roleKey)).size !== 1)
197
+ return { form: "unexplained" };
198
+ return withValue(roles[0], only);
199
+ }
200
+ const shorts = viewTable(row, "short", view);
201
+ const dashWords = viewTable(row, "dashWords", view);
202
+ const word = dashWords.size > 0 ? /^-([A-Za-z_][\w-]+)$/.exec(tok)?.[1] : undefined;
203
+ if (word !== undefined) {
204
+ if (shorts.get(word[0])?.arity === 1)
205
+ return { form: "unexplained" };
206
+ const spec = dashWords.get(word);
207
+ if (spec?.arity === 1)
208
+ return { form: "separated", role: spec.role, spec: spec.spec };
209
+ if (spec?.arity === 0)
210
+ return { form: "no-value" };
211
+ return { form: "unexplained" };
212
+ }
213
+ for (let i = 1; i < tok.length; i++) {
214
+ const spec = shorts.get(tok[i]);
215
+ if (spec?.arity === 1) {
216
+ const rest = tok.slice(i + 1);
217
+ return rest !== "" ? { form: "attached", value: rest, role: spec.role, spec: spec.spec } : { form: "separated", role: spec.role, spec: spec.spec };
218
+ }
219
+ if (spec?.arity === "attached" || spec?.arity === "suffix") {
220
+ const rest = tok.slice(i + 1);
221
+ if (rest !== "")
222
+ return { form: "attached", value: rest, role: spec.role, spec: spec.spec };
223
+ return spec.arity === "suffix" && (view === "roles" || suffixSpelled(next)) ? { form: "separated", role: spec.role, spec: spec.spec } : { form: "no-value" };
224
+ }
225
+ if (spec?.arity !== 0)
226
+ return { form: "unexplained" };
227
+ }
228
+ return { form: "no-value" };
229
+ }
230
+ export function readOptionSlot(row, tok) {
231
+ const r = readOptionIn(row, tok, "candidates");
232
+ if (r.form === "attached" || r.form === "separated")
233
+ return r.role === undefined ? { form: "unexplained" } : { ...r, role: r.role };
234
+ return r;
235
+ }
236
+ export function readOptionRole(row, tok, next) {
237
+ return readOptionIn(row, tok, "roles", next);
238
+ }
239
+ function suffixSpelled(tok) {
240
+ return tok !== undefined && (tok === "" || tok.startsWith("."));
241
+ }
242
+ const roleKey = (r) => (r === undefined ? "?" : r.kind === "path" ? `path:${r.valueForm ?? ""}` : JSON.stringify(r));
243
+ export function firstOperandSlot(row, view = "candidates") {
244
+ const role = row?.operands?.positional?.[0];
245
+ if (row === undefined || role === undefined || (view === "candidates" && !preciseRole(role)))
246
+ return undefined;
247
+ const shorts = [...mergedTable(row, "short")];
248
+ const letters = shorts.filter(([, m]) => m.spec.fillsSlot === true).map(([l]) => l).join("");
249
+ const valueLetters = shorts.filter(([, m]) => m.spec.fillsSlot !== true && m.ownsRestEverywhere).map(([l]) => l).join("");
250
+ const longs = [...mergedTable(row, "long")].filter(([, m]) => m.spec.fillsSlot === true).map(([n]) => n);
251
+ return { role, suppliedByLetters: letters, suppliedByLongNames: longs, valueLetters };
252
+ }
253
+ export function suppliesFirstOperandSlot(slot, tok) {
254
+ if (tok.startsWith("--")) {
255
+ const long = longOptionNameOf(tok);
256
+ return long !== undefined && slot.suppliedByLongNames.some((full) => isLongOptionAbbrevOf(long, full));
257
+ }
258
+ if (!tok.startsWith("-"))
259
+ return false;
260
+ for (let i = 1; i < tok.length; i++) {
261
+ const ch = tok[i];
262
+ if (!/[A-Za-z0-9]/.test(ch))
263
+ return false;
264
+ if (slot.suppliedByLetters.includes(ch))
265
+ return true;
266
+ if (slot.valueLetters.includes(ch))
267
+ return false;
268
+ }
269
+ return false;
270
+ }
271
+ export function optionsStandAnywhere(row) {
272
+ return row !== undefined && row.grammars.length > 0 && row.grammars.every((g) => g.afterFirstOperand === "options");
273
+ }
274
+ function localFileUrlPath(value) {
275
+ const m = /^file:(?:\/\/[^/?#]*)?(\/[^?#]*)/i.exec(value.trim());
276
+ if (m === null)
277
+ return undefined;
278
+ const raw = m[1];
279
+ try {
280
+ return decodeURIComponent(raw);
281
+ }
282
+ catch {
283
+ return raw;
284
+ }
285
+ }
286
+ function formSpecFileNames(value) {
287
+ const out = [];
288
+ const after = (s) => {
289
+ const at = s.search(/[@<]/);
290
+ if (at !== -1 && at < s.length - 1)
291
+ out.push(s.slice(at + 1));
292
+ };
293
+ after(value);
294
+ for (const part of value.split(/[;,]/))
295
+ after(part);
296
+ return [...new Set(out)];
297
+ }
298
+ export const PROGRAM_GLOB_MAX = 256;
299
+ function globRange(text) {
300
+ const close = text.indexOf("]");
301
+ if (close < 0)
302
+ return undefined;
303
+ const body = text.slice(0, close);
304
+ const letters = /^([A-Za-z])-(.)(?::\s*\+?(\d+))?$/.exec(body);
305
+ if (letters !== null) {
306
+ const lo = letters[1].charCodeAt(0), hi = letters[2].charCodeAt(0), step = letters[3] !== undefined ? Number(letters[3]) : 1;
307
+ if (step === 0 || (lo === hi && step !== 1) || (lo !== hi && (lo > hi || step > hi - lo || hi - lo > 25)))
308
+ return undefined;
309
+ const values = [];
310
+ for (let c = lo; c <= hi && values.length <= PROGRAM_GLOB_MAX; c += step)
311
+ values.push(String.fromCharCode(c));
312
+ return { values, length: close + 1 };
313
+ }
314
+ const digits = /^(\d+)-[ \t]*(\d+)(?::\s*\+?(\d+))?$/.exec(body);
315
+ if (digits === null)
316
+ return undefined;
317
+ const pad = digits[1].startsWith("0") ? digits[1].length : 0;
318
+ const lo = Number(digits[1]), hi = Number(digits[2]), step = digits[3] !== undefined ? Number(digits[3]) : 1;
319
+ if (!Number.isSafeInteger(lo) || !Number.isSafeInteger(hi) || step === 0 || (lo === hi && step !== 1) || (lo !== hi && (lo > hi || step > hi - lo)))
320
+ return undefined;
321
+ const values = [];
322
+ for (let n = lo; n <= hi && values.length <= PROGRAM_GLOB_MAX; n += step)
323
+ values.push(String(n).padStart(pad, "0"));
324
+ return { values, length: close + 1 };
325
+ }
326
+ const IPV6_LITERAL = /^\[[0-9A-Fa-f.]*:[0-9A-Fa-f.]*:[0-9A-Fa-f:.]*(?:%[^\]]*)?\]/;
327
+ export function programGlobExpansions(value) {
328
+ let out = [""];
329
+ const append = (alternatives) => {
330
+ out = out.flatMap((head) => alternatives.map((tail) => head + tail));
331
+ return out.length <= PROGRAM_GLOB_MAX;
332
+ };
333
+ let literal = "";
334
+ let i = 0;
335
+ while (i < value.length) {
336
+ const ch = value[i];
337
+ if (ch === "\\" && "{[}]".includes(value[i + 1] ?? "\u0000")) {
338
+ literal += value[i + 1];
339
+ i += 2;
340
+ continue;
341
+ }
342
+ if (ch === "}" || ch === "]")
343
+ return undefined;
344
+ if (ch === "[" && IPV6_LITERAL.test(value.slice(i))) {
345
+ const end = value.indexOf("]", i) + 1;
346
+ literal += value.slice(i, end);
347
+ i = end;
348
+ continue;
349
+ }
350
+ if (ch !== "{" && ch !== "[") {
351
+ literal += ch;
352
+ i++;
353
+ continue;
354
+ }
355
+ if (!append([literal]))
356
+ return undefined;
357
+ literal = "";
358
+ if (ch === "[") {
359
+ const range = globRange(value.slice(i + 1));
360
+ if (range === undefined)
361
+ return undefined;
362
+ if (!append(range.values))
363
+ return undefined;
364
+ i += 1 + range.length;
365
+ continue;
366
+ }
367
+ const set = [];
368
+ let element = "";
369
+ let j = i + 1;
370
+ for (;; j++) {
371
+ const c = value[j];
372
+ if (c === undefined || c === "{" || c === "[" || c === "]")
373
+ return undefined;
374
+ if (c === "}") {
375
+ if (j === i + 1)
376
+ return undefined;
377
+ set.push(element);
378
+ break;
379
+ }
380
+ if (c === ",") {
381
+ set.push(element);
382
+ element = "";
383
+ continue;
384
+ }
385
+ if (c === "\\" && value[j + 1] !== undefined) {
386
+ element += value[++j];
387
+ continue;
388
+ }
389
+ element += c;
390
+ }
391
+ if (!append(set))
392
+ return undefined;
393
+ i = j + 1;
394
+ }
395
+ return append([literal]) ? out : undefined;
396
+ }
397
+ export function slotValueCandidates(value, role, globs = "expanded") {
398
+ if (role.kind === "mount-source")
399
+ return mountSourceOf(value, role.form);
400
+ if (role.kind === "program-file")
401
+ return [value];
402
+ if (role.kind !== "path")
403
+ return [];
404
+ if (role.kind === "path" && role.programGlob === true && globs === "expanded") {
405
+ const values = programGlobExpansions(value);
406
+ if (values === undefined)
407
+ return undefined;
408
+ const out = [];
409
+ for (const v of values)
410
+ for (const c of slotValueCandidates(v, role, "literal") ?? [])
411
+ if (!out.includes(c))
412
+ out.push(c);
413
+ return out;
414
+ }
415
+ const form = role.kind === "path" ? role.valueForm : undefined;
416
+ if (form === "url") {
417
+ const local = localFileUrlPath(value);
418
+ return local !== undefined ? [local] : [];
419
+ }
420
+ if (form === "form")
421
+ return formSpecFileNames(value).map(literalTildeSpelling);
422
+ const named = value.startsWith("@") && value.length > 1 ? literalTildeSpelling(value.slice(1)) : undefined;
423
+ if (form === "header")
424
+ return named !== undefined ? [value, named] : [];
425
+ const out = [value];
426
+ if (form === "indirect" && named !== undefined)
427
+ out.push(named);
428
+ return out;
429
+ }
430
+ function mountSourceOf(value, form) {
431
+ const source = form === "volume" ? value.split(":")[0] : value.split(",").map((kv) => /^(?:source|src)=(.*)$/i.exec(kv)?.[1]).find((v) => v !== undefined) ?? "";
432
+ return source !== "" && (source.includes("/") || source.startsWith(".") || source.startsWith("~")) ? [source] : [];
433
+ }
434
+ export function objectPathsOf(value) {
435
+ if (/^[A-Za-z][\w+.-]*:\/\//.test(value))
436
+ return [];
437
+ const out = [];
438
+ for (let i = value.indexOf(":"); i >= 0; i = value.indexOf(":", i + 1)) {
439
+ const path = value.slice(i + 1);
440
+ if (path !== "" && !out.includes(path))
441
+ out.push(path);
442
+ }
443
+ return out;
444
+ }
445
+ function walkArgs(row, words, readOption, slot, readsRole) {
446
+ const out = [];
447
+ const folded = words.map((w) => w.folded);
448
+ const eoo = folded.indexOf("--");
449
+ const slotSupplied = slot !== undefined && (eoo === -1 ? folded : folded.slice(0, eoo)).some((t) => suppliesFirstOperandSlot(slot, t));
450
+ const permutes = !optionsStandAnywhere(row);
451
+ const dashRead = row?.operands?.dash === "file" ? "file" : "stdin";
452
+ const plus = row?.grammars.some((g) => g.plusOptions === true) === true;
453
+ let sawOperand = false;
454
+ let ordinal = 0;
455
+ let endOfOptions = false;
456
+ for (let k = 0; k < words.length; k++) {
457
+ if (words[k].skip === true)
458
+ continue;
459
+ const t = plus && /^\+[^+]/.test(folded[k]) ? `-${folded[k].slice(1)}` : folded[k];
460
+ if (!endOfOptions && t === "--") {
461
+ endOfOptions = true;
462
+ out.push({ kind: "end-of-options", at: k });
463
+ continue;
464
+ }
465
+ if (!endOfOptions && t.startsWith("-") && t !== "-") {
466
+ const r = row === undefined ? { form: "unexplained" } : readOption(t, folded[k + 1]);
467
+ const both = sawOperand && permutes;
468
+ if (both) {
469
+ out.push({ kind: "dash-word-operand", at: k });
470
+ if (r.form === "separated" && k + 1 < words.length)
471
+ out.push({ kind: "value", at: k + 1, of: k, role: r.role, consumed: false, ...(r.spec !== undefined ? { spec: r.spec } : {}) });
472
+ }
473
+ if (r.form === "no-value") {
474
+ out.push({ kind: "option", at: k, reading: "no-value" });
475
+ continue;
476
+ }
477
+ if (r.form === "attached") {
478
+ out.push({ kind: "option", at: k, reading: { attached: r.value, role: r.role, ...(r.spec !== undefined ? { spec: r.spec } : {}) } });
479
+ continue;
480
+ }
481
+ if (r.form === "separated" && !both) {
482
+ if (k + 1 < words.length)
483
+ out.push({ kind: "value", at: k + 1, of: k, role: r.role, consumed: true, ...(r.spec !== undefined ? { spec: r.spec } : {}) });
484
+ k++;
485
+ continue;
486
+ }
487
+ out.push({ kind: "option", at: k, reading: "speculative" });
488
+ continue;
489
+ }
490
+ const inSlot = slot !== undefined && !slotSupplied && !sawOperand;
491
+ sawOperand = true;
492
+ const declared = inSlot ? undefined : slot !== undefined ? row?.operands?.positional?.[slotSupplied ? ordinal + 1 : ordinal] ?? row?.operands?.rest : row?.operands?.rest;
493
+ const role = declared !== undefined && readsRole(declared) ? declared : undefined;
494
+ out.push({ kind: "operand", at: k, ordinal: ordinal++, ...(inSlot ? { slot: slot.role } : {}), ...(role !== undefined ? { role } : {}), ...(t === "-" ? { dash: dashRead } : {}) });
495
+ }
496
+ return out;
497
+ }
498
+ export function readArgs(row, words, opts) {
499
+ const slot = opts.firstOperandSlot === false ? undefined : firstOperandSlot(row);
500
+ return walkArgs(row, words, (tok) => readOptionSlot(row, tok), opts.firstOperandSlot === "program-text" && slot?.role.kind !== "program-text" ? undefined : slot, preciseRole);
501
+ }
502
+ export function readArgRoles(row, args) {
503
+ return walkArgs(row, args.map((folded) => ({ folded })), (tok, next) => readOptionRole(row, tok, next), firstOperandSlot(row, "roles"), () => true);
504
+ }
505
+ export function selectsContentsTraversal(row, args) {
506
+ const model = row?.traversal;
507
+ if (row === undefined || model === undefined || model.discloses !== "contents")
508
+ return false;
509
+ if (model.always === true)
510
+ return true;
511
+ if (model.keyWordLetters !== undefined) {
512
+ const first = args.find((t) => t.length > 0);
513
+ if (first !== undefined && !first.startsWith("-") && /^[A-Za-z]+$/.test(first) && [...first].some((ch) => model.keyWordLetters.includes(ch)))
514
+ return true;
515
+ }
516
+ const shorts = mergedTable(row, "short");
517
+ const longs = mergedTable(row, "long");
518
+ let endOfOptions = false;
519
+ for (let k = 0; k < args.length; k++) {
520
+ const t = args[k];
521
+ if (endOfOptions)
522
+ continue;
523
+ if (t === "--") {
524
+ const prev = k > 0 ? args[k - 1] : undefined;
525
+ const prevMayOwnValue = prev !== undefined && prev.startsWith("--") && prev.length > 2 && !prev.includes("=");
526
+ if (!prevMayOwnValue)
527
+ endOfOptions = true;
528
+ continue;
529
+ }
530
+ if (t.startsWith("--")) {
531
+ const long = longOptionNameOf(t);
532
+ if (long === undefined)
533
+ continue;
534
+ if ([...longs].some(([full, m]) => m.spec.selects === "traversal" && isLongOptionAbbrevOf(long, full)))
535
+ return true;
536
+ for (const [full, m] of longs) {
537
+ const recursive = m.spec.selectsWhenValue;
538
+ if (recursive === undefined || !isLongOptionAbbrevOf(long, full))
539
+ continue;
540
+ const eq = t.indexOf("=");
541
+ const v = eq >= 0 ? t.slice(eq + 1) : args[k + 1];
542
+ if (v !== undefined && v.length > 0 && recursive.startsWith(v.toLowerCase()))
543
+ return true;
544
+ }
545
+ continue;
546
+ }
547
+ if (!t.startsWith("-") || t === "-")
548
+ continue;
549
+ for (let i = 1; i < t.length; i++) {
550
+ const ch = t[i];
551
+ const m = shorts.get(ch);
552
+ if (m?.spec.selects === "traversal")
553
+ return true;
554
+ if (m?.spec.selectsWhenValue !== undefined) {
555
+ const v = i === t.length - 1 ? args[k + 1] : t.slice(i + 1);
556
+ if (v !== undefined && v.length > 0 && m.spec.selectsWhenValue.startsWith(v.toLowerCase()))
557
+ return true;
558
+ if (i === t.length - 1)
559
+ k++;
560
+ break;
561
+ }
562
+ if (m?.takesValueEverywhere === true) {
563
+ if (i === t.length - 1)
564
+ k++;
565
+ break;
566
+ }
567
+ if (!/[A-Za-z0-9]/.test(ch))
568
+ break;
569
+ }
570
+ }
571
+ return false;
572
+ }
573
+ export function walksCwdWithoutOperand(row) {
574
+ return row !== undefined && row.grammars.some((g) => g.walksCwdWithoutOperand === true);
575
+ }
576
+ export function valuesAreLiteral(row, args) {
577
+ if (row === undefined || !row.grammars.some((g) => [...Object.values(g.short), ...Object.values(g.long)].some((s) => s.literalValues === true)))
578
+ return false;
579
+ const shorts = mergedTable(row, "short");
580
+ const longs = mergedTable(row, "long");
581
+ const negates = (t) => {
582
+ const name = t.startsWith("--no-") ? longOptionNameOf(t)?.slice(3) : undefined;
583
+ return name !== undefined && name.length > 0 && [...longs].some(([full, m]) => m.spec.literalValues === true && isLongOptionAbbrevOf(name, full));
584
+ };
585
+ if (args.some(negates))
586
+ return false;
587
+ let doubt = false;
588
+ for (const e of readArgRoles(row, args)) {
589
+ if (e.kind === "option" && e.reading === "speculative") {
590
+ doubt = true;
591
+ continue;
592
+ }
593
+ const at = e.kind === "option" ? e.at : e.kind === "value" ? e.of : undefined;
594
+ if (at === undefined || doubt)
595
+ continue;
596
+ const t = args[at];
597
+ if (t.startsWith("--")) {
598
+ const long = longOptionNameOf(t);
599
+ if (long === undefined || t.includes("="))
600
+ continue;
601
+ const exact = longs.get(long);
602
+ const hits = exact !== undefined ? [exact] : [...longs].filter(([full]) => isLongOptionAbbrevOf(long, full)).map(([, m]) => m);
603
+ if (hits.length === 1 && hits[0].spec.literalValues === true)
604
+ return true;
605
+ continue;
606
+ }
607
+ for (const ch of t.slice(1)) {
608
+ const m = shorts.get(ch);
609
+ if (m === undefined || m.arity !== 0)
610
+ break;
611
+ if (m.spec.literalValues === true)
612
+ return true;
613
+ }
614
+ }
615
+ return false;
616
+ }
617
+ export function dashOperandIsStdin(row) {
618
+ return row?.operands?.dash !== "file";
619
+ }
620
+ export function declaresOption(row, pred) {
621
+ return row.grammars.some((g) => [...Object.values(g.short), ...Object.values(g.long), ...Object.values(g.dashWords ?? {})].some(pred));
622
+ }
623
+ const isDatumValue = (m) => m.spec.value?.kind === "datum" && m.spec.fillsSlot !== true;
624
+ const isFileValue = (spec) => spec.value === undefined || spec.value.kind === "path" || spec.value.kind === "program-file";
625
+ export function takesSeparatedDatum(row, tok) {
626
+ if (row === undefined)
627
+ return false;
628
+ if (tok.startsWith("--")) {
629
+ if (tok.includes("="))
630
+ return false;
631
+ const name = longOptionNameOf(tok);
632
+ return name !== undefined && [...mergedTable(row, "long")].some(([full, m]) => isLongOptionAbbrevOf(name, full) && m.takesValueSomewhere && isDatumValue(m));
633
+ }
634
+ if (!/^-[A-Za-z0-9]/.test(tok))
635
+ return false;
636
+ const shorts = mergedTable(row, "short");
637
+ for (let i = 1; i < tok.length; i++) {
638
+ const ch = tok[i];
639
+ const m = shorts.get(ch);
640
+ if (m !== undefined && m.arity !== 0)
641
+ return m.takesValueSomewhere && isDatumValue(m) && i === tok.length - 1;
642
+ if (!/[A-Za-z0-9]/.test(ch))
643
+ return false;
644
+ }
645
+ return false;
646
+ }
647
+ export function attachedStdinFile(row, tok) {
648
+ if (row === undefined)
649
+ return false;
650
+ if (tok.startsWith("--")) {
651
+ const eq = tok.indexOf("=");
652
+ const name = longOptionNameOf(tok);
653
+ if (eq < 0 || tok.slice(eq + 1) !== "-" || name === undefined)
654
+ return false;
655
+ const longs = mergedTable(row, "long");
656
+ const exact = longs.get(name);
657
+ const reach = exact !== undefined ? [exact] : [...longs].filter(([full]) => isLongOptionAbbrevOf(name, full)).map(([, m]) => m);
658
+ return reach.length === 0 || reach.some((m) => m.arity !== 0 && isFileValue(m.spec));
659
+ }
660
+ if (!/^-[A-Za-z0-9]/.test(tok))
661
+ return false;
662
+ const shorts = mergedTable(row, "short");
663
+ for (let i = 1; i < tok.length; i++) {
664
+ const ch = tok[i];
665
+ const m = shorts.get(ch);
666
+ if (m !== undefined && m.arity !== 0)
667
+ return tok.slice(i + 1) === "-" && isFileValue(m.spec);
668
+ if (!/[A-Za-z0-9]/.test(ch))
669
+ return false;
670
+ }
671
+ return false;
672
+ }
673
+ const IMPLEMENTATIONS = new WeakMap();
674
+ export function implementationsOf(row) {
675
+ let views = IMPLEMENTATIONS.get(row);
676
+ if (views === undefined) {
677
+ views = row.grammars.length <= 1 ? [row] : row.grammars.map((g) => ({ ...row, grammars: [g] }));
678
+ IMPLEMENTATIONS.set(row, views);
679
+ }
680
+ return views;
681
+ }
682
+ export function selectedOptions(row, args, under) {
683
+ return row === undefined ? [] : [...scanOptions(row, args, under === "one-implementation").specs];
684
+ }
685
+ function scanOptions(row, args, one) {
686
+ const stopsAtOperand = one && row.grammars[0]?.afterFirstOperand === "operands";
687
+ const shorts = mergedTable(row, "short");
688
+ const longs = mergedTable(row, "long");
689
+ const dashWords = mergedTable(row, "dashWords");
690
+ const obsolete = row.grammars.flatMap((g) => (g.obsoleteFirst === undefined ? [] : [g.obsoleteFirst]));
691
+ const specs = [];
692
+ const values = [];
693
+ const operands = [];
694
+ let endOfOptions = false;
695
+ for (let k = 0; k < args.length; k++) {
696
+ const t = args[k];
697
+ if (endOfOptions) {
698
+ operands.push(k);
699
+ continue;
700
+ }
701
+ const traditional = k === 0 || !one ? obsolete.filter((o) => o.signs.includes(t[0] ?? "") && /^.\d+[A-Za-z]*$/.test(t)) : [];
702
+ if (traditional.length > 0) {
703
+ for (const o of traditional)
704
+ for (const ch of t.replace(/^.\d+/, "")) {
705
+ const spec = o.letters[ch];
706
+ if (spec !== undefined)
707
+ specs.push(spec);
708
+ }
709
+ continue;
710
+ }
711
+ if (t === "--") {
712
+ if (one)
713
+ endOfOptions = true;
714
+ continue;
715
+ }
716
+ if (!t.startsWith("-") || t === "-") {
717
+ operands.push(k);
718
+ if (stopsAtOperand)
719
+ endOfOptions = true;
720
+ continue;
721
+ }
722
+ const take = (spec, attached) => {
723
+ if (attached !== undefined) {
724
+ values.push({ at: k, value: attached, spec });
725
+ return;
726
+ }
727
+ if (one && k + 1 < args.length) {
728
+ values.push({ at: k + 1, spec });
729
+ k++;
730
+ }
731
+ };
732
+ if (t.startsWith("--")) {
733
+ const name = longOptionNameOf(t);
734
+ if (name === undefined)
735
+ continue;
736
+ const eq = t.indexOf("=");
737
+ const exact = longs.get(name);
738
+ const hits = exact !== undefined ? [exact] : [...longs].filter(([full]) => isLongOptionAbbrevOf(name, full)).map(([, m]) => m);
739
+ for (const m of hits)
740
+ specs.push(m.spec);
741
+ if (hits.length === 1 && (hits[0].arity === 1 || (eq >= 0 && hits[0].arity === "attached")))
742
+ take(hits[0].spec, eq >= 0 ? t.slice(eq + 1) : undefined);
743
+ else if (one && eq < 0 && hits.length > 1 && hits.every((m) => m.arity === 1))
744
+ k++;
745
+ continue;
746
+ }
747
+ const word = /^-([A-Za-z_][\w-]+)$/.exec(t)?.[1];
748
+ const dash = word === undefined ? undefined : dashWords.get(word);
749
+ if (dash !== undefined) {
750
+ specs.push(dash.spec);
751
+ if (one) {
752
+ if (dash.arity === 1)
753
+ take(dash.spec, undefined);
754
+ continue;
755
+ }
756
+ }
757
+ for (let i = 1; i < t.length; i++) {
758
+ const m = shorts.get(t[i]);
759
+ if (m === undefined) {
760
+ if (/[A-Za-z0-9]/.test(t[i]))
761
+ continue;
762
+ break;
763
+ }
764
+ specs.push(m.spec);
765
+ if (m.arity === 0)
766
+ continue;
767
+ const rest = t.slice(i + 1);
768
+ if (rest !== "")
769
+ values.push({ at: k, value: rest, spec: m.spec });
770
+ else if (m.arity === 1 || m.arity === "suffix")
771
+ take(m.spec, undefined);
772
+ break;
773
+ }
774
+ }
775
+ return { specs, values, operands };
776
+ }
777
+ export function writesPath(role) {
778
+ return role?.kind === "path" && WRITING_EFFECTS.has(role.effect);
779
+ }
780
+ export function writeReadings(row, args) {
781
+ return implementationsOf(row).map((view) => {
782
+ const ops = view.operands;
783
+ const scan = scanOptions(view, args, true);
784
+ const inPlace = scan.specs.some((s) => s.selects === "edit-in-place");
785
+ const unstated = scan.specs.some((s) => s.effect !== "none" && s.selects !== "edit-in-place" && s.writesAt === undefined && s.fillsLast !== true && !writesPath(s.value));
786
+ const ordinary = inPlace && ops?.editedInPlace !== undefined ? ops.editedInPlace : ops?.rest;
787
+ const operandRole = writesPath(ordinary) ? ordinary : writesPath(ops?.last) ? ops.last : undefined;
788
+ const suffixes = scan.values.flatMap((v) => (v.spec.selects === "edit-in-place" ? [v.value ?? args[v.at]] : [])).filter((x) => x !== "");
789
+ const written = [];
790
+ let unexplained = unstated;
791
+ for (const e of readArgRoles(view, args)) {
792
+ if (e.kind === "option") {
793
+ if (e.reading === "speculative")
794
+ unexplained = true;
795
+ else if (e.reading !== "no-value" && writesPath(e.reading.role))
796
+ written.push({ at: e.at, value: e.reading.attached, role: e.reading.role });
797
+ }
798
+ else if (e.kind === "value") {
799
+ if (writesPath(e.role))
800
+ written.push({ at: e.at, role: e.role });
801
+ }
802
+ else if (e.kind === "operand") {
803
+ if (e.dash === "stdin" || e.slot !== undefined)
804
+ continue;
805
+ const role = e.role ?? ordinary;
806
+ if (writesPath(role))
807
+ written.push({ at: e.at, role });
808
+ }
809
+ else if (e.kind === "dash-word-operand") {
810
+ if (writesPath(ordinary))
811
+ written.push({ at: e.at, role: ordinary });
812
+ }
813
+ }
814
+ let copy;
815
+ const last = ops?.last;
816
+ if (writesPath(last)) {
817
+ const filled = scan.values.filter((v) => v.spec.fillsLast === true).at(-1);
818
+ const destination = filled !== undefined ? { at: filled.at, ...(filled.value !== undefined ? { value: filled.value } : {}) } : scan.operands.length > 0 ? { at: scan.operands.at(-1) } : undefined;
819
+ if (destination !== undefined) {
820
+ copy = { destination, sources: scan.operands.filter((at) => at !== destination.at) };
821
+ for (let i = written.length - 1; i >= 0; i--)
822
+ if (written[i].at === destination.at && written[i].value === destination.value)
823
+ written.splice(i, 1);
824
+ written.push({ at: destination.at, ...(destination.value !== undefined ? { value: destination.value } : {}), role: last });
825
+ }
826
+ }
827
+ return { written, ...(operandRole !== undefined ? { operandRole } : {}), unexplained, suffixes, ...(copy !== undefined ? { copy } : {}) };
828
+ });
829
+ }
830
+ export function programDelivery(row, args) {
831
+ const delivery = row?.delivery;
832
+ if (row === undefined || delivery === undefined)
833
+ return undefined;
834
+ const longs = mergedTable(row, "long");
835
+ const dashWords = mergedTable(row, "dashWords");
836
+ const shorts = mergedTable(row, "short");
837
+ const namesByValue = (spec) => (spec.value?.kind === "program-file" && spec.fillsSlot === true) || (spec.mode === "names-program" && spec.arity === 1);
838
+ const positional = row.operands?.positional ?? [];
839
+ const programAt = positional.findIndex((r) => r?.kind === "program-text" || r?.kind === "program-file");
840
+ const programIsText = programAt >= 0 && positional[programAt].kind === "program-text";
841
+ let endOfOptions = false;
842
+ let banner = false;
843
+ let interactive = false;
844
+ let named = false;
845
+ let stdin = false;
846
+ let explained = true;
847
+ let operands = 0;
848
+ scan: for (let i = 0; i < args.length; i++) {
849
+ const arg = args[i];
850
+ if (!endOfOptions && arg === "--") {
851
+ endOfOptions = true;
852
+ continue;
853
+ }
854
+ if (arg === "-") {
855
+ if (!programIsText)
856
+ stdin = true;
857
+ continue;
858
+ }
859
+ if (!endOfOptions && arg.startsWith("-")) {
860
+ const eq = arg.indexOf("=");
861
+ const whole = eq < 0 ? arg : arg.slice(0, eq);
862
+ const valueOf = () => (eq < 0 ? args[++i] : arg.slice(eq + 1));
863
+ const spec = (whole.startsWith("--") ? longs.get(whole.slice(2)) : whole.length > 2 ? dashWords.get(whole.slice(1)) : undefined)?.spec;
864
+ if (spec !== undefined) {
865
+ if (spec.value?.kind === "program-text")
866
+ return "text";
867
+ if (namesByValue(spec)) {
868
+ const value = valueOf();
869
+ if (value === "-") {
870
+ stdin = true;
871
+ continue;
872
+ }
873
+ if (value !== undefined && row.modules?.[value]?.kind === "program-text")
874
+ return "text";
875
+ named = true;
876
+ if (explained && spec.endsOptions === true)
877
+ break scan;
878
+ continue;
879
+ }
880
+ if (spec.mode === "names-program") {
881
+ named = true;
882
+ continue;
883
+ }
884
+ if (spec.mode === "banner") {
885
+ banner = true;
886
+ continue;
887
+ }
888
+ if (spec.arity === 1) {
889
+ valueOf();
890
+ continue;
891
+ }
892
+ continue;
893
+ }
894
+ if (arg.startsWith("--")) {
895
+ if (eq < 0)
896
+ explained = false;
897
+ continue;
898
+ }
899
+ for (let k = 1; k < arg.length; k++) {
900
+ const ch = arg[k];
901
+ if (ch >= "0" && ch <= "9")
902
+ continue;
903
+ const s = shorts.get(ch)?.spec;
904
+ if (s?.value?.kind === "program-text")
905
+ return "text";
906
+ if (s !== undefined && namesByValue(s)) {
907
+ const value = k + 1 < arg.length ? arg.slice(k + 1) : args[++i];
908
+ if (value === "-") {
909
+ stdin = true;
910
+ break;
911
+ }
912
+ if (explained && value !== undefined && row.modules?.[value]?.kind === "program-text")
913
+ return "text";
914
+ if (!explained)
915
+ break;
916
+ named = true;
917
+ if (explained && s.endsOptions === true)
918
+ break scan;
919
+ break;
920
+ }
921
+ if (s?.arity === "attached") {
922
+ if (s.mode === "banner")
923
+ banner = true;
924
+ break;
925
+ }
926
+ if (s?.mode === "banner") {
927
+ banner = true;
928
+ continue;
929
+ }
930
+ if (s?.mode === "interactive") {
931
+ interactive = true;
932
+ continue;
933
+ }
934
+ if (s?.arity === 1) {
935
+ if (k + 1 >= arg.length)
936
+ i++;
937
+ break;
938
+ }
939
+ if (s?.arity !== 0)
940
+ explained = false;
941
+ }
942
+ continue;
943
+ }
944
+ operands++;
945
+ if (!named && explained && programAt >= 0 && operands === programAt + 1) {
946
+ if (programIsText)
947
+ return "text";
948
+ named = true;
949
+ break;
950
+ }
951
+ }
952
+ if (!named && !explained && programIsText && operands > programAt)
953
+ return "text";
954
+ if (stdin || interactive)
955
+ return "stdin";
956
+ if (named || banner)
957
+ return undefined;
958
+ return delivery.stdinWhenUnnamed ? "stdin" : undefined;
959
+ }
960
+ export function programLanguageOf(row) {
961
+ if (row?.delivery === undefined)
962
+ return undefined;
963
+ const roles = [...(row.operands?.positional ?? []), ...row.grammars.flatMap((g) => [...Object.values(g.short), ...Object.values(g.long), ...Object.values(g.dashWords ?? {})].map((s) => s.value))];
964
+ for (const r of roles)
965
+ if (r?.kind === "program-text" || r?.kind === "program-file")
966
+ return r.language;
967
+ return undefined;
968
+ }
969
+ export function printedText(row, args) {
970
+ const words = args.filter((a) => a !== undefined);
971
+ if (row?.prints === undefined || words.length !== args.length)
972
+ return undefined;
973
+ const events = readArgRoles(row, words);
974
+ const from = events.find((e) => e.kind === "operand" || e.kind === "dash-word-operand")?.at ?? words.length;
975
+ if (events.some((e) => e.at < from && e.kind === "option" && e.reading === "speculative"))
976
+ return undefined;
977
+ const printed = words.slice(from);
978
+ if (printed.some((w) => w.includes("\\")))
979
+ return undefined;
980
+ if (row.prints === "words")
981
+ return printed.join(" ");
982
+ return printed.length === 1 && !printed[0].includes("%") ? printed[0] : undefined;
983
+ }
984
+ export function wordsReadBySomeImplementations(row, args) {
985
+ if (row === undefined || row.grammars.length < 2)
986
+ return new Set();
987
+ const opened = (role) => role === undefined || (role.kind === "path" && (role.effect === "read" || role.effect === "edit-in-place")) || role.kind === "program-file";
988
+ const readings = [];
989
+ for (const view of implementationsOf(row)) {
990
+ const reads = new Set();
991
+ for (const e of readArgRoles(view, args)) {
992
+ if (e.kind === "option" && e.reading === "speculative")
993
+ return new Set();
994
+ if (e.kind === "operand") {
995
+ if (e.slot === undefined && e.dash === undefined && opened(e.role))
996
+ reads.add(e.at);
997
+ }
998
+ else if (e.kind === "value") {
999
+ if (e.role !== undefined && opened(e.role) && e.consumed)
1000
+ reads.add(e.at);
1001
+ }
1002
+ }
1003
+ readings.push(reads);
1004
+ }
1005
+ const some = new Set(readings.flatMap((r) => [...r]));
1006
+ return new Set([...some].filter((k) => !readings.every((r) => r.has(k))));
1007
+ }
1008
+ export function moduleTailOf(row, args) {
1009
+ if (row?.modules === undefined)
1010
+ return undefined;
1011
+ for (const e of readArgRoles(row, args)) {
1012
+ const spec = e.kind === "value" ? e.spec : e.kind === "option" && typeof e.reading === "object" ? e.reading.spec : undefined;
1013
+ if (spec?.mode !== "names-program")
1014
+ continue;
1015
+ const name = e.kind === "value" ? args[e.at] : e.kind === "option" && typeof e.reading === "object" ? e.reading.attached : undefined;
1016
+ const role = name === undefined || !Object.hasOwn(row.modules, name) ? undefined : row.modules[name];
1017
+ if (role !== undefined)
1018
+ return { from: e.at + 1, role };
1019
+ }
1020
+ return undefined;
1021
+ }
1022
+ function steppableLauncherOption(row, tok) {
1023
+ const m = tok.startsWith("--") ? (tok.includes("=") ? undefined : mergedTable(row, "long").get(tok.slice(2))) : tok.length === 2 && tok.startsWith("-") ? mergedTable(row, "short").get(tok[1]) : undefined;
1024
+ if (m === undefined || m.spec.value?.kind === "shell-text" || (m.spec.value?.kind === "path" && m.spec.value.base !== undefined))
1025
+ return undefined;
1026
+ return m.arity === "disputed" ? undefined : m;
1027
+ }
1028
+ export function launcherOptionArity(row, tok) {
1029
+ if (row.grammars.length === 0)
1030
+ return undefined;
1031
+ if (tok === "--")
1032
+ return row.grammars.every((g) => g.stepsDashDash === true) ? 0 : undefined;
1033
+ const m = steppableLauncherOption(row, tok);
1034
+ return m === undefined ? undefined : m.arity === 1 ? 1 : 0;
1035
+ }
1036
+ export function launcherOptionPathRole(row, tok) {
1037
+ const role = steppableLauncherOption(row, tok)?.spec.value;
1038
+ return role?.kind === "path" ? role : undefined;
1039
+ }
1040
+ export function launcherOptionStep(row, tok) {
1041
+ if (tok === "-" && row.launcher?.bareDash === true)
1042
+ return 1;
1043
+ const exact = launcherOptionArity(row, tok);
1044
+ if (exact !== undefined)
1045
+ return exact === 1 ? 2 : 1;
1046
+ const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
1047
+ if (eq > 2 && steppableLauncherOption(row, tok.slice(0, eq))?.arity !== undefined && steppableLauncherOption(row, tok.slice(0, eq)).arity !== 0)
1048
+ return 1;
1049
+ if (/^-[A-Za-z]./.test(tok) && !tok.startsWith("--")) {
1050
+ const first = steppableLauncherOption(row, tok.slice(0, 2));
1051
+ if (first !== undefined && first.arity !== 0)
1052
+ return 1;
1053
+ }
1054
+ if (/^-[A-Za-z]+$/.test(tok) && [...tok.slice(1)].every((ch) => launcherOptionArity(row, `-${ch}`) === 0 && steppableLauncherOption(row, `-${ch}`)?.arity === 0))
1055
+ return 1;
1056
+ return undefined;
1057
+ }
1058
+ export function launcherRunsShell(row, args) {
1059
+ const l = row.launcher;
1060
+ if (l?.shellText === undefined)
1061
+ return false;
1062
+ const specs = new Set((l.programWith ?? []).map((s) => (s.startsWith("--") ? mergedTable(row, "long").get(s.slice(2)) : mergedTable(row, "short").get(s.slice(1)))?.spec));
1063
+ return !implementationsOf(row).some((view) => selectedOptions(view, args, "one-implementation").some((o) => specs.has(o)));
1064
+ }
1065
+ export function commandLineOptionSpellings(row) {
1066
+ if (row === undefined)
1067
+ return [];
1068
+ return [
1069
+ ...[...mergedTable(row, "short")].filter(([, m]) => m.spec.value?.kind === "shell-text").map(([l]) => `-${l}`),
1070
+ ...[...mergedTable(row, "long")].filter(([, m]) => m.spec.value?.kind === "shell-text").map(([n]) => `--${n}`),
1071
+ ];
1072
+ }
1073
+ export function readProgramTextLanguage(row) {
1074
+ const first = row?.operands?.positional?.[0];
1075
+ return first?.kind === "program-text" && READ_LANGUAGES.has(first.language) ? first.language : undefined;
1076
+ }
1077
+ export function programTextReadings(row, args) {
1078
+ return row.grammars.map((g) => programTextUnder(g, args));
1079
+ }
1080
+ function programTextUnder(g, args) {
1081
+ const scripts = [];
1082
+ let supplied = false;
1083
+ let endOfOptions = false;
1084
+ let firstOperand;
1085
+ const longs = Object.entries(g.long);
1086
+ const reach = (long, pick) => longs.some(([full, s]) => pick(s) && isLongOptionAbbrevOf(long, full));
1087
+ for (let k = 0; k < args.length; k++) {
1088
+ const tok = args[k];
1089
+ if (!endOfOptions && tok === "--") {
1090
+ endOfOptions = true;
1091
+ continue;
1092
+ }
1093
+ if (endOfOptions || !tok.startsWith("-") || tok === "-") {
1094
+ if (firstOperand === undefined) {
1095
+ firstOperand = tok;
1096
+ if (g.afterFirstOperand === "operands")
1097
+ endOfOptions = true;
1098
+ }
1099
+ continue;
1100
+ }
1101
+ if (tok.startsWith("--")) {
1102
+ const long = longOptionNameOf(tok);
1103
+ if (long === undefined)
1104
+ return "unparsed";
1105
+ const eq = tok.indexOf("=");
1106
+ const attached = eq >= 0 ? tok.slice(eq + 1) : undefined;
1107
+ if (reach(long, (s) => s.fillsSlot === true && s.value?.kind !== "program-text"))
1108
+ return "from-file";
1109
+ if (reach(long, (s) => s.fillsSlot === true && s.value?.kind === "program-text")) {
1110
+ const value = attached ?? args[++k];
1111
+ if (value === undefined)
1112
+ return "unparsed";
1113
+ scripts.push(value);
1114
+ supplied = true;
1115
+ continue;
1116
+ }
1117
+ if (reach(long, (s) => s.arity === 1)) {
1118
+ if (attached === undefined)
1119
+ k++;
1120
+ continue;
1121
+ }
1122
+ if (reach(long, (s) => s.arity === 0 || s.arity === "attached"))
1123
+ continue;
1124
+ return "unparsed";
1125
+ }
1126
+ for (let c = 1; c < tok.length; c++) {
1127
+ const s = g.short[tok[c]];
1128
+ if (s === undefined)
1129
+ return "unparsed";
1130
+ if (s.arity === "suffix") {
1131
+ if (c + 1 === tok.length && suffixSpelled(args[k + 1]))
1132
+ k++;
1133
+ break;
1134
+ }
1135
+ if (s.arity === "attached")
1136
+ break;
1137
+ if (s.arity === 1) {
1138
+ const rest = tok.slice(c + 1);
1139
+ const value = rest !== "" ? rest : args[++k];
1140
+ if (s.fillsSlot === true && s.value?.kind !== "program-text")
1141
+ return "from-file";
1142
+ if (s.fillsSlot === true) {
1143
+ if (value === undefined)
1144
+ return "unparsed";
1145
+ scripts.push(value);
1146
+ supplied = true;
1147
+ }
1148
+ break;
1149
+ }
1150
+ }
1151
+ }
1152
+ const script = supplied ? scripts.join("\n") : firstOperand;
1153
+ return script === undefined ? "none" : { text: script };
1154
+ }
1155
+ function exactSpec(g, tok) {
1156
+ if (tok.startsWith("--"))
1157
+ return tok.includes("=") ? undefined : g.long[tok.slice(2)];
1158
+ return tok.length === 2 && tok.startsWith("-") ? g.short[tok[1]] : undefined;
1159
+ }
1160
+ const isMessage = (s) => s?.value?.kind === "datum" && s.value.form === "message";
1161
+ const SUBCOMMAND_VIEWS = new WeakMap();
1162
+ export function subcommandOf(row, words) {
1163
+ const global = row?.grammars[0];
1164
+ if (row?.subcommands === undefined || global === undefined)
1165
+ return undefined;
1166
+ let relocated = false;
1167
+ let j = 0;
1168
+ for (; j < words.length; j++) {
1169
+ const w = words[j];
1170
+ if (!w.startsWith("-"))
1171
+ break;
1172
+ const spec = exactSpec(global, w);
1173
+ const longWithValue = w.startsWith("--") && w.includes("=") ? global.long[w.slice(2, w.indexOf("="))] : undefined;
1174
+ const taken = spec ?? longWithValue;
1175
+ if (taken?.value?.kind === "path" && taken.value.base !== undefined)
1176
+ relocated = true;
1177
+ if (spec?.arity === 1)
1178
+ j++;
1179
+ else if (spec?.arity !== 0 && longWithValue?.arity !== 1)
1180
+ return undefined;
1181
+ }
1182
+ const name = words[j];
1183
+ const sub = name === undefined || !Object.hasOwn(row.subcommands, name) ? undefined : row.subcommands[name];
1184
+ if (name === undefined || sub === undefined)
1185
+ return undefined;
1186
+ let views = SUBCOMMAND_VIEWS.get(row);
1187
+ if (views === undefined) {
1188
+ views = new Map();
1189
+ SUBCOMMAND_VIEWS.set(row, views);
1190
+ }
1191
+ let view = views.get(name);
1192
+ if (view === undefined) {
1193
+ view = { key: `${row.key} ${name}`, grammars: [sub.grammar], ...(sub.operands !== undefined ? { operands: sub.operands } : {}), ...(sub.traversal !== undefined ? { traversal: sub.traversal } : {}), witness: row.witness };
1194
+ views.set(name, view);
1195
+ }
1196
+ return { name, at: j, row: view, relocated };
1197
+ }
1198
+ export function messageWords(program, words, programIndex) {
1199
+ const out = new Set();
1200
+ const found = subcommandOf(programRow(program), words.slice(programIndex + 1).map((w) => w.folded));
1201
+ if (found === undefined)
1202
+ return out;
1203
+ const j = programIndex + 1 + found.at;
1204
+ const sub = found.row.grammars[0];
1205
+ const settled = (k) => words[k] !== undefined && words[k].expands === false;
1206
+ const longValues = Object.entries(sub.long).filter(([, s]) => s.arity === 1);
1207
+ let pending;
1208
+ for (let k = j + 1; k < words.length; k++) {
1209
+ const w = words[k].folded;
1210
+ if (pending !== undefined) {
1211
+ if (pending === "message" && settled(k))
1212
+ out.add(k);
1213
+ pending = undefined;
1214
+ continue;
1215
+ }
1216
+ if (w === "--")
1217
+ break;
1218
+ if (!settled(k)) {
1219
+ pending = "other";
1220
+ continue;
1221
+ }
1222
+ if (!w.startsWith("-") || w === "-")
1223
+ continue;
1224
+ if (w.startsWith("--")) {
1225
+ const eq = w.indexOf("=");
1226
+ const name = w.slice(2, eq < 0 ? undefined : eq);
1227
+ const takers = longValues.filter(([n]) => n.startsWith(name));
1228
+ const message = (name.length > 0 && takers.length > 0 && takers.every(([, s]) => isMessage(s))) || isMessage(sub.long[name]);
1229
+ if (eq >= 0) {
1230
+ if (message)
1231
+ out.add(k);
1232
+ continue;
1233
+ }
1234
+ if (takers.length > 0)
1235
+ pending = message ? "message" : "other";
1236
+ continue;
1237
+ }
1238
+ const letters = w.slice(1);
1239
+ for (let i = 0; i < letters.length; i++) {
1240
+ const s = sub.short[letters[i]];
1241
+ if (s?.arity === 0)
1242
+ continue;
1243
+ if (s?.arity === "attached")
1244
+ break;
1245
+ if (s?.arity === 1) {
1246
+ if (i < letters.length - 1) {
1247
+ if (isMessage(s))
1248
+ out.add(k);
1249
+ }
1250
+ else
1251
+ pending = isMessage(s) ? "message" : "other";
1252
+ break;
1253
+ }
1254
+ pending = "other";
1255
+ break;
1256
+ }
1257
+ }
1258
+ return out;
1259
+ }