@molecule/api-ai-tools 1.13.1 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-10-22T07:11:20.054Z
6
+ Generated: 2026-10-23T00:59:47.543Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-ai-tools
@@ -140,6 +140,13 @@ still names the deployed host (xr-molecule-flash-m103 +28:08).
140
140
 
141
141
  ```typescript
142
142
  interface LocatedCommandSegment {
143
+ /**
144
+ * Directory-scope ancestry supplied by the existing shell parse, outermost first.
145
+ * Parenthesized groups and nested `sh -c` strings have their own shell directory;
146
+ * braces share their parent's. Identities are opaque and local to this invocation.
147
+ * Absent for ordinary statements in the outer shell, preserving their existing shape.
148
+ */
149
+ shellScope?: readonly string[]
143
150
  /**
144
151
  * What the statement runs, or null when it only sets variables (`BASE=http://…` on its own):
145
152
  * that shape persists in the shell, so a caller following assignments across `;`/`&&` has to
@@ -148,6 +155,13 @@ interface LocatedCommandSegment {
148
155
  segment: CommandSegment | null
149
156
  /** The statement's own leading `NAME=value` words, as written (`TEST_MODE=fullstack`). */
150
157
  assignments: readonly string[]
158
+ /**
159
+ * Assignments whose values expand at this source statement, when different from
160
+ * inherited environment bindings. A nested `sh -c` carries outer bindings into
161
+ * every entry, but expands its caller's assignment values only before its first
162
+ * command. Absent when the ordinary `assignments` list is also the source list.
163
+ */
164
+ sourceAssignments?: readonly string[]
151
165
  /**
152
166
  * The offset in the command of the statement's first word, or null for a segment inside a
153
167
  * nested `sh -c '<command>'` string — its positions are offsets in THAT string, not in this
@@ -1491,6 +1505,19 @@ interface SuiteRunPipelinePlacement {
1491
1505
  }
1492
1506
  ```
1493
1507
 
1508
+ #### `RunningLogRead`
1509
+
1510
+ A bounded, contiguous read of a running task's own log.
1511
+
1512
+ ```typescript
1513
+ interface RunningLogRead {
1514
+ /** The log's last {@link RUNNING_LOG_READ_BYTES} bytes, contiguous, as one string. */
1515
+ text: string
1516
+ /** How many bytes the WHOLE log holds, or null when the read did not answer its size. */
1517
+ bytes: number | null
1518
+ }
1519
+ ```
1520
+
1494
1521
  #### `FailedTest`
1495
1522
 
1496
1523
  One failed test, as a running suite's log names it.
@@ -1845,6 +1872,23 @@ function commandSegments(command: string): CommandSegment[]
1845
1872
 
1846
1873
  **Returns:** One entry per statement or pipeline stage that runs something, in order.
1847
1874
 
1875
+ #### `commandSubstitutions(command)`
1876
+
1877
+ The direct executable command-substitution bodies in shell text, in source order.
1878
+
1879
+ Uses the same quote, comment and heredoc boundaries as {@link executedCommands}.
1880
+ Single-quoted and escaped text is inert. Nested substitutions stay inside their
1881
+ parent's body so a caller can recurse with a separate working-directory scope
1882
+ for each body; a `cd` inside one must not affect its sibling or the outer shell.
1883
+
1884
+ ```typescript
1885
+ function commandSubstitutions(command: string): string[]
1886
+ ```
1887
+
1888
+ - `command` — The shell text to read, including any leading assignments.
1889
+
1890
+ **Returns:** Each direct `$(…)` or backtick body, without its delimiters.
1891
+
1848
1892
  #### `executedCommands(command)`
1849
1893
 
1850
1894
  Every command a shell command actually executes, at any depth — the statements themselves, the
@@ -2691,7 +2735,9 @@ positional selection the run carried (a spec file, a suite directory or a regex
2691
2735
  The re-run keeps the run's `> <file>` redirect only in the sense of keeping its OUTPUT there:
2692
2736
  the target is rewritten to a fresh sibling ({@link redirectRunnerOutputsToFreshFiles}), so a
2693
2737
  re-run never overwrites the log the run itself is the evidence for (xr-molecule-flash-m173) —
2694
- and the setup around the run keeps its own file writes untouched (xr-molecule-flash-m429).
2738
+ and the setup around the run keeps its own file writes untouched (xr-molecule-flash-m429). A
2739
+ `tail`/`head`/`cat`/`grep` chained after the run that reads that exact log is shown the fresh
2740
+ sibling instead, so the re-run displays the run it performed (xr-molecule-flash-o03).
2695
2741
 
2696
2742
  `config` is the config the run was measured under ({@link withSuiteConfig}): the narrowed re-run
2697
2743
  carries it whenever the command itself does not, so a run that dropped `--config` cannot be
@@ -2890,6 +2936,26 @@ function moleculeDistReadNote(path: string): string | null
2890
2936
 
2891
2937
  **Returns:** The note, or null when the path is not inside a package's `dist`.
2892
2938
 
2939
+ #### `registeredTaskLogCommand(taskId)`
2940
+
2941
+ The command that reads a REGISTERED background task's own log as one bounded contiguous window
2942
+ ({@link runningLogReadCommand}), with the file its launch redirects to when the launch recorded
2943
+ one.
2944
+
2945
+ The task id is the ownership: it is the handle `wait_for_task` returned, `/tmp/${taskId}.log` is
2946
+ the log this platform's launcher writes for it, and the redirect target is the file this
2947
+ process's own launch registered for that id — never a path parsed out of a command by the
2948
+ caller. A diagnosis that reads a running walk must not build a `/tmp` path of its own
2949
+ (xr-molecule-flash-l07: the wait's DISPLAY was diagnosed as if it were the log).
2950
+
2951
+ ```typescript
2952
+ function registeredTaskLogCommand(taskId: string): string | null
2953
+ ```
2954
+
2955
+ - `taskId` — The `mol-bg-…` handle the wait returned.
2956
+
2957
+ **Returns:** The read command, or null when the handle is not a task id this platform minted.
2958
+
2893
2959
  #### `shellInstalledPackageProbe(run)`
2894
2960
 
2895
2961
  Build an {@link InstalledPackageProbe} from a shell runner (a backend's
@@ -4213,6 +4279,42 @@ function runningCauseCommand(log: string, own?: string): string
4213
4279
 
4214
4280
  **Returns:** The shell command, safe to hand to the execution backend as-is.
4215
4281
 
4282
+ #### `runningLogReadCommand(log, own)`
4283
+
4284
+ The shell command whose stdout is a bounded CONTIGUOUS read of a running task's own log: the
4285
+ log's byte size, then its last {@link RUNNING_LOG_READ_BYTES} bytes.
4286
+
4287
+ {@link runningOutputSliceCommand} is the wrong read for a diagnosis, and l07 is the finding: it
4288
+ stitches the first 40 grep-selected failure lines to the last 1 000 bytes with a blank line
4289
+ between, so the tail is DISJOINT from the headers above it. Read as one log, the last numbered
4290
+ header absorbs whatever the tail starts with — a clipped skipped-test title became the cause of
4291
+ a genuine failure (xr-molecule-flash-l07). A contiguous window can only ever hold real
4292
+ neighbouring lines of one log.
4293
+
4294
+ The size rides along so a caller can say when the window is only the log's end
4295
+ ({@link parseRunningLogRead}); without it a tail reads as the whole run.
4296
+
4297
+ ```typescript
4298
+ function runningLogReadCommand(log: string, own?: string): string
4299
+ ```
4300
+
4301
+ - `log` — The task log path.
4302
+ - `own` — A file the command redirects its own output to, if any.
4303
+
4304
+ **Returns:** The shell command, safe to hand to the execution backend as-is.
4305
+
4306
+ #### `parseRunningLogRead(stdout)`
4307
+
4308
+ The two parts of {@link runningLogReadCommand}'s answer.
4309
+
4310
+ ```typescript
4311
+ function parseRunningLogRead(stdout: string): RunningLogRead | null
4312
+ ```
4313
+
4314
+ - `stdout` — The command's stdout.
4315
+
4316
+ **Returns:** The window and the whole log's byte size, or null when the size line is absent (the read did not run, so nothing may be said about the log).
4317
+
4216
4318
  #### `repeatingFailure(log)`
4217
4319
 
4218
4320
  The cause repeating among a running suite's failures, or null.
@@ -5185,6 +5287,14 @@ Bytes of a running log a repeating-cause look reads back.
5185
5287
  const REPEATING_CAUSE_TAIL_BYTES: 40000
5186
5288
  ```
