@smthrs/std 1.0.0-rc.7 → 1.0.0-rc.8

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 (36) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +38 -36
  3. package/dist/cjs/Checkpoints.d.ts +37 -0
  4. package/dist/cjs/Checkpoints.d.ts.map +1 -1
  5. package/dist/cjs/Checkpoints.js +75 -0
  6. package/dist/cjs/Checkpoints.js.map +2 -2
  7. package/dist/cjs/internal/EnvelopePrecheck.d.ts +2 -0
  8. package/dist/cjs/internal/EnvelopePrecheck.d.ts.map +1 -1
  9. package/dist/cjs/internal/EnvelopePrecheck.js +217 -34
  10. package/dist/cjs/internal/EnvelopePrecheck.js.map +3 -3
  11. package/dist/cjs/internal/Exec.d.ts +12 -7
  12. package/dist/cjs/internal/Exec.d.ts.map +1 -1
  13. package/dist/cjs/internal/Exec.js +8 -4
  14. package/dist/cjs/internal/Exec.js.map +2 -2
  15. package/dist/esm/Checkpoints.d.ts +37 -0
  16. package/dist/esm/Checkpoints.d.ts.map +1 -1
  17. package/dist/esm/Checkpoints.js +85 -0
  18. package/dist/esm/Checkpoints.js.map +1 -1
  19. package/dist/esm/internal/EnvelopePrecheck.d.ts +2 -0
  20. package/dist/esm/internal/EnvelopePrecheck.d.ts.map +1 -1
  21. package/dist/esm/internal/EnvelopePrecheck.js +295 -60
  22. package/dist/esm/internal/EnvelopePrecheck.js.map +1 -1
  23. package/dist/esm/internal/Exec.d.ts +12 -7
  24. package/dist/esm/internal/Exec.d.ts.map +1 -1
  25. package/dist/esm/internal/Exec.js +30 -9
  26. package/dist/esm/internal/Exec.js.map +1 -1
  27. package/docs/README.md +3 -1
  28. package/docs/api.md +20 -17
  29. package/docs/guides/pin-a-checkpoint.md +20 -0
  30. package/docs/installation.md +13 -9
  31. package/docs/quickstart.md +1 -1
  32. package/docs/troubleshooting.md +12 -0
  33. package/package.json +6 -6
  34. package/src/Checkpoints.ts +137 -0
  35. package/src/internal/EnvelopePrecheck.ts +295 -63
  36. package/src/internal/Exec.ts +32 -8
@@ -17,32 +17,251 @@
17
17
  */
18
18
  import * as StdError from "../StdError.js";
19
19
  import { withinEnvelope } from "./Paths.js";
20
- const commandSeparators = new Set(["&&", "||", ";", "|", "&", "\n"]);
21
- const redirections = new Set([">", ">>", "<", "<<"]);
20
+ const commandSeparators = new Set(["&&", "||", ";", ";;", ";&", ";;&", "|", "|&", "&", "\n", "(", ")"]);
21
+ const writeRedirections = new Set([">", ">>", ">|", "&>", "&>>", ">&", "<>"]);
22
+ const readRedirections = new Set(["<", "<&"]);
23
+ // A here-document delimiter and a here-string are text, not file names.
24
+ const textRedirections = new Set(["<<", "<<-", "<<<"]);
25
+ const isRedirection = (token) => token.operator &&
26
+ (writeRedirections.has(token.text) || readRedirections.has(token.text) || textRedirections.has(token.text));
27
+ // Longest first, so `&>>` is not read as `&` then `>>`.
28
+ const operators = [
29
+ ";;&",
30
+ "&>>",
31
+ "<<<",
32
+ "<<-",
33
+ ";;",
34
+ ";&",
35
+ "&&",
36
+ "||",
37
+ "|&",
38
+ "&>",
39
+ ">>",
40
+ ">|",
41
+ ">&",
42
+ "<>",
43
+ "<<",
44
+ "<&",
45
+ "\n",
46
+ ";",
47
+ "|",
48
+ "&",
49
+ "(",
50
+ ")",
51
+ ">",
52
+ "<"
53
+ ];
54
+ // Reserved words and grouping braces open or close a compound command; the
55
+ // command they wrap stands after them.
56
+ const reservedWords = new Set([
57
+ "!",
58
+ "{",
59
+ "}",
60
+ "case",
61
+ "do",
62
+ "done",
63
+ "elif",
64
+ "else",
65
+ "esac",
66
+ "fi",
67
+ "for",
68
+ "function",
69
+ "if",
70
+ "in",
71
+ "select",
72
+ "then",
73
+ "until",
74
+ "while"
75
+ ]);
22
76
  const writeCommands = new Set(["chmod", "chown", "mkdir", "rm", "rmdir", "tee", "touch", "truncate", "unlink"]);
23
77
  const destinationCommands = new Set(["cp", "install", "mv"]);
24
78
  const prefixWrappers = new Set(["env", "nice", "time", "sudo", "nohup", "xargs", "command", "exec"]);
25
- // Shell spaces may disappear, but a physical line ends one command. Retaining
26
- // LF prevents a command on line one from classifying every later line's paths.
79
+ // The end of a `$(` body that starts at `from`: the index of its closing
80
+ // parenthesis, skipping quoted spans and nested parentheses. An unclosed body
81
+ // runs to the end of the text, which is how a fail-closed scan must read it.
82
+ // Substitutions and quotes nest without limit in a shell, but each level
83
+ // costs this scan a pass over the rest of the text and a stack frame. Fifty
84
+ // thousand `$(` used to run for half a minute and then overflow the stack, so
85
+ // past this depth the text is refused rather than scanned.
86
+ const maxNesting = 32;
87
+ const tooDeep = () => new StdError.StdError({
88
+ code: "invalid_input",
89
+ message: `Command nests substitutions or quotes deeper than ${maxNesting} levels`
90
+ });
91
+ const substitutionEnd = (text, from, nesting) => {
92
+ if (nesting > maxNesting)
93
+ throw tooDeep();
94
+ let depth = 1;
95
+ let index = from;
96
+ while (index < text.length) {
97
+ const char = text[index];
98
+ if (char === "\\") {
99
+ index += 2;
100
+ }
101
+ else if (char === "'") {
102
+ const close = text.indexOf("'", index + 1);
103
+ index = close === -1 ? text.length : close + 1;
104
+ }
105
+ else if (char === "\"") {
106
+ index = doubleQuoteEnd(text, index + 1, nesting + 1) + 1;
107
+ }
108
+ else if (char === "`") {
109
+ index = backtickEnd(text, index + 1) + 1;
110
+ }
111
+ else {
112
+ if (char === "(")
113
+ depth++;
114
+ if (char === ")" && --depth === 0)
115
+ return index;
116
+ index++;
117
+ }
118
+ }
119
+ return text.length;
120
+ };
121
+ const backtickEnd = (text, from) => {
122
+ let index = from;
123
+ while (index < text.length && text[index] !== "`")
124
+ index += text[index] === "\\" ? 2 : 1;
125
+ return Math.min(index, text.length);
126
+ };
127
+ const doubleQuoteEnd = (text, from, nesting) => {
128
+ if (nesting > maxNesting)
129
+ throw tooDeep();
130
+ let index = from;
131
+ while (index < text.length && text[index] !== "\"") {
132
+ const char = text[index];
133
+ if (char === "\\")
134
+ index += 2;
135
+ else if (char === "`")
136
+ index = backtickEnd(text, index + 1) + 1;
137
+ else if (char === "$" && text[index + 1] === "(")
138
+ index = substitutionEnd(text, index + 2, nesting + 1) + 1;
139
+ else
140
+ index++;
141
+ }
142
+ return Math.min(index, text.length);
143
+ };
144
+ // A hand-rolled lexer rather than one regular expression: a word is any run
145
+ // of bare characters, quoted spans, and substitutions, and a substitution can
146
+ // hold quotes and operators of its own. Splitting on operator characters
147
+ // alone let `echo "$(rm /work/target)"` hide a delete inside one quoted word,
148
+ // read `>|` as a pipe that turned the target into the next command's name,
149
+ // and read `(rm /work/target)` as a command named `(rm`.
27
150
  //