5187
5289
 
5290
+ #### `RUNNING_LOG_READ_BYTES`
5291
+
5292
+ Bytes of a running log a diagnostic note reads back: one {@link REPEATING_CAUSE_TAIL_BYTES} window.
5293
+
5294
+ ```typescript
5295
+ const RUNNING_LOG_READ_BYTES: 40000
5296
+ ```
5297
+
5188
5298
  #### `REPEATING_FAILURE_MIN`
5189
5299
 
5190
5300
  DISTINCT tests that must share one signature before a running suite's repeating cause is named.
@@ -90,6 +90,18 @@ export interface ExecutedCommand {
90
90
  /** The program and its arguments as one line, what a pattern anchored at the program matches. */
91
91
  text: string;
92
92
  }
93
+ /**
94
+ * The direct executable command-substitution bodies in shell text, in source order.
95
+ *
96
+ * Uses the same quote, comment and heredoc boundaries as {@link executedCommands}.
97
+ * Single-quoted and escaped text is inert. Nested substitutions stay inside their
98
+ * parent's body so a caller can recurse with a separate working-directory scope
99
+ * for each body; a `cd` inside one must not affect its sibling or the outer shell.
100
+ *
101
+ * @param command - The shell text to read, including any leading assignments.
102
+ * @returns Each direct `$(…)` or backtick body, without its delimiters.
103
+ */
104
+ export declare function commandSubstitutions(command: string): string[];
93
105
  /**
94
106
  * Every command a shell command actually executes, at any depth — the statements themselves, the
95
107
  * body of a `sh -c '<command>'`, and the body of every command substitution (`$(…)`, backticks).
@@ -122,6 +134,13 @@ export declare function executedCommands(command: string): ExecutedCommand[];
122
134
  * still names the deployed host (xr-molecule-flash-m103 +28:08).
123
135
  */
124
136
  export interface LocatedCommandSegment {
137
+ /**
138
+ * Directory-scope ancestry supplied by the existing shell parse, outermost first.
139
+ * Parenthesized groups and nested `sh -c` strings have their own shell directory;
140
+ * braces share their parent's. Identities are opaque and local to this invocation.
141
+ * Absent for ordinary statements in the outer shell, preserving their existing shape.
142
+ */
143
+ shellScope?: readonly string[];
125
144
  /**
126
145
  * What the statement runs, or null when it only sets variables (`BASE=http://…` on its own):
127
146
  * that shape persists in the shell, so a caller following assignments across `;`/`&&` has to
@@ -130,6 +149,13 @@ export interface LocatedCommandSegment {
130
149
  segment: CommandSegment | null;
131
150
  /** The statement's own leading `NAME=value` words, as written (`TEST_MODE=fullstack`). */
132
151
  assignments: readonly string[];
152
+ /**
153
+ * Assignments whose values expand at this source statement, when different from
154
+ * inherited environment bindings. A nested `sh -c` carries outer bindings into
155
+ * every entry, but expands its caller's assignment values only before its first
156
+ * command. Absent when the ordinary `assignments` list is also the source list.
157
+ */
158
+ sourceAssignments?: readonly string[];
133
159
  /**
134
160
  * The offset in the command of the statement's first word, or null for a segment inside a
135
161
  * nested `sh -c '<command>'` string — its positions are offsets in THAT string, not in this
@@ -1 +1 @@
1
- {"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"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"}
@@ -32,10 +32,246 @@
32
32
  *
33
33
  * @module
34
34
  */
35
- /** A command's words, quotes kept whole — the same reading a printed-source check uses. */
36
- const WORD = /"(?:\\.|[^"\\])*"|'[^']*'|\S+/g;
37
35
  /** Shell words that stand alone: grouping, never an argument. */
38
36
  const GROUPING = new Set(['(', ')', '{', '}']);