28
- // A word is one or more runs of bare characters and quoted sections, not a
29
- // bare run alone: `FOO="a b" rm /work/target` used to tokenize as `FOO="a`,
30
- // `b"`, `rm`, `/work/target`, and since only the first token carried an `=`
31
- // the command was read as `b"` rather than `rm` — so the delete was
32
- // classified as a read and a hermetic call with `writes: []` spawned. The
33
- // quoted alternatives come first inside the group so a quoted span is taken
34
- // whole; the bare class excludes quotes so the branches cannot overlap.
35
- const tokenize = (command) => command.match(/\n|>>|<<|&&|\|\||[<>;|&]|(?:"(?:\\.|[^"\\])*"|'[^']*'|[^\s<>;|&"']+)+/g) ?? [];
36
- const unquote = (token) => {
37
- const first = token[0];
38
- const last = token[token.length - 1];
39
- return token.length >= 2 && (first === "'" || first === "\"") && last === first
40
- ? token.slice(1, -1)
41
- : token;
151
+ // Quotes are removed from a word's text, because `"/outs"ide/x` names
152
+ // `/outside/x`; keeping the quotes made it a relative path under the
153
+ // working directory.
154
+ // Sticky, so the match starts at `lastIndex` without copying the rest of the
155
+ // text for every word.
156
+ const descriptorPattern = /\d+(?=[<>])/y;
157
+ const lex = (command, nesting) => {
158
+ const tokens = [];
159
+ const substitutions = [];
160
+ let index = 0;
161
+ const substitution = (from, to) => {
162
+ substitutions.push(command.slice(from, to));
163
+ return "$()";
164
+ };
165
+ while (index < command.length) {
166
+ const char = command[index];
167
+ // Every blank the word loop stops at must be skipped here, or the lexer
168
+ // would push an empty word without advancing.
169
+ if (char !== "\n" && /\s/.test(char)) {
170
+ index++;
171
+ continue;
172
+ }
173
+ if (char === "\\" && command[index + 1] === "\n") {
174
+ index += 2;
175
+ continue;
176
+ }
177
+ if (char === "#") {
178
+ while (index < command.length && command[index] !== "\n")
179
+ index++;
180
+ continue;
181
+ }
182
+ // A file-descriptor number belongs to the redirection after it: in
183
+ // `2>/dev/null rm /work/target` the command is `rm`, not `2`.
184
+ descriptorPattern.lastIndex = index;
185
+ const descriptor = descriptorPattern.exec(command);
186
+ if (descriptor !== null) {
187
+ index += descriptor[0].length;
188
+ continue;
189
+ }
190
+ const operator = operators.find((candidate) => command.startsWith(candidate, index));
191
+ if (operator !== undefined) {
192
+ tokens.push({ operator: true, text: operator });
193
+ index += operator.length;
194
+ continue;
195
+ }
196
+ let text = "";
197
+ while (index < command.length) {
198
+ const next = command[index];
199
+ if (/[\s<>;|&()]/.test(next))
200
+ break;
201
+ if (next === "\\") {
202
+ // A backslash escapes shell syntax. Before any other character it is
203
+ // kept, so `C:\work\input` stays the path it names on Windows rather
204
+ // than collapsing to a word the scan cannot see as a path.
205
+ const escaped = command[index + 1] ?? "";
206
+ if (escaped !== "\n")
207
+ text += /[\s<>;|&()'"`$\\#]/.test(escaped) ? escaped : `\\${escaped}`;
208
+ index += 2;
209
+ }
210
+ else if (next === "'") {
211
+ const close = command.indexOf("'", index + 1);
212
+ const end = close === -1 ? command.length : close;
213
+ text += command.slice(index + 1, end);
214
+ index = end + 1;
215
+ }
216
+ else if (next === "\"") {
217
+ const end = doubleQuoteEnd(command, index + 1, nesting + 1);
218
+ let inner = index + 1;
219
+ while (inner < end) {
220
+ const quoted = command[inner];
221
+ if (quoted === "\\" && /[$`"\\\n]/.test(command[inner + 1] ?? "")) {
222
+ if (command[inner + 1] !== "\n")
223
+ text += command[inner + 1];
224
+ inner += 2;
225
+ }
226
+ else if (quoted === "`") {
227
+ const close = backtickEnd(command, inner + 1);
228
+ text += substitution(inner + 1, close);
229
+ inner = close + 1;
230
+ }
231
+ else if (quoted === "$" && command[inner + 1] === "(") {
232
+ const close = substitutionEnd(command, inner + 2, nesting + 2);
233
+ text += substitution(inner + 2, close);
234
+ inner = close + 1;
235
+ }
236
+ else {
237
+ text += quoted;
238
+ inner++;
239
+ }
240
+ }
241
+ index = end + 1;
242
+ }
243
+ else if (next === "`") {
244
+ const close = backtickEnd(command, index + 1);
245
+ text += substitution(index + 1, close);
246
+ index = close + 1;
247
+ }
248
+ else if (next === "$" && command[index + 1] === "(") {
249
+ const close = substitutionEnd(command, index + 2, nesting + 1);
250
+ text += substitution(index + 2, close);
251
+ index = close + 1;
252
+ }
253
+ else {
254
+ text += next;
255
+ index++;
256
+ }
257
+ }
258
+ tokens.push({ operator: false, text });
259
+ }
260
+ return { tokens, substitutions };
42
261
  };
43
- const pathValue = (token) => unquote(token)
44
- .replace(/^\$\(+/, "")
45
- .replace(/[),]+$/, "");
262
+ // A parenthesis is an operator to the lexer, so one left in a word was quoted
263
+ // and is part of the name; only a trailing comma is punctuation.
264
+ const pathValue = (token) => token.replace(/,+$/, "");
46
265
  const isPathToken = (path, token) => token === "." ||
47
266
  token === ".." ||
48
267
  token.startsWith("./") ||
@@ -51,69 +270,76 @@ const isPathToken = (path, token) => token === "." ||
51
270
  /^[A-Za-z]:[\\/]/.test(token) ||
52
271
  token.includes("/");
53
272
  const segmentReferences = (path, tokens) => {
54
- const commentIndex = tokens.findIndex((token) => token.startsWith("#"));
55
- const active = commentIndex === -1 ? tokens : tokens.slice(0, commentIndex);
56
- const hasWrapper = active.some((token) => prefixWrappers.has(path.basename(pathValue(token))));
57
- let commandIndex = active.findIndex((token) => !redirections.has(token) &&
58
- !token.includes("=") &&
59
- !prefixWrappers.has(path.basename(pathValue(token))) &&
60
- !token.startsWith("-") &&
61
- token !== "");
273
+ // The word after a redirection operator is its target, never the command.
274
+ const isTarget = (index) => index > 0 && isRedirection(tokens[index - 1]);
275
+ const isWord = (index) => !tokens[index].operator && !isTarget(index);
276
+ const name = (index) => path.basename(pathValue(tokens[index].text));
277
+ const hasWrapper = tokens.some((_, index) => isWord(index) && prefixWrappers.has(name(index)));
278
+ let commandIndex = tokens.findIndex((token, index) => isWord(index) &&
279
+ !token.text.includes("=") &&
280
+ !prefixWrappers.has(name(index)) &&
281
+ !reservedWords.has(token.text) &&
282
+ !token.text.startsWith("-") &&
283
+ token.text !== "");
62
284
  if (hasWrapper) {
63
285
  // Wrapper options can carry their own values. Prefer a later known
64
286
  // mutating command so an option value cannot lend it a read classification.
65
- const mutatingIndex = active.findIndex((token) => {
66
- const command = path.basename(pathValue(token));
67
- return writeCommands.has(command) || destinationCommands.has(command);
68
- });
287
+ const mutatingIndex = tokens.findIndex((_, index) => isWord(index) && (writeCommands.has(name(index)) || destinationCommands.has(name(index))));
69
288
  if (mutatingIndex !== -1)
70
289
  commandIndex = mutatingIndex;
71
290
  }
72
- if (commandIndex === -1)
73
- return [];
74
- const command = path.basename(pathValue(active[commandIndex]));
291
+ const command = commandIndex === -1 ? "" : name(commandIndex);
75
292
  const candidates = [];
76
- for (let index = 0; index < active.length; index++) {
77
- const token = active[index];
78
- if (index === commandIndex || redirections.has(token) || token.startsWith("-"))
293
+ for (let index = 0; index < tokens.length; index++) {
294
+ const token = tokens[index];
295
+ if (index === commandIndex || token.operator || (!isTarget(index) && token.text.startsWith("-")))
296
+ continue;
297
+ if (isTarget(index) && textRedirections.has(tokens[index - 1].text))
79
298
  continue;
80
- const value = pathValue(token);
299
+ const value = pathValue(token.text);
81
300
  if (value !== "" && isPathToken(path, value))
82
301
  candidates.push({ index, value });
83
302
  }
84
303
  const destinationIndex = destinationCommands.has(command)
85
- ? candidates[candidates.length - 1]?.index
304
+ ? candidates.filter(({ index }) => !isTarget(index)).at(-1)?.index
86
305
  : undefined;
87
306
  return candidates.map(({ index, value }) => {
88
- const previous = active[index - 1];
89
- const access = previous === ">" || previous === ">>" ||
90
- writeCommands.has(command) || destinationIndex === index
91
- ? "write"
92
- : "read";
307
+ const access = isTarget(index)
308
+ ? writeRedirections.has(tokens[index - 1].text) ? "write" : "read"
309
+ : writeCommands.has(command) || destinationIndex === index
310
+ ? "write"
311
+ : "read";
93
312
  return { access, value };
94
313
  });
95
314
  };
96
- /**
97
- * Every path token the shell text names, one segment at a time.
98
- *
99
- * @category pre-check
100
- * @since 1.0.0
101
- */
102
- export const commandReferences = (path, command) => {
103
- const references = [];
315
+ const references = (path, command, nesting) => {
316
+ const { substitutions, tokens } = lex(command, nesting);
317
+ const found = [];
104
318
  let segment = [];
105
- for (const token of tokenize(command)) {
106
- if (commandSeparators.has(token)) {
107
- references.push(...segmentReferences(path, segment));
319
+ for (const token of tokens) {
320
+ if (token.operator && commandSeparators.has(token.text)) {
321
+ found.push(...segmentReferences(path, segment));
108
322
  segment = [];
109
323
  }
110
324
  else {
111
325
  segment.push(token);
112
326
  }
113
327
  }
114
- references.push(...segmentReferences(path, segment));
115
- return references;
328
+ found.push(...segmentReferences(path, segment));
329
+ // A substitution runs its body as a command; its paths count like any other.
330
+ for (const body of substitutions)
331
+ found.push(...references(path, body, nesting + 1));
332
+ return found;
116
333
  };
334
+ /**
335
+ * Every path token the shell text names, one segment at a time.
336
+ *
337
+ * @throws {StdError.StdError} `invalid_input` when substitutions or quotes nest
338
+ * deeper than the scan reads.
339
+ * @category pre-check
340
+ * @since 1.0.0
341
+ */
342
+ export const commandReferences = (path, command) => references(path, command, 0);
117
343
  const resolvePath = (path, cwd, value) => path.isAbsolute(value) ? path.normalize(value) : path.resolve(cwd, value);
118
344
  const isDeclared = (path, cwd, declared, source) => withinEnvelope(declared.map((entry) => resolvePath(path, cwd, entry)), resolvePath(path, cwd, source));
119
345
  /**
@@ -145,7 +371,16 @@ export const outsideEnvelope = (input, text, path) => {
145
371
  // This lexical scan is intentionally only a fail-closed pre-check for
146
372
  // explicit path tokens. It cannot prove confinement; a kernel/host sandbox
147
373
  // must eventually enforce and report the complete read and write sets.
148
- for (const reference of commandReferences(path, text)) {
374
+ let named;
375
+ try {
376
+ named = commandReferences(path, text);
377
+ }
378
+ catch {
379
+ // The depth bound is the one failure the scan raises, and a text the scan
380
+ // cannot read is refused whatever the reason, never run unchecked.
381
+ return tooDeep();
382
+ }
383
+ for (const reference of named) {
149
384
  const resolved = resolvePath(path, cwd, reference.value);
150
385
  // /dev/* is the process plumbing every shell one-liner leans on:
151
386
  // `2>/dev/null`, `cat /dev/stdin`. Normalize first so a dot-dot segment
@@ -1 +1 @@
1
- {"version":3,"file":"EnvelopePrecheck.js","sourceRoot":"","sources":["../../../src/internal/EnvelopePrecheck.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The hermetic pre-check: a lexical scan of shell text for the paths it names,\n * and the refusal when one of them falls outside the declared envelope.\n *\n * The scan is fail-closed over explicit path tokens and nothing more. It\n * cannot prove confinement — a shell can name a path no lexer sees, through a\n * variable, a substitution, or a program that opens a file of its own — so a\n * kernel or host sandbox must eventually enforce and report the complete read\n * and write sets.\n *\n * It lives beside the flow rather than inside it because it is its own\n * concept, with its own vocabulary (Access, PathReference) and its own\n * security history: three independent bypasses, each sufficient on its own to\n * defeat it, are closed here.\n *\n * @since 1.0.0\n */\n\nimport type * as Path from \"@smthrs/kernel/Path\"\nimport * as StdError from \"../StdError.ts\"\nimport { withinEnvelope } from \"./Paths.ts\"\n\n/**\n * The filesystem envelope one invocation declared.\n *\n * Structural rather than the hermetic `Bash.Input` itself: the scan needs the\n * three fields and none of the rest, and depending on the flow module would\n * make the flow and its pre-check import each other.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface Envelope {\n readonly cwd?: string | undefined\n readonly reads: ReadonlyArray<string>\n readonly writes: ReadonlyArray<string>\n}\n\n/**\n * How a command touches a path it names.\n *\n * @category models\n * @since 1.0.0\n */\nexport type Access = \"read\" | \"write\"\n\n/**\n * One path a command names, and how it touches it.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface PathReference {\n readonly access: Access\n readonly value: string\n}\n\nconst commandSeparators = new Set([\"&&\", \"||\", \";\", \"|\", \"&\", \"\\n\"])\nconst redirections = new Set([\">\", \">>\", \"<\", \"<<\"])\nconst writeCommands = new Set([\"chmod\", \"chown\", \"mkdir\", \"rm\", \"rmdir\", \"tee\", \"touch\", \"truncate\", \"unlink\"])\nconst destinationCommands = new Set([\"cp\", \"install\", \"mv\"])\nconst prefixWrappers = new Set([\"env\", \"nice\", \"time\", \"sudo\", \"nohup\", \"xargs\", \"command\", \"exec\"])\n\n// Shell spaces may disappear, but a physical line ends one command. Retaining\n// LF prevents a command on line one from classifying every later line's paths.\n//\n// A word is one or more runs of bare characters and quoted sections, not a\n// bare run alone: `FOO=\"a b\" rm /work/target` used to tokenize as `FOO=\"a`,\n// `b\"`, `rm`, `/work/target`, and since only the first token carried an `=`\n// the command was read as `b\"` rather than `rm` — so the delete was\n// classified as a read and a hermetic call with `writes: []` spawned. The\n// quoted alternatives come first inside the group so a quoted span is taken\n// whole; the bare class excludes quotes so the branches cannot overlap.\nconst tokenize = (command: string): ReadonlyArray<string> =>\n command.match(/\\n|>>|<<|&&|\\|\\||[<>;|&]|(?:\"(?:\\\\.|[^\"\\\\])*\"|'[^']*'|[^\\s<>;|&\"']+)+/g) ?? []\n\nconst unquote = (token: string): string => {\n const first = token[0]\n const last = token[token.length - 1]\n return token.length >= 2 && (first === \"'\" || first === \"\\\"\") && last === first\n ? token.slice(1, -1)\n : token\n}\n\nconst pathValue = (token: string): string =>\n unquote(token)\n .replace(/^\\$\\(+/, \"\")\n .replace(/[),]+$/, \"\")\n\nconst isPathToken = (path: Path.Path, token: string): boolean =>\n token === \".\" ||\n token === \"..\" ||\n token.startsWith(\"./\") ||\n token.startsWith(\"../\") ||\n path.isAbsolute(token) ||\n /^[A-Za-z]:[\\\\/]/.test(token) ||\n token.includes(\"/\")\n\nconst segmentReferences = (path: Path.Path, tokens: ReadonlyArray<string>): ReadonlyArray<PathReference> => {\n const commentIndex = tokens.findIndex((token) => token.startsWith(\"#\"))\n const active = commentIndex === -1 ? tokens : tokens.slice(0, commentIndex)\n const hasWrapper = active.some((token) => prefixWrappers.has(path.basename(pathValue(token))))\n let commandIndex = active.findIndex((token) =>\n !redirections.has(token) &&\n !token.includes(\"=\") &&\n !prefixWrappers.has(path.basename(pathValue(token))) &&\n !token.startsWith(\"-\") &&\n token !== \"\"\n )\n if (hasWrapper) {\n // Wrapper options can carry their own values. Prefer a later known\n // mutating command so an option value cannot lend it a read classification.\n const mutatingIndex = active.findIndex((token) => {\n const command = path.basename(pathValue(token))\n return writeCommands.has(command) || destinationCommands.has(command)\n })\n if (mutatingIndex !== -1) commandIndex = mutatingIndex\n }\n if (commandIndex === -1) return []\n\n const command = path.basename(pathValue(active[commandIndex]!))\n const candidates: Array<{ readonly index: number; readonly value: string }> = []\n for (let index = 0; index < active.length; index++) {\n const token = active[index]!\n if (index === commandIndex || redirections.has(token) || token.startsWith(\"-\")) continue\n const value = pathValue(token)\n if (value !== \"\" && isPathToken(path, value)) candidates.push({ index, value })\n }\n\n const destinationIndex = destinationCommands.has(command)\n ? candidates[candidates.length - 1]?.index\n : undefined\n\n return candidates.map(({ index, value }) => {\n const previous = active[index - 1]\n const access: Access = previous === \">\" || previous === \">>\" ||\n writeCommands.has(command) || destinationIndex === index\n ? \"write\"\n : \"read\"\n return { access, value }\n })\n}\n\n/**\n * Every path token the shell text names, one segment at a time.\n *\n * @category pre-check\n * @since 1.0.0\n */\nexport const commandReferences = (path: Path.Path, command: string): ReadonlyArray<PathReference> => {\n const references: Array<PathReference> = []\n let segment: Array<string> = []\n for (const token of tokenize(command)) {\n if (commandSeparators.has(token)) {\n references.push(...segmentReferences(path, segment))\n segment = []\n } else {\n segment.push(token)\n }\n }\n references.push(...segmentReferences(path, segment))\n return references\n}\n\nconst resolvePath = (\n path: Path.Path,\n cwd: string,\n value: string\n): string => path.isAbsolute(value) ? path.normalize(value) : path.resolve(cwd, value)\n\nconst isDeclared = (\n path: Path.Path,\n cwd: string,\n declared: ReadonlyArray<string>,\n source: string\n): boolean =>\n withinEnvelope(\n declared.map((entry) => resolvePath(path, cwd, entry)),\n resolvePath(path, cwd, source)\n )\n\n/**\n * The refusal shell text earns by naming a path outside its declared\n * envelope, or `undefined` when every path it names is declared.\n *\n * @category pre-check\n * @since 1.0.0\n */\nexport const outsideEnvelope = (\n input: Envelope,\n text: string,\n path: Path.Path\n): StdError.StdError | undefined => {\n const base = path.resolve(\".\")\n const cwd = path.resolve(input.cwd ?? \".\")\n // Passing the default explicitly is not a declaration the caller owes. A\n // working directory is where the command runs, not a file it reads, and\n // `cwd: \".\"` names exactly what omitting `cwd` names — so refusing it asked\n // the caller to list the workspace root among its reads to say nothing at\n // all. Agents hit this constantly: one SWE-bench run spent ten of its\n // forty-eight tool calls re-issuing the same command after\n // \"Working directory is outside declared reads: <the workspace root>\". A\n // cwd that points somewhere else is still declared or refused.\n if (input.cwd !== undefined && cwd !== base && !isDeclared(path, cwd, input.reads, cwd)) {\n return new StdError.StdError({\n code: \"outside_declared_reads\",\n message: `Working directory is outside declared reads: ${cwd}`,\n path: cwd\n })\n }\n\n // The Shell contract currently has no sandbox or access-reporting surface.\n // This lexical scan is intentionally only a fail-closed pre-check for\n // explicit path tokens. It cannot prove confinement; a kernel/host sandbox\n // must eventually enforce and report the complete read and write sets.\n for (const reference of commandReferences(path, text)) {\n const resolved = resolvePath(path, cwd, reference.value)\n // /dev/* is the process plumbing every shell one-liner leans on:\n // `2>/dev/null`, `cat /dev/stdin`. Normalize first so a dot-dot segment\n // cannot disguise an ordinary filesystem path as process plumbing.\n if (resolved.startsWith(\"/dev/\")) continue\n const declared = reference.access === \"write\" ? input.writes : input.reads\n if (!isDeclared(path, cwd, declared, resolved)) {\n const code = reference.access === \"write\" ? \"outside_declared_writes\" : \"outside_declared_reads\"\n return new StdError.StdError({\n code,\n message: `Command path is outside declared ${reference.access}s: ${resolved}`,\n path: resolved\n })\n }\n }\n return undefined\n}\n"]}
1
+ {"version":3,"file":"EnvelopePrecheck.js","sourceRoot":"","sources":["../../../src/internal/EnvelopePrecheck.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The hermetic pre-check: a lexical scan of shell text for the paths it names,\n * and the refusal when one of them falls outside the declared envelope.\n *\n * The scan is fail-closed over explicit path tokens and nothing more. It\n * cannot prove confinement — a shell can name a path no lexer sees, through a\n * variable, a substitution, or a program that opens a file of its own — so a\n * kernel or host sandbox must eventually enforce and report the complete read\n * and write sets.\n *\n * It lives beside the flow rather than inside it because it is its own\n * concept, with its own vocabulary (Access, PathReference) and its own\n * security history: three independent bypasses, each sufficient on its own to\n * defeat it, are closed here.\n *\n * @since 1.0.0\n */\n\nimport type * as Path from \"@smthrs/kernel/Path\"\nimport * as StdError from \"../StdError.ts\"\nimport { withinEnvelope } from \"./Paths.ts\"\n\n/**\n * The filesystem envelope one invocation declared.\n *\n * Structural rather than the hermetic `Bash.Input` itself: the scan needs the\n * three fields and none of the rest, and depending on the flow module would\n * make the flow and its pre-check import each other.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface Envelope {\n readonly cwd?: string | undefined\n readonly reads: ReadonlyArray<string>\n readonly writes: ReadonlyArray<string>\n}\n\n/**\n * How a command touches a path it names.\n *\n * @category models\n * @since 1.0.0\n */\nexport type Access = \"read\" | \"write\"\n\n/**\n * One path a command names, and how it touches it.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface PathReference {\n readonly access: Access\n readonly value: string\n}\n\nconst commandSeparators = new Set([\"&&\", \"||\", \";\", \";;\", \";&\", \";;&\", \"|\", \"|&\", \"&\", \"\\n\", \"(\", \")\"])\nconst writeRedirections = new Set([\">\", \">>\", \">|\", \"&>\", \"&>>\", \">&\", \"<>\"])\nconst readRedirections = new Set([\"<\", \"<&\"])\n// A here-document delimiter and a here-string are text, not file names.\nconst textRedirections = new Set([\"<<\", \"<<-\", \"<<<\"])\nconst isRedirection = (token: Token): boolean =>\n token.operator &&\n (writeRedirections.has(token.text) || readRedirections.has(token.text) || textRedirections.has(token.text))\n// Longest first, so `&>>` is not read as `&` then `>>`.\nconst operators = [\n \";;&\",\n \"&>>\",\n \"<<<\",\n \"<<-\",\n \";;\",\n \";&\",\n \"&&\",\n \"||\",\n \"|&\",\n \"&>\",\n \">>\",\n \">|\",\n \">&\",\n \"<>\",\n \"<<\",\n \"<&\",\n \"\\n\",\n \";\",\n \"|\",\n \"&\",\n \"(\",\n \")\",\n \">\",\n \"<\"\n]\n// Reserved words and grouping braces open or close a compound command; the\n// command they wrap stands after them.\nconst reservedWords = new Set([\n \"!\",\n \"{\",\n \"}\",\n \"case\",\n \"do\",\n \"done\",\n \"elif\",\n \"else\",\n \"esac\",\n \"fi\",\n \"for\",\n \"function\",\n \"if\",\n \"in\",\n \"select\",\n \"then\",\n \"until\",\n \"while\"\n])\nconst writeCommands = new Set([\"chmod\", \"chown\", \"mkdir\", \"rm\", \"rmdir\", \"tee\", \"touch\", \"truncate\", \"unlink\"])\nconst destinationCommands = new Set([\"cp\", \"install\", \"mv\"])\nconst prefixWrappers = new Set([\"env\", \"nice\", \"time\", \"sudo\", \"nohup\", \"xargs\", \"command\", \"exec\"])\n\n/**\n * One lexical unit of shell text: an operator, or a word with its quotes\n * removed. A command substitution inside a word stands as `$()` in the word;\n * its body is scanned as a command of its own.\n */\ninterface Token {\n readonly operator: boolean\n readonly text: string\n}\n\ninterface Lexed {\n readonly tokens: ReadonlyArray<Token>\n readonly substitutions: ReadonlyArray<string>\n}\n\n// The end of a `$(` body that starts at `from`: the index of its closing\n// parenthesis, skipping quoted spans and nested parentheses. An unclosed body\n// runs to the end of the text, which is how a fail-closed scan must read it.\n// Substitutions and quotes nest without limit in a shell, but each level\n// costs this scan a pass over the rest of the text and a stack frame. Fifty\n// thousand `$(` used to run for half a minute and then overflow the stack, so\n// past this depth the text is refused rather than scanned.\nconst maxNesting = 32\n\nconst tooDeep = (): StdError.StdError =>\n new StdError.StdError({\n code: \"invalid_input\",\n message: `Command nests substitutions or quotes deeper than ${maxNesting} levels`\n })\n\nconst substitutionEnd = (text: string, from: number, nesting: number): number => {\n if (nesting > maxNesting) throw tooDeep()\n let depth = 1\n let index = from\n while (index < text.length) {\n const char = text[index]!\n if (char === \"\\\\\") {\n index += 2\n } else if (char === \"'\") {\n const close = text.indexOf(\"'\", index + 1)\n index = close === -1 ? text.length : close + 1\n } else if (char === \"\\\"\") {\n index = doubleQuoteEnd(text, index + 1, nesting + 1) + 1\n } else if (char === \"`\") {\n index = backtickEnd(text, index + 1) + 1\n } else {\n if (char === \"(\") depth++\n if (char === \")\" && --depth === 0) return index\n index++\n }\n }\n return text.length\n}\n\nconst backtickEnd = (text: string, from: number): number => {\n let index = from\n while (index < text.length && text[index] !== \"`\") index += text[index] === \"\\\\\" ? 2 : 1\n return Math.min(index, text.length)\n}\n\nconst doubleQuoteEnd = (text: string, from: number, nesting: number): number => {\n if (nesting > maxNesting) throw tooDeep()\n let index = from\n while (index < text.length && text[index] !== \"\\\"\") {\n const char = text[index]!\n if (char === \"\\\\\") index += 2\n else if (char === \"`\") index = backtickEnd(text, index + 1) + 1\n else if (char === \"$\" && text[index + 1] === \"(\") index = substitutionEnd(text, index + 2, nesting + 1) + 1\n else index++\n }\n return Math.min(index, text.length)\n}\n\n// A hand-rolled lexer rather than one regular expression: a word is any run\n// of bare characters, quoted spans, and substitutions, and a substitution can\n// hold quotes and operators of its own. Splitting on operator characters\n// alone let `echo \"$(rm /work/target)\"` hide a delete inside one quoted word,\n// read `>|` as a pipe that turned the target into the next command's name,\n// and read `(rm /work/target)` as a command named `(rm`.\n//\n// Quotes are removed from a word's text, because `\"/outs\"ide/x` names\n// `/outside/x`; keeping the quotes made it a relative path under the\n// working directory.\n// Sticky, so the match starts at `lastIndex` without copying the rest of the\n// text for every word.\nconst descriptorPattern = /\\d+(?=[<>])/y\n\nconst lex = (command: string, nesting: number): Lexed => {\n const tokens: Array<Token> = []\n const substitutions: Array<string> = []\n let index = 0\n const substitution = (from: number, to: number): string => {\n substitutions.push(command.slice(from, to))\n return \"$()\"\n }\n while (index < command.length) {\n const char = command[index]!\n // Every blank the word loop stops at must be skipped here, or the lexer\n // would push an empty word without advancing.\n if (char !== \"\\n\" && /\\s/.test(char)) {\n index++\n continue\n }\n if (char === \"\\\\\" && command[index + 1] === \"\\n\") {\n index += 2\n continue\n }\n if (char === \"#\") {\n while (index < command.length && command[index] !== \"\\n\") index++\n continue\n }\n // A file-descriptor number belongs to the redirection after it: in\n // `2>/dev/null rm /work/target` the command is `rm`, not `2`.\n descriptorPattern.lastIndex = index\n const descriptor = descriptorPattern.exec(command)\n if (descriptor !== null) {\n index += descriptor[0].length\n continue\n }\n const operator = operators.find((candidate) => command.startsWith(candidate, index))\n if (operator !== undefined) {\n tokens.push({ operator: true, text: operator })\n index += operator.length\n continue\n }\n let text = \"\"\n while (index < command.length) {\n const next = command[index]!\n if (/[\\s<>;|&()]/.test(next)) break\n if (next === \"\\\\\") {\n // A backslash escapes shell syntax. Before any other character it is\n // kept, so `C:\\work\\input` stays the path it names on Windows rather\n // than collapsing to a word the scan cannot see as a path.\n const escaped = command[index + 1] ?? \"\"\n if (escaped !== \"\\n\") text += /[\\s<>;|&()'\"`$\\\\#]/.test(escaped) ? escaped : `\\\\${escaped}`\n index += 2\n } else if (next === \"'\") {\n const close = command.indexOf(\"'\", index + 1)\n const end = close === -1 ? command.length : close\n text += command.slice(index + 1, end)\n index = end + 1\n } else if (next === \"\\\"\") {\n const end = doubleQuoteEnd(command, index + 1, nesting + 1)\n let inner = index + 1\n while (inner < end) {\n const quoted = command[inner]!\n if (quoted === \"\\\\\" && /[$`\"\\\\\\n]/.test(command[inner + 1] ?? \"\")) {\n if (command[inner + 1] !== \"\\n\") text += command[inner + 1]\n inner += 2\n } else if (quoted === \"`\") {\n const close = backtickEnd(command, inner + 1)\n text += substitution(inner + 1, close)\n inner = close + 1\n } else if (quoted === \"$\" && command[inner + 1] === \"(\") {\n const close = substitutionEnd(command, inner + 2, nesting + 2)\n text += substitution(inner + 2, close)\n inner = close + 1\n } else {\n text += quoted\n inner++\n }\n }\n index = end + 1\n } else if (next === \"`\") {\n const close = backtickEnd(command, index + 1)\n text += substitution(index + 1, close)\n index = close + 1\n } else if (next === \"$\" && command[index + 1] === \"(\") {\n const close = substitutionEnd(command, index + 2, nesting + 1)\n text += substitution(index + 2, close)\n index = close + 1\n } else {\n text += next\n index++\n }\n }\n tokens.push({ operator: false, text })\n }\n return { tokens, substitutions }\n}\n\n// A parenthesis is an operator to the lexer, so one left in a word was quoted\n// and is part of the name; only a trailing comma is punctuation.\nconst pathValue = (token: string): string => token.replace(/,+$/, \"\")\n\nconst isPathToken = (path: Path.Path, token: string): boolean =>\n token === \".\" ||\n token === \"..\" ||\n token.startsWith(\"./\") ||\n token.startsWith(\"../\") ||\n path.isAbsolute(token) ||\n /^[A-Za-z]:[\\\\/]/.test(token) ||\n token.includes(\"/\")\n\nconst segmentReferences = (path: Path.Path, tokens: ReadonlyArray<Token>): ReadonlyArray<PathReference> => {\n // The word after a redirection operator is its target, never the command.\n const isTarget = (index: number): boolean => index > 0 && isRedirection(tokens[index - 1]!)\n const isWord = (index: number): boolean => !tokens[index]!.operator && !isTarget(index)\n const name = (index: number): string => path.basename(pathValue(tokens[index]!.text))\n const hasWrapper = tokens.some((_, index) => isWord(index) && prefixWrappers.has(name(index)))\n let commandIndex = tokens.findIndex((token, index) =>\n isWord(index) &&\n !token.text.includes(\"=\") &&\n !prefixWrappers.has(name(index)) &&\n !reservedWords.has(token.text) &&\n !token.text.startsWith(\"-\") &&\n token.text !== \"\"\n )\n if (hasWrapper) {\n // Wrapper options can carry their own values. Prefer a later known\n // mutating command so an option value cannot lend it a read classification.\n const mutatingIndex = tokens.findIndex((_, index) =>\n isWord(index) && (writeCommands.has(name(index)) || destinationCommands.has(name(index)))\n )\n if (mutatingIndex !== -1) commandIndex = mutatingIndex\n }\n\n const command = commandIndex === -1 ? \"\" : name(commandIndex)\n const candidates: Array<{ readonly index: number; readonly value: string }> = []\n for (let index = 0; index < tokens.length; index++) {\n const token = tokens[index]!\n if (index === commandIndex || token.operator || (!isTarget(index) && token.text.startsWith(\"-\"))) continue\n if (isTarget(index) && textRedirections.has(tokens[index - 1]!.text)) continue\n const value = pathValue(token.text)\n if (value !== \"\" && isPathToken(path, value)) candidates.push({ index, value })\n }\n\n const destinationIndex = destinationCommands.has(command)\n ? candidates.filter(({ index }) => !isTarget(index)).at(-1)?.index\n : undefined\n\n return candidates.map(({ index, value }) => {\n const access: Access = isTarget(index)\n ? writeRedirections.has(tokens[index - 1]!.text) ? \"write\" : \"read\"\n : writeCommands.has(command) || destinationIndex === index\n ? \"write\"\n : \"read\"\n return { access, value }\n })\n}\n\nconst references = (path: Path.Path, command: string, nesting: number): ReadonlyArray<PathReference> => {\n const { substitutions, tokens } = lex(command, nesting)\n const found: Array<PathReference> = []\n let segment: Array<Token> = []\n for (const token of tokens) {\n if (token.operator && commandSeparators.has(token.text)) {\n found.push(...segmentReferences(path, segment))\n segment = []\n } else {\n segment.push(token)\n }\n }\n found.push(...segmentReferences(path, segment))\n // A substitution runs its body as a command; its paths count like any other.\n for (const body of substitutions) found.push(...references(path, body, nesting + 1))\n return found\n}\n\n/**\n * Every path token the shell text names, one segment at a time.\n *\n * @throws {StdError.StdError} `invalid_input` when substitutions or quotes nest\n * deeper than the scan reads.\n * @category pre-check\n * @since 1.0.0\n */\nexport const commandReferences = (path: Path.Path, command: string): ReadonlyArray<PathReference> =>\n references(path, command, 0)\n\nconst resolvePath = (\n path: Path.Path,\n cwd: string,\n value: string\n): string => path.isAbsolute(value) ? path.normalize(value) : path.resolve(cwd, value)\n\nconst isDeclared = (\n path: Path.Path,\n cwd: string,\n declared: ReadonlyArray<string>,\n source: string\n): boolean =>\n withinEnvelope(\n declared.map((entry) => resolvePath(path, cwd, entry)),\n resolvePath(path, cwd, source)\n )\n\n/**\n * The refusal shell text earns by naming a path outside its declared\n * envelope, or `undefined` when every path it names is declared.\n *\n * @category pre-check\n * @since 1.0.0\n */\nexport const outsideEnvelope = (\n input: Envelope,\n text: string,\n path: Path.Path\n): StdError.StdError | undefined => {\n const base = path.resolve(\".\")\n const cwd = path.resolve(input.cwd ?? \".\")\n // Passing the default explicitly is not a declaration the caller owes. A\n // working directory is where the command runs, not a file it reads, and\n // `cwd: \".\"` names exactly what omitting `cwd` names — so refusing it asked\n // the caller to list the workspace root among its reads to say nothing at\n // all. Agents hit this constantly: one SWE-bench run spent ten of its\n // forty-eight tool calls re-issuing the same command after\n // \"Working directory is outside declared reads: <the workspace root>\". A\n // cwd that points somewhere else is still declared or refused.\n if (input.cwd !== undefined && cwd !== base && !isDeclared(path, cwd, input.reads, cwd)) {\n return new StdError.StdError({\n code: \"outside_declared_reads\",\n message: `Working directory is outside declared reads: ${cwd}`,\n path: cwd\n })\n }\n\n // The Shell contract currently has no sandbox or access-reporting surface.\n // This lexical scan is intentionally only a fail-closed pre-check for\n // explicit path tokens. It cannot prove confinement; a kernel/host sandbox\n // must eventually enforce and report the complete read and write sets.\n let named: ReadonlyArray<PathReference>\n try {\n named = commandReferences(path, text)\n } catch {\n // The depth bound is the one failure the scan raises, and a text the scan\n // cannot read is refused whatever the reason, never run unchecked.\n return tooDeep()\n }\n for (const reference of named) {\n const resolved = resolvePath(path, cwd, reference.value)\n // /dev/* is the process plumbing every shell one-liner leans on:\n // `2>/dev/null`, `cat /dev/stdin`. Normalize first so a dot-dot segment\n // cannot disguise an ordinary filesystem path as process plumbing.\n if (resolved.startsWith(\"/dev/\")) continue\n const declared = reference.access === \"write\" ? input.writes : input.reads\n if (!isDeclared(path, cwd, declared, resolved)) {\n const code = reference.access === \"write\" ? \"outside_declared_writes\" : \"outside_declared_reads\"\n return new StdError.StdError({\n code,\n message: `Command path is outside declared ${reference.access}s: ${resolved}`,\n path: resolved\n })\n }\n }\n return undefined\n}\n"]}
@@ -24,7 +24,7 @@ import * as StdError from "../StdError.ts";
24
24
  * @category models
25
25
  * @since 1.0.0
26
26
  */
27
- export declare const ExecErrorCode: Schema.Literals<readonly ["timeout", "spawn_error", "capture_overflow"]>;
27
+ export declare const ExecErrorCode: Schema.Literals<readonly ["timeout", "spawn_error", "arguments_too_long", "capture_overflow"]>;
28
28
  /**
29
29
  * Failure codes a buffered execution can report.
30
30
  *
@@ -33,7 +33,7 @@ export declare const ExecErrorCode: Schema.Literals<readonly ["timeout", "spawn_
33
33
  */
34
34
  export type ExecErrorCode = typeof ExecErrorCode.Type;
35
35
  declare const ExecError_base: Schema.Class<ExecError, Schema.TaggedStruct<"@smthrs/std/ExecError", {
36
- readonly code: Schema.Literals<readonly ["timeout", "spawn_error", "capture_overflow"]>;
36
+ readonly code: Schema.Literals<readonly ["timeout", "spawn_error", "arguments_too_long", "capture_overflow"]>;
37
37
  readonly message: Schema.String;
38
38
  /** The limit a `timeout` ran past, in milliseconds. */
39
39
  readonly limitMillis: Schema.optional<Schema.Number>;
@@ -42,8 +42,10 @@ declare const ExecError_base: Schema.Class<ExecError, Schema.TaggedStruct<"@smth
42
42
  * A command that never produced an exit code.
43
43
  *
44
44
  * A non-zero exit is a successful {@link ExecResult}, not a failure; this
45
- * error is reserved for a command that could not start or was cut off by its
46
- * timeout, or whose captured output exceeded a refusing capture bound.
45
+ * error is reserved for a command that could not start (`arguments_too_long`
46
+ * when the operating system refused it for the size of its arguments) or was
47
+ * cut off by its timeout, or whose captured output exceeded a refusing capture
48
+ * bound.
47
49
  *
48
50
  * @category errors
49
51
  * @since 1.0.0
@@ -125,7 +127,9 @@ export declare const exec: (command: string, options?: ExecOptions) => Effect.Ef
125
127
  *
126
128
  * A timeout keeps its own code, because "the command never finished" and "the
127
129
  * command never started" are different things to a caller deciding whether to
128
- * retry. Every other way of producing no exit code is a host failure.
130
+ * retry. Arguments the operating system refused for their size are the
131
+ * caller's own input, which a shell flow publishes, so they read as
132
+ * `invalid_input`. Every other way of producing no exit code is a host failure.
129
133
  *
130
134
  * @category errors
131
135
  * @since 1.0.0
@@ -135,8 +139,9 @@ export declare const toStdErrorCode: (error: ExecError) => StdError.Code;
135
139
  * The model-facing failure one execution error becomes.
136
140
  *
137
141
  * A timeout names the command, which is what the caller asked for and all a
138
- * timeout has to say. Any other failure carries the message the execution
139
- * produced, which already names the command.
142
+ * timeout has to say. Arguments too long to start carry the reason and the
143
+ * fix, and nothing of the command. Any other failure carries the message the
144
+ * execution produced, which already names the command.
140
145
  *
141
146
  * @category errors
142
147
  * @since 1.0.0
@@ -1 +1 @@
1
- {"version":3,"file":"Exec.d.ts","sourceRoot":"","sources":["../../../src/internal/Exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,mBAAmB,MAAM,oCAAoC,CAAA;AACzE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAG1C;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,0EAAkE,CAAA;AAE5F;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAA;;;;IAenD,uDAAuD;;;AAbzD;;;;;;;;;GASG;AACH,qBAAa,SAAU,SAAQ,cAK7B;CAAG;AAEL;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,sFAAsF;IACtF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;IACnC,sFAAsF;IACtF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;CACpC;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC;;;;;;;;OAQG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CACzC;AAED,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;AA0N1C;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,GACf,SAAS,MAAM,EACf,UAAS,WAAgB,KACxB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,mBAAmB,CAAC,mBAAmB,CAazE,CAAA;AAEN;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,SAAS,KAAG,QAAQ,CAAC,IACF,CAAA;AAEzD;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,OAAO,SAAS,KAAG,QAAQ,CAAC,QAOpE,CAAA"}
1
+ {"version":3,"file":"Exec.d.ts","sourceRoot":"","sources":["../../../src/internal/Exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,mBAAmB,MAAM,oCAAoC,CAAA;AACzE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAG1C;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,gGAAwF,CAAA;AAElH;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAA;;;;IAiBnD,uDAAuD;;;AAfzD;;;;;;;;;;;GAWG;AACH,qBAAa,SAAU,SAAQ,cAK7B;CAAG;AAEL;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,sFAAsF;IACtF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;IACnC,sFAAsF;IACtF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;CACpC;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC;;;;;;;;OAQG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CACzC;AAED,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;AA2O1C;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,GACf,SAAS,MAAM,EACf,UAAS,WAAgB,KACxB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,mBAAmB,CAAC,mBAAmB,CAazE,CAAA;AAEN;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,SAAS,KAAG,QAAQ,CAAC,IACsD,CAAA;AAEjH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,OAAO,SAAS,KAAG,QAAQ,CAAC,QASpE,CAAA"}