37
+ /** The index just past a single-quoted string that starts at `at` (its opening quote). */
38
+ function singleQuotedEnd(text, at) {
39
+ const close = text.indexOf("'", at + 1);
40
+ return close === -1 ? text.length : close + 1;
41
+ }
42
+ /**
43
+ * The index just past a double-quoted string that starts at `at`. A command substitution or a
44
+ * backtick inside it is skipped as a unit, because a `"` inside one belongs to the nested command,
45
+ * not to this string (`DIR="$(cd "$(dirname "$0")" && pwd)"`).
46
+ */
47
+ function doubleQuotedEnd(text, at) {
48
+ let i = at + 1;
49
+ while (i < text.length) {
50
+ const char = text[i] ?? '';
51
+ if (char === '\\') {
52
+ i += 2;
53
+ continue;
54
+ }
55
+ if (char === '"')
56
+ return i + 1;
57
+ if (char === '`') {
58
+ i = backtickEnd(text, i);
59
+ continue;
60
+ }
61
+ if (char === '$' && text[i + 1] === '(') {
62
+ i = substitutionEnd(text, i + 2);
63
+ continue;
64
+ }
65
+ if (char === '$' && text[i + 1] === '{') {
66
+ i = parameterEnd(text, i + 2);
67
+ continue;
68
+ }
69
+ i += 1;
70
+ }
71
+ return text.length;
72
+ }
73
+ /** The index just past a backtick substitution that starts at `at` (`\`` is literal, not a close). */
74
+ function backtickEnd(text, at) {
75
+ let i = at + 1;
76
+ while (i < text.length) {
77
+ if (text[i] === '\\') {
78
+ i += 2;
79
+ continue;
80
+ }
81
+ if (text[i] === '`')
82
+ return i + 1;
83
+ i += 1;
84
+ }
85
+ return text.length;
86
+ }
87
+ /**
88
+ * The index just past a `$( … )` command substitution whose body starts at `at`. The body is NOT
89
+ * evaluated and its whitespace splits nothing: only its closing `)` is looked for, through quotes,
90
+ * escapes and nested substitutions. An unclosed substitution runs to the end of the text.
91
+ */
92
+ function substitutionEnd(text, at) {
93
+ let depth = 1;
94
+ let i = at;
95
+ while (i < text.length) {
96
+ const char = text[i] ?? '';
97
+ // A `#` in the nested command starts a comment, so a `$(` or `)` inside it is data — the same
98
+ // reading `splitCommand` makes (`$(printf x # $(` opens nothing).
99
+ if (char === '#' && commentStartsAt(text, i)) {
100
+ const newline = text.indexOf('\n', i);
101
+ i = newline === -1 ? text.length : newline;
102
+ continue;
103
+ }
104
+ if (char === '\\') {
105
+ i += 2;
106
+ continue;
107
+ }
108
+ if (char === "'") {
109
+ i = singleQuotedEnd(text, i);
110
+ continue;
111
+ }
112
+ if (char === '"') {
113
+ i = doubleQuotedEnd(text, i);
114
+ continue;
115
+ }
116
+ if (char === '`') {
117
+ i = backtickEnd(text, i);
118
+ continue;
119
+ }
120
+ if (char === '$' && text[i + 1] === '(') {
121
+ i = substitutionEnd(text, i + 2);
122
+ continue;
123
+ }
124
+ if (char === '$' && text[i + 1] === '{') {
125
+ i = parameterEnd(text, i + 2);
126
+ continue;
127
+ }
128
+ if (char === '(')
129
+ depth += 1;
130
+ else if (char === ')') {
131
+ depth -= 1;
132
+ if (depth === 0)
133
+ return i + 1;
134
+ }
135
+ i += 1;
136
+ }
137
+ return text.length;
138
+ }
139
+ /** The index just past a `${ … }` parameter expansion whose body starts at `at`. */
140
+ function parameterEnd(text, at) {
141
+ let depth = 1;
142
+ let i = at;
143
+ while (i < text.length) {
144
+ const char = text[i] ?? '';
145
+ if (char === '\\') {
146
+ i += 2;
147
+ continue;
148
+ }
149
+ if (char === "'") {
150
+ i = singleQuotedEnd(text, i);
151
+ continue;
152
+ }
153
+ if (char === '"') {
154
+ i = doubleQuotedEnd(text, i);
155
+ continue;
156
+ }
157
+ if (char === '`') {
158
+ i = backtickEnd(text, i);
159
+ continue;
160
+ }
161
+ if (char === '$' && text[i + 1] === '(') {
162
+ i = substitutionEnd(text, i + 2);
163
+ continue;
164
+ }
165
+ if (char === '$' && text[i + 1] === '{') {
166
+ depth += 1;
167
+ i += 2;
168
+ continue;
169
+ }
170
+ if (char === '}') {
171
+ depth -= 1;
172
+ if (depth === 0)
173
+ return i + 1;
174
+ }
175
+ i += 1;
176
+ }
177
+ return text.length;
178
+ }
179
+ /**
180
+ * The index just past the shell word that starts at `at` (a non-whitespace character): a word ends
181
+ * at unquoted whitespace, and every quoted part, command substitution (`$( … )`, backticks),
182
+ * parameter expansion (`${ … }`) and process substitution (`<( … )`) inside it is skipped as a
183
+ * unit — so the spaces in `UID_VAL=h$(date +%s)` belong to that one word.
184
+ *
185
+ * Nothing is evaluated or expanded: this finds word BOUNDARIES only, and returns the text as
186
+ * written. A backslash-newline is a line continuation, so it ends the word and is skipped.
187
+ */
188
+ function shellWordEnd(text, at) {
189
+ let i = at;
190
+ while (i < text.length) {
191
+ const char = text[i] ?? '';
192
+ if (/\s/.test(char))
193
+ break;
194
+ // Grouping punctuation is a shell operator, never part of the word beside it (`tail -25)`,
195
+ // `(npx …`), so a caller can step over the closer the way it always has.
196
+ if (GROUPING.has(char))
197
+ break;
198
+ if (char === '\\') {
199
+ if (text[i + 1] === '\n')
200
+ break;
201
+ i += 2;
202
+ continue;
203
+ }
204
+ if (char === "'") {
205
+ i = singleQuotedEnd(text, i);
206
+ continue;
207
+ }
208
+ if (char === '"') {
209
+ i = doubleQuotedEnd(text, i);
210
+ continue;
211
+ }
212
+ if (char === '`') {
213
+ i = backtickEnd(text, i);
214
+ continue;
215
+ }
216
+ if (char === '$' && text[i + 1] === '(') {
217
+ i = substitutionEnd(text, i + 2);
218
+ continue;
219
+ }
220
+ if (char === '$' && text[i + 1] === '{') {
221
+ i = parameterEnd(text, i + 2);
222
+ continue;
223
+ }
224
+ if ((char === '<' || char === '>') && text[i + 1] === '(') {
225
+ i = substitutionEnd(text, i + 2);
226
+ continue;
227
+ }
228
+ i += 1;
229
+ }
230
+ return i;
231
+ }
232
+ /** One text's shell words, quotes kept, grouping punctuation still its own word. */
233
+ function shellWordSpans(text) {
234
+ const words = [];
235
+ let i = 0;
236
+ while (i < text.length) {
237
+ const char = text[i] ?? '';
238
+ if (char === '\\' && text[i + 1] === '\n') {
239
+ i += 2;
240
+ continue;
241
+ }
242
+ if (/\s/.test(char)) {
243
+ i += 1;
244
+ continue;
245
+ }
246
+ if (GROUPING.has(char)) {
247
+ words.push({ text: char, start: i });
248
+ i += 1;
249
+ continue;
250
+ }
251
+ const end = shellWordEnd(text, i);
252
+ words.push({ text: text.slice(i, end), start: i });
253
+ i = end;
254
+ }
255
+ return words;
256
+ }
257
+ /**
258
+ * The words {@link segmentWords} keeps, with the offset each was written at: quotes kept whole,
259
+ * grouping words dropped, and a leading `(`/`{` taken off the first word. One walk answers both
260
+ * readings, so a caller splicing text at a word's offset and a caller matching that word can
261
+ * never disagree.
262
+ */
263
+ function segmentWordSpans(text) {
264
+ const words = shellWordSpans(text).filter((word) => !GROUPING.has(word.text));
265
+ const first = words[0];
266
+ if (first !== undefined) {
267
+ const bare = first.text.replace(/^[({]+/, '');
268
+ if (bare === '')
269
+ words.shift();
270
+ else if (bare !== first.text)
271
+ words[0] = { text: bare, start: first.start + (first.text.length - bare.length) };
272
+ }
273
+ return words;
274
+ }
39
275
  /**
40
276
  * A redirection written as ONE word, its target attached: `2>&1`, `>out.log`, `&>/dev/null`,
41
277
  * `<<'EOF'`. Matched against a word of the statement, so a redirect's target written as its own
@@ -707,6 +943,8 @@ function splitCommand(command) {
707
943
  const source = blankHeredocBodies(command);
708
944
  const parts = [];
709
945
  const substitutions = [];
946
+ const subshells = [];
947
+ const subshellOpens = [];
710
948
  /** Where each open `$(` body starts; -1 for a bare `(` opened inside one. */
711
949
  const subOpens = [];
712
950
  /** Where each open backtick body starts. */
@@ -855,11 +1093,18 @@ function splitCommand(command) {
855
1093
  // `{ … }` writes through that group, so the depth travels with every character a caller
856
1094
  // reading a redirect may ask about.
857
1095
  if (char === '(' || char === '{') {
1096
+ if (char === '(')
1097
+ subshellOpens.push(i + 1);
858
1098
  put(char);
859
1099
  groupDepth += 1;
860
1100
  continue;
861
1101
  }
862
1102
  if (char === ')' || char === '}') {
1103
+ if (char === ')') {
1104
+ const start = subshellOpens.pop();
1105
+ if (start !== undefined)
1106
+ subshells.push({ start, end: i });
1107
+ }
863
1108
  groupDepth = Math.max(0, groupDepth - 1);
864
1109
  put(char);
865
1110
  continue;
@@ -903,7 +1148,9 @@ function splitCommand(command) {
903
1148
  });
904
1149
  lastAfter = part.after;
905
1150
  }
906
- return { parts: out, substitutions };
1151
+ for (const start of subshellOpens)
1152
+ subshells.push({ start, end: source.length });
1153
+ return { parts: out, substitutions, subshells };
907
1154
  }
908
1155
  /**
909
1156
  * A command's statements and pipeline stages — {@link splitCommand}'s parts on their own.
@@ -980,20 +1227,8 @@ function redirectTargetOf(text, depths, program, args) {
980
1227
  * @returns The words.
981
1228
  */
982
1229
  function segmentWords(text) {
983
- const words = text.match(WORD) ?? [];
984
- const cleaned = words.filter((word) => !GROUPING.has(word));
985
- const first = cleaned[0];
986
- if (first !== undefined) {
987
- const bare = first.replace(/^[({]+/, '');
988
- if (bare === '')
989
- cleaned.shift();
990
- else
991
- cleaned[0] = bare;
992
- }
993
- return cleaned;
1230
+ return segmentWordSpans(text).map((word) => word.text);
994
1231
  }
995
- /** {@link WORD} anchored at an offset, for walking a statement's raw words. */
996
- const WORD_AT = new RegExp(WORD.source, 'y');
997
1232
  /**
998
1233
  * A statement's own leading `NAME=value` words, and where they end.
999
1234
  *
@@ -1008,19 +1243,25 @@ function leadingAssignments(text) {
1008
1243
  const words = [];
1009
1244
  let at = 0;
1010
1245
  for (let guard = 0; guard < MAX_WRAPPERS; guard++) {
1011
- while (at < text.length && /\s/.test(text[at] ?? ''))
1246
+ while (at < text.length) {
1247
+ if (text[at] === '\\' && text[at + 1] === '\n') {
1248
+ at += 2;
1249
+ continue;
1250
+ }
1251
+ if (!/\s/.test(text[at] ?? ''))
1252
+ break;
1012
1253
  at += 1;
1254
+ }
1013
1255
  // Grouping in front of the statement (`(npx …)`, `{ …`): not a word the shell assigns with.
1014
1256
  if (text[at] === '(' || text[at] === '{') {
1015
1257
  at += 1;
1016
1258
  continue;
1017
1259
  }
1018
- WORD_AT.lastIndex = at;
1019
- const match = WORD_AT.exec(text);
1020
- if (!match || !ENV_ASSIGNMENT.test(match[0]))
1260
+ const word = text.slice(at, shellWordEnd(text, at));
1261
+ if (!ENV_ASSIGNMENT.test(word))
1021
1262
  return { words, end: at };
1022
- words.push(match[0]);
1023
- at += match[0].length;
1263
+ words.push(word);
1264
+ at += word.length;
1024
1265
  }
1025
1266
  return { words, end: at };
1026
1267
  }
@@ -1117,6 +1358,31 @@ function executedCommandsOf(command, depth) {
1117
1358
  }
1118
1359
  return out;
1119
1360
  }
1361
+ /**
1362
+ * The direct executable command-substitution bodies in shell text, in source order.
1363
+ *
1364
+ * Uses the same quote, comment and heredoc boundaries as {@link executedCommands}.
1365
+ * Single-quoted and escaped text is inert. Nested substitutions stay inside their
1366
+ * parent's body so a caller can recurse with a separate working-directory scope
1367
+ * for each body; a `cd` inside one must not affect its sibling or the outer shell.
1368
+ *
1369
+ * @param command - The shell text to read, including any leading assignments.
1370
+ * @returns Each direct `$(…)` or backtick body, without its delimiters.
1371
+ */
1372
+ export function commandSubstitutions(command) {
1373
+ if (typeof command !== 'string' || !command.trim())
1374
+ return [];
1375
+ const { substitutions } = splitCommand(command);
1376
+ const bodies = [];
1377
+ let parentEnd = -1;
1378
+ for (const { start, end } of substitutions.sort((a, b) => a.start - b.start || b.end - a.end)) {
1379
+ if (start < parentEnd)
1380
+ continue;
1381
+ bodies.push(command.slice(start, end));
1382
+ parentEnd = end;
1383
+ }
1384
+ return bodies;
1385
+ }
1120
1386
  /**
1121
1387
  * Every command a shell command actually executes, at any depth — the statements themselves, the
1122
1388
  * body of a `sh -c '<command>'`, and the body of every command substitution (`$(…)`, backticks).
@@ -1154,29 +1420,7 @@ export function executedCommands(command) {
1154
1420
  * @returns The word's offset in `text`, or null when there is no such word.
1155
1421
  */
1156
1422
  function wordOffset(text, index) {
1157
- const placement = new RegExp(WORD.source, 'g');
1158
- let kept = 0;
1159
- let first = true;
1160
- for (let match = placement.exec(text); match !== null; match = placement.exec(text)) {
1161
- if (GROUPING.has(match[0]))
1162
- continue;
1163
- if (first) {
1164
- first = false;
1165
- const bare = match[0].replace(/^[({]+/, '');
1166
- // `segmentWords` shifts a first word that was nothing but grouping away, so the NEXT word
1167
- // is not stripped and is counted from zero.
1168
- if (bare === '')
1169
- continue;
1170
- if (kept === index)
1171
- return match.index + (match[0].length - bare.length);
1172
- kept += 1;
1173
- continue;
1174
- }
1175
- if (kept === index)
1176
- return match.index;
1177
- kept += 1;
1178
- }
1179
- return null;
1423
+ return segmentWordSpans(text)[index]?.start ?? null;
1180
1424
  }
1181
1425
  /**
1182
1426
  * Every statement of a command, with its own assignments and where it sits — assignment-only
@@ -1289,9 +1533,9 @@ export function statementArgumentEnd(command, start, end) {
1289
1533
  }
1290
1534
  at = cursor - 1;
1291
1535
  }
1292
- const words = [...command.slice(start, at).matchAll(new RegExp(WORD.source, 'g'))].map((m) => ({
1293
- text: m[0],
1294
- index: start + (m.index ?? 0),
1536
+ const words = shellWordSpans(command.slice(start, at)).map((word) => ({
1537
+ text: word.text,
1538
+ index: start + word.start,
1295
1539
  }));
1296
1540
  // A trailing redirection belongs to the statement but is not an argument of its program. An
1297
1541
  // option written after it would still parse, but the option belongs with the program's own
@@ -1404,7 +1648,8 @@ function locatedSegmentsOf(command, depth) {
1404
1648
  if (typeof command !== 'string' || depth > MAX_NESTING)
1405
1649
  return [];
1406
1650
  const out = [];
1407
- for (const part of splitSegments(command)) {
1651
+ const { parts, subshells } = splitCommand(command);
1652
+ for (const part of parts) {
1408
1653
  const words = segmentWords(part.text);
1409
1654
  const start = commandStart(words);
1410
1655
  const leading = leadingAssignments(part.text);
@@ -1428,6 +1673,12 @@ function locatedSegmentsOf(command, depth) {
1428
1673
  : part.start + (wordOffset(part.text, start.envInsert) ?? leading.end),
1429
1674
  programOffset: words[start.at] === undefined ? null : part.start + (wordOffset(part.text, start.at) ?? 0),
1430
1675
  };
1676
+ const scopeAt = placed.programOffset ?? part.start + (wordOffset(part.text, 0) ?? 0);
1677
+ const shellScope = subshells
1678
+ .filter(({ start, end }) => start <= scopeAt && scopeAt < end)
1679
+ .sort((a, b) => a.start - b.start)
1680
+ .map(({ start }) => `group:${start}`);
1681
+ const scoped = shellScope.length === 0 ? {} : { shellScope };
1431
1682
  // The runner the word RUNS names, when that is not the word's own name (`node <path>/playwright`
1432
1683
  // is a `playwright` invocation, xr-molecule-flash-m179).
1433
1684
  const program = words[start.at] === undefined ? '' : (start.program ?? programName(words[start.at] ?? ''));
@@ -1441,9 +1692,14 @@ function locatedSegmentsOf(command, depth) {
1441
1692
  continue;
1442
1693
  out.push({
1443
1694
  ...entry,
1695
+ shellScope: [...shellScope, `shell:${part.start}`, ...(entry.shellScope ?? [])],
1444
1696
  // The variables this statement bound before the shell reached it are the nested
1445
1697
  // command's too: `env BASE_URL=… sh -c '… npx playwright test …'` passes them down.
1446
1698
  assignments: [...new Set([...assignments, ...entry.assignments])],
1699
+ sourceAssignments: [
1700
+ ...(i === 0 ? assignments : []),
1701
+ ...(entry.sourceAssignments ?? entry.assignments),
1702
+ ],
1447
1703
  // A nested statement's positions are positions in the nested string, not in this
1448
1704
  // command. The FIRST one keeps this statement's own separator: the shell reads the
1449
1705
  // nested string where this statement stands.
@@ -1469,6 +1725,7 @@ function locatedSegmentsOf(command, depth) {
1469
1725
  if (assignments.length > 0)
1470
1726
  out.push({
1471
1727
  segment: null,
1728
+ ...scoped,
1472
1729
  assignments,
1473
1730
  ...placed,
1474
1731
  programOffset: null,
@@ -1479,6 +1736,7 @@ function locatedSegmentsOf(command, depth) {
1479
1736
  continue;
1480
1737
  }
1481
1738
  out.push({
1739
+ ...scoped,
1482
1740
  segment: {
1483
1741
  program,
1484
1742
  args,
@@ -1554,16 +1812,13 @@ export function withoutTimeoutWrapper(command, which) {
1554
1812
  continue;
1555
1813
  // Every word in front of the program: the assignments and the wrappers. The duration belongs
1556
1814
  // to the wrapper, so the walk has to see the words, not just the parse's total bound.
1557
- const prefix = command.slice(located.start, located.programOffset);
1558
- const words = [];
1559
- const at = new RegExp(WORD.source, 'g');
1560
- for (let match = at.exec(prefix); match !== null; match = at.exec(prefix)) {
1561
- words.push({
1562
- text: match[0],
1563
- start: located.start + match.index,
1564
- end: located.start + match.index + match[0].length,
1565
- });
1566
- }
1815
+ const start = located.start;
1816
+ const prefix = command.slice(start, located.programOffset);
1817
+ const words = shellWordSpans(prefix).map((word) => ({
1818
+ text: word.text,
1819
+ start: start + word.start,
1820
+ end: start + word.start + word.text.length,
1821
+ }));
1567
1822
  for (let i = 0; i < words.length; i += 1) {
1568
1823
  const word = words[i];
1569
1824
  if (word === undefined || programName(word.text) !== 'timeout')
@@ -87,7 +87,9 @@ export declare function withSuiteConfig(command: string, config: string | null |
87
87
  * The re-run keeps the run's `> <file>` redirect only in the sense of keeping its OUTPUT there:
88
88
  * the target is rewritten to a fresh sibling ({@link redirectRunnerOutputsToFreshFiles}), so a
89
89
  * re-run never overwrites the log the run itself is the evidence for (xr-molecule-flash-m173) —
90
- * and the setup around the run keeps its own file writes untouched (xr-molecule-flash-m429).
90
+ * and the setup around the run keeps its own file writes untouched (xr-molecule-flash-m429). A
91
+ * `tail`/`head`/`cat`/`grep` chained after the run that reads that exact log is shown the fresh
92
+ * sibling instead, so the re-run displays the run it performed (xr-molecule-flash-o03).
91
93
  *
92
94
  * `config` is the config the run was measured under ({@link withSuiteConfig}): the narrowed re-run
93
95
  * carries it whenever the command itself does not, so a run that dropped `--config` cannot be
@@ -1 +1 @@
1
- {"version":3,"file":"suite-overlap.d.ts","sourceRoot":"","sources":["../src/suite-overlap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAaH;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAoB1D;AAKD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAS1F;AAoOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,QAAQ,GAAE,SAAS,MAAM,EAAO,EAChC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EACnB,GAAG,GAAE,SAAS,aAAa,EAAO,GACjC,MAAM,CAgDR;AAED,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAmCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,SAAS,aAAa,EAAO,GAAG,MAAM,CAe3F;AAwOD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+FAA+F;IAC/F,SAAS,EAAE,OAAO,CAAA;IAClB,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,EACzD,SAAS,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EAC7B,QAAQ,EAAE,SAAS,CAAC,EAAE,GACrB,CAAC,GAAG,IAAI,CAMV;AA2FD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACvC;AAmCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAYtF"}
1
+ {"version":3,"file":"suite-overlap.d.ts","sourceRoot":"","sources":["../src/suite-overlap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAaH;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAoB1D;AAKD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAS1F;AA4VD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,QAAQ,GAAE,SAAS,MAAM,EAAO,EAChC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EACnB,GAAG,GAAE,SAAS,aAAa,EAAO,GACjC,MAAM,CAgDR;AAED,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAmCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,SAAS,aAAa,EAAO,GAAG,MAAM,CAe3F;AAwOD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+FAA+F;IAC/F,SAAS,EAAE,OAAO,CAAA;IAClB,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,EACzD,SAAS,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EAC7B,QAAQ,EAAE,SAAS,CAAC,EAAE,GACrB,CAAC,GAAG,IAAI,CAMV;AA2FD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACvC;AAmCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAYtF"}
@@ -180,9 +180,10 @@ function applyTextEdits(command, edits) {
180
180
  * @param statement - The statement's text.
181
181
  * @param offset - The statement's offset in the command.
182
182
  * @param words - The command's word spans.
183
+ * @param fresh - The exact old file → fresh file mapping the edits make, filled in here.
183
184
  * @returns The edits, in statement order.
184
185
  */
185
- function freshRedirectEdits(statement, offset, words) {
186
+ function freshRedirectEdits(statement, offset, words, fresh) {
186
187
  const edits = [];
187
188
  for (const match of statement.matchAll(FILE_REDIRECT)) {
188
189
  const before = match[1] ?? '';
@@ -203,7 +204,9 @@ function freshRedirectEdits(statement, offset, words) {
203
204
  continue;
204
205
  const quote = single !== undefined || double !== undefined ? 1 : 0;
205
206
  const start = offset + (match.index ?? 0) + before.length + op.length + space.length + quote;
206
- edits.push({ start, end: start + target.length, text: `${target}.rerun.log` });
207
+ const rewritten = `${target}.rerun.log`;
208
+ fresh.set(target, rewritten);
209
+ edits.push({ start, end: start + target.length, text: rewritten });
207
210
  }
208
211
  return edits;
209
212
  }
@@ -217,9 +220,10 @@ function freshRedirectEdits(statement, offset, words) {
217
220
  *
218
221
  * @param statement - The stage's text.
219
222
  * @param offset - The stage's offset in the command.
223
+ * @param fresh - The exact old file → fresh file mapping the edits make, filled in here.
220
224
  * @returns The edits, in stage order.
221
225
  */
222
- function freshTeeEdits(statement, offset) {
226
+ function freshTeeEdits(statement, offset, fresh) {
223
227
  const words = [...statement.matchAll(ARGUMENT_WORD)].map((match) => ({
224
228
  text: match[0],
225
229
  start: offset + (match.index ?? 0),
@@ -233,10 +237,12 @@ function freshTeeEdits(statement, offset) {
233
237
  if (!bare || bare.startsWith('-') || DEVICE_TARGET.test(bare))
234
238
  continue;
235
239
  const quote = /^['"]/.test(word.text) ? 1 : 0;
240
+ const rewritten = `${bare}.rerun.log`;
241
+ fresh.set(bare, rewritten);
236
242
  edits.push({
237
243
  start: word.start + quote,
238
244
  end: word.start + word.text.length - quote,
239
- text: `${bare}.rerun.log`,
245
+ text: rewritten,
240
246
  });
241
247
  }
242
248
  return edits;
@@ -283,6 +289,113 @@ function runnerOutputStatements(command) {
283
289
  }
284
290
  return statements;
285
291
  }
292
+ /**
293
+ * Readers whose non-flag operands are ALL files: a display of the run's own report. Every one of
294
+ * them is read-only, so moving its operand with the file it reads cannot change what it does.
295
+ */
296
+ const FILE_READERS = new Set(['cat', 'head', 'tail']);
297
+ /**
298
+ * grep-family readers: their first non-flag operand is the pattern, and the words after it are the
299
+ * files they display — unless a `-e`/`-f` flag named the pattern already.
300
+ */
301
+ const GREP_READERS = new Set(['egrep', 'fgrep', 'grep']);
302
+ /** grep's pattern flags: the word after one is a pattern (or a pattern file), never a file. */
303
+ const GREP_PATTERN_FLAGS = new Set(['-e', '--regexp', '-f', '--file']);
304
+ /**
305
+ * The postlude statements that DISPLAY the run's own report, with the exact file that run wrote
306
+ * pointed at the fresh sibling the re-run writes instead.
307
+ *
308
+ * xr-molecule-flash-o03 (2026-10-22; the stale-READ arm m248 filed at +25:55): the recipe the
309
+ * platform handed the executor ended `> /tmp/e2e-local.log.rerun.log 2>&1; echo EXIT=$?; tail -80
310
+ * /tmp/e2e-local.log`. The writer moved to the fresh sibling and the trailing tail did not, so the
311
+ * narrowed re-run displayed the walk it was narrowed FROM — the builder followed that recipe at
312
+ * +19:16 and read the previous walk's failures as the result of the run it had just done.
313
+ *
314
+ * Only the EXACT file a runner statement (or its `tee`) wrote moves, and only in a statement AFTER
315
+ * the run: the setup in front of it keeps every byte (m429), and a read of any other file is left
316
+ * alone. The value is compared whole — `/tmp/full.log` never matches `/tmp/full.log.bak` — and
317
+ * inside shell quotes the operand's own quoting survives (`"/tmp/my walk.log"` stays quoted).
318
+ *
319
+ * The bound is deliberate: a display this reader set does not recognise (a `wc`, a path held in a
320
+ * variable, a path the command builds) is left exactly as written rather than guessed at. Those
321
+ * shapes are not the ones the platform emits, and rewriting a word by resemblance is how m429's
322
+ * setup redirect was corrupted.
323
+ *
324
+ * @param command - The composed command.
325
+ * @param statements - The statements carrying the run's own output.
326
+ * @param fresh - The exact old file → fresh file mapping the redirect edits made.
327
+ * @returns The edits, in statement order.
328
+ */
329
+ function freshReportReadEdits(command, statements, fresh) {
330
+ if (fresh.size === 0)
331
+ return [];
332
+ const after = Math.max(...statements.map((statement) => statement.end));
333
+ const edits = [];
334
+ for (const entry of locatedCommandSegments(command)) {
335
+ const segment = entry.segment;
336
+ const start = entry.start;
337
+ const end = entry.end;
338
+ const programOffset = entry.programOffset;
339
+ // Only a statement the parse placed and that runs AFTER the walk can display its report.
340
+ if (segment === null || start === null || end === null)
341
+ continue;
342
+ if (start < after || programOffset === null)
343
+ continue;
344
+ const allFiles = FILE_READERS.has(segment.program);
345
+ const grep = GREP_READERS.has(segment.program);
346
+ if (!allFiles && !grep)
347
+ continue;
348
+ const text = command.slice(start, end);
349
+ const words = [...text.matchAll(ARGUMENT_WORD)].map((match) => ({
350
+ text: match[0],
351
+ start: start + (match.index ?? 0),
352
+ }));
353
+ // The program word's own span, so the walk starts exactly where the parse says it does.
354
+ const program = words.findIndex((word) => word.start === programOffset);
355
+ if (program < 0)
356
+ continue;
357
+ /** grep still owes its pattern: the first bare operand is that pattern, not a file. */
358
+ let patternPending = grep;
359
+ for (let i = program + 1; i < words.length; i += 1) {
360
+ const word = words[i];
361
+ if (word === undefined)
362
+ break;
363
+ if (ARGUMENT_REDIRECT_OPERATOR.test(word.text)) {
364
+ // The operator's target is where the display WRITES, not a file it reads.
365
+ i += 1;
366
+ continue;
367
+ }
368
+ if (ARGUMENT_REDIRECT.test(word.text))
369
+ continue;
370
+ const flag = unquoted(word.text);
371
+ if (flag.startsWith('-') && flag !== '-') {
372
+ if (grep) {
373
+ if (GREP_PATTERN_FLAGS.has(flag)) {
374
+ patternPending = false;
375
+ i += 1;
376
+ }
377
+ else if (/^(?:--(?:regexp|file)=|-[ef].)/.test(flag))
378
+ patternPending = false;
379
+ }
380
+ continue;
381
+ }
382
+ if (patternPending) {
383
+ patternPending = false;
384
+ continue;
385
+ }
386
+ const to = fresh.get(unquoted(word.text));
387
+ if (to === undefined)
388
+ continue;
389
+ const quote = /^['"]/.test(word.text) ? 1 : 0;
390
+ edits.push({
391
+ start: word.start + quote,
392
+ end: word.start + word.text.length - quote,
393
+ text: to,
394
+ });
395
+ }
396
+ }
397
+ return edits;
398
+ }
286
399
  /**
287
400
  * The command with the SUITE RUN's own log files pointed at fresh siblings, and nothing else
288
401
  * changed.
@@ -302,6 +415,12 @@ function runnerOutputStatements(command) {
302
415
  * source asset it lays down are the same shape: their targets stay byte-for-byte, and so does
303
416
  * every statement chained after the run (`; echo EXIT $? > /tmp/done`).
304
417
  *
418
+ * Every statement chained after the run (`; echo EXIT $? > /tmp/done`) is postlude and keeps its
419
+ * own writes, but the DISPLAY of the run's report is part of the same run: a `tail`, `head`, `cat`
420
+ * or `grep` after the run that reads the exact file it wrote is pointed at the fresh sibling too
421
+ * ({@link freshReportReadEdits}), so a re-run shows its own output instead of the walk's
422
+ * (xr-molecule-flash-o03).
423
+ *
305
424
  * @param command - The composed command.
306
425
  * @returns The command whose suite-run redirects write to a fresh target.
307
426
  */
@@ -311,12 +430,14 @@ function redirectRunnerOutputsToFreshFiles(command) {
311
430
  return command;
312
431
  const words = wordSpans(command);
313
432
  const edits = [];
433
+ const fresh = new Map();
314
434
  for (const statement of statements) {
315
435
  const text = command.slice(statement.start, statement.end);
316
- edits.push(...freshRedirectEdits(text, statement.start, words));
436
+ edits.push(...freshRedirectEdits(text, statement.start, words, fresh));
317
437
  if (statement.tee)
318
- edits.push(...freshTeeEdits(text, statement.start));
438
+ edits.push(...freshTeeEdits(text, statement.start, fresh));
319
439
  }
440
+ edits.push(...freshReportReadEdits(command, statements, fresh));
320
441
  return applyTextEdits(command, edits);
321
442
  }
322
443
  /**
@@ -329,7 +450,9 @@ function redirectRunnerOutputsToFreshFiles(command) {
329
450
  * The re-run keeps the run's `> <file>` redirect only in the sense of keeping its OUTPUT there:
330
451
  * the target is rewritten to a fresh sibling ({@link redirectRunnerOutputsToFreshFiles}), so a
331
452
  * re-run never overwrites the log the run itself is the evidence for (xr-molecule-flash-m173) —
332
- * and the setup around the run keeps its own file writes untouched (xr-molecule-flash-m429).
453
+ * and the setup around the run keeps its own file writes untouched (xr-molecule-flash-m429). A
454
+ * `tail`/`head`/`cat`/`grep` chained after the run that reads that exact log is shown the fresh
455
+ * sibling instead, so the re-run displays the run it performed (xr-molecule-flash-o03).
333
456
  *
334
457
  * `config` is the config the run was measured under ({@link withSuiteConfig}): the narrowed re-run
335
458
  * carries it whenever the command itself does not, so a run that dropped `--config` cannot be
package/dist/tools.d.ts CHANGED
@@ -59,6 +59,21 @@ export declare const SUITE_OVER_BUDGET_ADVICE: string;
59
59
  * @returns The note, or null when the path is not inside a package's `dist`.
60
60
  */
61
61
  export declare function moleculeDistReadNote(path: string): string | null;
62
+ /**
63
+ * The command that reads a REGISTERED background task's own log as one bounded contiguous window
64
+ * ({@link runningLogReadCommand}), with the file its launch redirects to when the launch recorded
65
+ * one.
66
+ *
67
+ * The task id is the ownership: it is the handle `wait_for_task` returned, `/tmp/${taskId}.log` is
68
+ * the log this platform's launcher writes for it, and the redirect target is the file this
69
+ * process's own launch registered for that id — never a path parsed out of a command by the
70
+ * caller. A diagnosis that reads a running walk must not build a `/tmp` path of its own
71
+ * (xr-molecule-flash-l07: the wait's DISPLAY was diagnosed as if it were the log).
72
+ *
73
+ * @param taskId - The `mol-bg-…` handle the wait returned.
74
+ * @returns The read command, or null when the handle is not a task id this platform minted.
75
+ */
76
+ export declare function registeredTaskLogCommand(taskId: string): string | null;
62
77
  /**
63
78
  * What the filesystem says about a write target under `node_modules` — the half
64
79
  * of the decision a path's spelling cannot make.
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAgS9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AAudD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAgInE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAEA,CAAA;AAE9B;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,QAI6C,CAAA;AA2DlF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;AAoBpF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GACxE,qBAAqB,CAkBvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AA2GD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAq/FxF"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAgS9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AAudD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAiInE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAEA,CAAA;AAE9B;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,QAI6C,CAAA;AA2DlF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;AAoBpF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GACxE,qBAAqB,CAkBvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AA2GD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAq/FxF"}
package/dist/tools.js CHANGED
@@ -703,7 +703,7 @@ async function backgroundTaskState(backend, command, seconds, ceilingMs) {
703
703
  }
704
704
  import { suiteCommandTarget } from './suite-overlap.js';
705
705
  import { diagnosisTraceCommand } from './trace-artifacts.js';
706
- import { addedRedactionMask, BRACE_GLOB_HINT, checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIRS, directoryReadHint, earlyReturnCause, emptyCallError, expandBraceGlob, failureCausesNote, findPathArgs, findPatternArgs, fusedLine, htmlOutline, isCommandTimeout, isEnvFilePath, isOutsideRoot, isPlaywrightRunCommand, isReadOnlyInspection, isSuiteRunCommand, linesWithinSerialized, literalDirPrefix, logShowsInlineFailureBodies, MAX_BATCH_READ_FILES, MAX_FIND_RESULTS, MAX_HTML_INLINE_CHARS, MAX_OUTPUT_SIZE, MAX_READ_CALL_CHARS, MAX_READ_RETURN_CHARS, MAX_READ_SIZE, MAX_SEARCH_CONTEXT_LINES, MAX_SEARCH_RESULTS, MAX_WRITE_SIZE, outputIsWithheldUntilExit, outputRedirectTarget, parseCheckCommand, parseCheckProblem, pathArgError, READ_RESULT_ENVELOPE_CHARS, redactSecrets, redactSecretsInCode, repeatedSuiteRunError, repeatingFailure, repeatingFailureNote, resolvePath, RUNNING_FAILURE_LINES, runningCauseCommand, runningOutputSliceCommand, searchTimeoutError, serializedChars, shellQuote, sliceLines, SMALL_FILE_WHOLE_CHARS, streamingBackgroundCommand, stripControlChars, suiteRunBudgetCommand, suiteRunConfigCommand, suiteRunPipelinePlacement, suiteRunPriorityLaunch, TOOL_RESULT_CHARS, truncateMiddle, universalCause, whitespaceTolerantReplace, withoutSuiteTimeout, withPlaywrightRunReport, } from './utilities.js';
706
+ import { addedRedactionMask, BRACE_GLOB_HINT, checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIRS, directoryReadHint, earlyReturnCause, emptyCallError, expandBraceGlob, failureCausesNote, findPathArgs, findPatternArgs, fusedLine, htmlOutline, isCommandTimeout, isEnvFilePath, isOutsideRoot, isPlaywrightRunCommand, isReadOnlyInspection, isSuiteRunCommand, linesWithinSerialized, literalDirPrefix, logShowsInlineFailureBodies, MAX_BATCH_READ_FILES, MAX_FIND_RESULTS, MAX_HTML_INLINE_CHARS, MAX_OUTPUT_SIZE, MAX_READ_CALL_CHARS, MAX_READ_RETURN_CHARS, MAX_READ_SIZE, MAX_SEARCH_CONTEXT_LINES, MAX_SEARCH_RESULTS, MAX_WRITE_SIZE, outputIsWithheldUntilExit, outputRedirectTarget, parseCheckCommand, parseCheckProblem, pathArgError, READ_RESULT_ENVELOPE_CHARS, redactSecrets, redactSecretsInCode, repeatedSuiteRunError, repeatingFailure, repeatingFailureNote, resolvePath, RUNNING_FAILURE_LINES, runningCauseCommand, runningLogReadCommand, runningOutputSliceCommand, searchTimeoutError, serializedChars, shellQuote, sliceLines, SMALL_FILE_WHOLE_CHARS, streamingBackgroundCommand, stripControlChars, suiteRunBudgetCommand, suiteRunConfigCommand, suiteRunPipelinePlacement, suiteRunPriorityLaunch, TOOL_RESULT_CHARS, truncateMiddle, universalCause, whitespaceTolerantReplace, withoutSuiteTimeout, withPlaywrightRunReport, } from './utilities.js';
707
707
  /**
708
708
  * How long exec_command waits for a command it backgrounded only because the
709
709
  * command asked for more than the tool's ceiling, before handing back a task id.
@@ -840,6 +840,25 @@ export function moleculeDistReadNote(path) {
840
840
  ? ' The declarations above are generated from it.'
841
841
  : ' For one signature, read the matching .d.ts file.'));
842
842
  }
843
+ /**
844
+ * The command that reads a REGISTERED background task's own log as one bounded contiguous window
845
+ * ({@link runningLogReadCommand}), with the file its launch redirects to when the launch recorded
846
+ * one.
847
+ *
848
+ * The task id is the ownership: it is the handle `wait_for_task` returned, `/tmp/${taskId}.log` is
849
+ * the log this platform's launcher writes for it, and the redirect target is the file this
850
+ * process's own launch registered for that id — never a path parsed out of a command by the
851
+ * caller. A diagnosis that reads a running walk must not build a `/tmp` path of its own
852
+ * (xr-molecule-flash-l07: the wait's DISPLAY was diagnosed as if it were the log).
853
+ *
854
+ * @param taskId - The `mol-bg-…` handle the wait returned.
855
+ * @returns The read command, or null when the handle is not a task id this platform minted.
856
+ */
857
+ export function registeredTaskLogCommand(taskId) {
858
+ if (!TASK_ID.test(taskId))
859
+ return null;
860
+ return runningLogReadCommand(`/tmp/${taskId}.log`, outputFileByTask.get(taskId));
861
+ }
843
862
  /**
844
863
  * The `node_modules` entry a path goes through, and the package name after it
845
864
  * (`null` when the path IS the entry).
@@ -964,6 +964,42 @@ export declare const REPEATING_CAUSE_TAIL_BYTES = 40000;
964
964
  * @returns The shell command, safe to hand to the execution backend as-is.
965
965
  */
966
966
  export declare function runningCauseCommand(log: string, own?: string): string;
967
+ /** Bytes of a running log a diagnostic note reads back: one {@link REPEATING_CAUSE_TAIL_BYTES} window. */
968
+ export declare const RUNNING_LOG_READ_BYTES = 40000;
969
+ /** A bounded, contiguous read of a running task's own log. */
970
+ export interface RunningLogRead {
971
+ /** The log's last {@link RUNNING_LOG_READ_BYTES} bytes, contiguous, as one string. */
972
+ text: string;
973
+ /** How many bytes the WHOLE log holds, or null when the read did not answer its size. */
974
+ bytes: number | null;
975
+ }
976
+ /**
977
+ * The shell command whose stdout is a bounded CONTIGUOUS read of a running task's own log: the
978
+ * log's byte size, then its last {@link RUNNING_LOG_READ_BYTES} bytes.
979
+ *
980
+ * {@link runningOutputSliceCommand} is the wrong read for a diagnosis, and l07 is the finding: it
981
+ * stitches the first 40 grep-selected failure lines to the last 1 000 bytes with a blank line
982
+ * between, so the tail is DISJOINT from the headers above it. Read as one log, the last numbered
983
+ * header absorbs whatever the tail starts with — a clipped skipped-test title became the cause of
984
+ * a genuine failure (xr-molecule-flash-l07). A contiguous window can only ever hold real
985
+ * neighbouring lines of one log.
986
+ *
987
+ * The size rides along so a caller can say when the window is only the log's end
988
+ * ({@link parseRunningLogRead}); without it a tail reads as the whole run.
989
+ *
990
+ * @param log - The task log path.
991
+ * @param own - A file the command redirects its own output to, if any.
992
+ * @returns The shell command, safe to hand to the execution backend as-is.
993
+ */
994
+ export declare function runningLogReadCommand(log: string, own?: string): string;
995
+ /**
996
+ * The two parts of {@link runningLogReadCommand}'s answer.
997
+ *
998
+ * @param stdout - The command's stdout.
999
+ * @returns The window and the whole log's byte size, or null when the size line is absent (the
1000
+ * read did not run, so nothing may be said about the log).
1001
+ */
1002
+ export declare function parseRunningLogRead(stdout: string): RunningLogRead | null;
967
1003
  /**
968
1004
  * DISTINCT tests that must share one signature before a running suite's repeating cause is named.
969
1005
  * A test the log prints twice, or a test that failed twice, is still one test.
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
package/dist/utilities.js CHANGED
@@ -536,9 +536,25 @@ const PRINTING_REPORTERS = new Set(['list', 'line', 'dot', 'basic', 'spec']);
536
536
  * edited `app/src` while the run was still walking — which voids the run.
537
537
  */
538
538
  export const PLAYWRIGHT_FAILURES_INLINE_ENV = 'PLAYWRIGHT_LIST_PRINT_FAILURES_INLINE';
539
+ /**
540
+ * A step that stores the status of the step before it in a variable: `__proof_slow=$?`.
541
+ *
542
+ * The variable name is the shell's own (`[A-Za-z_][A-Za-z0-9_]*`) and the value is EXACTLY the
543
+ * special parameter, bare or double-quoted, so nothing else can be running here. A capture whose
544
+ * value is anything else — `x=$(rebuild)`, `x=$?; rm -rf …` (a separate statement anyway) — is a
545
+ * program, not a status, and is not one of these.
546
+ */
547
+ const STATUS_CAPTURE_STEP = /^[A-Za-z_][A-Za-z0-9_]*=(?:\$\?|"\$\?"|\$\{\?\})$/;
548
+ /**
549
+ * The arithmetic body `exit $((…))` may carry and still run nothing: variable names, numbers and
550
+ * arithmetic operators only. No `$`, backtick, `;` or comma is allowed, so no command substitution
551
+ * and no expansion of a variable into something that runs can hide in it.
552
+ */
553
+ const STATUS_EXIT_ARITHMETIC = /^[A-Za-z0-9_|&+\-*/%^<>=!~() \t]*$/;
539
554
  /**
540
555
  * Whether a command step only reports or discards the status of the steps before it: `echo EXIT
541
- * $?`, `echo $?`, `printf …`, `true`, `exit 0`.
556
+ * $?`, `echo $?`, `printf …`, `true`, `exit 0`, a status capture (`__proof_slow=$?`), or an
557
+ * `exit $((a | b))` over statuses already captured.
542
558
  *
543
559
  * The shape models and the platform's own re-run notes send routinely ends on one of these —
544
560
  * `npx playwright test … > /tmp/pw.log 2>&1; echo EXIT $?` — and reading the split's last part as
@@ -548,12 +564,33 @@ export const PLAYWRIGHT_FAILURES_INLINE_ENV = 'PLAYWRIGHT_LIST_PRINT_FAILURES_IN
548
564
  * punctuation are not part of the step; {@link streamingBackgroundCommand} strips those before
549
565
  * asking, and strips them here too for the split it is given.
550
566
  *
567
+ * A status CAPTURE is the same kind of step, and the platform's own chained proof walks end on a
568
+ * run of them: `… <browser run>; __proof_slow=$?; echo __PROOF_EXIT__ …; exit $((__proof_fast |
569
+ * __proof_slow))` (`chainedProofCommand`, molecule-dev `post-deploy-proof-run.ts`). Reading the
570
+ * browser half as a status step is what lets the run keep its reporter, its machine report and the
571
+ * inline-failure switch — without it, every platform proof ran its browser suite on the request's
572
+ * own `line` reporter, which writes no ✓/✘ mark and no per-failure error into the log the wait
573
+ * reads (xr-molecule-flash-x03 +27:44).
574
+ *
575
+ * Only the two shapes whose whole value is the shell's own status are read this way; anything that
576
+ * could run — a command substitution, a backticked word, a suffix after the status — stays a step.
577
+ *
551
578
  * @param step - One statement of the command, as the `&&`/`||`/`;` split left it.
552
579
  * @returns True when the step runs nothing but a status report.
553
580
  */
554
581
  function isStatusOnlyStep(step) {
555
- const text = step.replace(/[\s)}]+$/, '').trim();
556
- return /^(?:echo|printf)\b/.test(text) || /^true$/.test(text) || /^exit(?:\s+\S+)?$/.test(text);
582
+ const text = step.trim();
583
+ // An enclosing group's closer is punctuation, not part of the step — but the `))` that closes an
584
+ // arithmetic expansion is part of the statement, so that shape is read off the text as written.
585
+ const withoutCloser = text.replace(/[\s)}]+$/, '');
586
+ if (/^(?:echo|printf)\b/.test(withoutCloser) || /^true$/.test(withoutCloser))
587
+ return true;
588
+ if (/^exit(?:\s+\S+)?$/.test(withoutCloser))
589
+ return true;
590
+ if (STATUS_CAPTURE_STEP.test(withoutCloser))
591
+ return true;
592
+ const arithmetic = /^exit\s+\$\(\((.*)\)\)$/.exec(text);
593
+ return arithmetic !== null && STATUS_EXIT_ARITHMETIC.test(arithmetic[1] ?? '');
557
594
  }
558
595
  /**
559
596
  * Rewrite a command about to run in the background so its log grows while it
@@ -2423,6 +2460,43 @@ export function runningCauseCommand(log, own) {
2423
2460
  const read = `cat ${log}${own ? ` ${shellQuote(own)}` : ''} 2>/dev/null`;
2424
2461
  return `${read} | tail -c ${REPEATING_CAUSE_TAIL_BYTES}`;
2425
2462
  }
2463
+ /** Bytes of a running log a diagnostic note reads back: one {@link REPEATING_CAUSE_TAIL_BYTES} window. */
2464
+ export const RUNNING_LOG_READ_BYTES = REPEATING_CAUSE_TAIL_BYTES;
2465
+ /**
2466
+ * The shell command whose stdout is a bounded CONTIGUOUS read of a running task's own log: the
2467
+ * log's byte size, then its last {@link RUNNING_LOG_READ_BYTES} bytes.
2468
+ *
2469
+ * {@link runningOutputSliceCommand} is the wrong read for a diagnosis, and l07 is the finding: it
2470
+ * stitches the first 40 grep-selected failure lines to the last 1 000 bytes with a blank line
2471
+ * between, so the tail is DISJOINT from the headers above it. Read as one log, the last numbered
2472
+ * header absorbs whatever the tail starts with — a clipped skipped-test title became the cause of
2473
+ * a genuine failure (xr-molecule-flash-l07). A contiguous window can only ever hold real
2474
+ * neighbouring lines of one log.
2475
+ *
2476
+ * The size rides along so a caller can say when the window is only the log's end
2477
+ * ({@link parseRunningLogRead}); without it a tail reads as the whole run.
2478
+ *
2479
+ * @param log - The task log path.
2480
+ * @param own - A file the command redirects its own output to, if any.
2481
+ * @returns The shell command, safe to hand to the execution backend as-is.
2482
+ */
2483
+ export function runningLogReadCommand(log, own) {
2484
+ const read = `cat ${log}${own ? ` ${shellQuote(own)}` : ''} 2>/dev/null`;
2485
+ return `{ ${read} | wc -c; ${read} | tail -c ${RUNNING_LOG_READ_BYTES}; }`;
2486
+ }
2487
+ /**
2488
+ * The two parts of {@link runningLogReadCommand}'s answer.
2489
+ *
2490
+ * @param stdout - The command's stdout.
2491
+ * @returns The window and the whole log's byte size, or null when the size line is absent (the
2492
+ * read did not run, so nothing may be said about the log).
2493
+ */
2494
+ export function parseRunningLogRead(stdout) {
2495
+ const sized = /^\s*(\d+)\s*\n/.exec(stdout);
2496
+ if (sized === null)
2497
+ return null;
2498
+ return { text: stdout.slice(sized[0].length), bytes: Number(sized[1]) };
2499
+ }
2426
2500
  /**
2427
2501
  * DISTINCT tests that must share one signature before a running suite's repeating cause is named.
2428
2502
  * A test the log prints twice, or a test that failed twice, is still one test.
@@ -2513,6 +2587,12 @@ function failureBody(block) {
2513
2587
  .map((l) => l.replace(ANSI_SGR, '').trim())
2514
2588
  .filter((l) => l &&
2515
2589
  !LIST_RESULT_LINE.test(l) &&
2590
+ // A SKIPPED test's own row (` - 41 [chromium] › user-fetch-errors.spec.ts:88:3 › …`) is
2591
+ // a progress line, never a failure's body: a block with no body of its own is followed by
2592
+ // whatever the reporter printed next, and that row became the failure's "cause" when the
2593
+ // wait's stitched display was read as one log (xr-molecule-flash-l07). A `- waiting for`
2594
+ // call-log line stays — it names the locator, and the dash carries no index.
2595
+ !/^\s*-\s+\d+\s+/.test(l) &&
2516
2596
  !/^(?:at\s|\d+ \||>\s*\d+ \||\|)/.test(l) &&
2517
2597
  !/^Error Context:/.test(l));
2518
2598
  }
@@ -3870,14 +3950,14 @@ regressedSpecs = []) {
3870
3950
  'handler shape, a header or CORS.');
3871
3951
  }
3872
3952
  // A text that is the TAIL of a longer log says so in its first line (`…(N earlier characters
3873
- // omitted)`, the shape `background-tasks` writes when a log is capped): what it holds is not
3953
+ // omitted)`, or bytes for a byte-bounded read): what it holds is not
3874
3954
  // the run's list of failures, only the part that survived the cut. Saying "N failures in this
3875
3955
  // run" over it reads as complete, and did: xr-molecule-flash-m123's collected 42 KB diagnosis
3876
3956
  // log was clipped to its last 8 KB, and this note grouped 2 of the run's 14 failures under
3877
3957
  // "fix every cause below" while the 11 that shared the run's one real cause were gone
3878
3958
  // (2026-10-17). The root fix is to hand this function the whole log; this says so when a
3879
3959
  // caller cannot.
3880
- const clipped = /^…\((\d+) earlier characters omitted\)/.exec(log);
3960
+ const clipped = /^…\((\d+) earlier (characters|bytes) omitted\)/.exec(log);
3881
3961
  // The missing-header reading leads the list: four unrelated locators failing while every
3882
3962
  // snapshot shows the page painted and un-navigated is ONE fact about the route, and the list
3883
3963
  // below would otherwise read as four separate defects (xr-molecule-flash-m193 rewrote the
@@ -3887,7 +3967,7 @@ regressedSpecs = []) {
3887
3967
  const header = (missingHeader === null ? '' : `${missingHeader}\n`) +
3888
3968
  (clipped !== null
3889
3969
  ? `${total} failure${total === 1 ? '' : 's'} in the LAST part of this run’s log — its ` +
3890
- `first ${clipped[1]} characters were clipped, so a cause that failed earlier is ` +
3970
+ `first ${clipped[1]} ${clipped[2]} were clipped, so a cause that failed earlier is ` +
3891
3971
  `missing here. Fix every cause below${connections.length > 0 ? ' the app’s code can produce, and re-send the connection error once as it is' : ''}, ` +
3892
3972
  `and read the whole run log before concluding:\n`
3893
3973
  : `${total} failure${total === 1 ? '' : 's'} in this run, grouped by cause — fix every cause ` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-tools",
3
- "version": "1.13.1",
3
+ "version": "1.14.0",
4
4
  "description": "Shared AI agent tools with backend abstraction for sandbox and local execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",