@molecule/api-ai-tools 1.9.18 → 1.10.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 +170 -19
- package/dist/command-position.d.ts +3 -1
- package/dist/command-position.d.ts.map +1 -1
- package/dist/command-position.js +95 -6
- package/dist/output-filter.d.ts +13 -6
- package/dist/output-filter.d.ts.map +1 -1
- package/dist/output-filter.js +35 -16
- package/dist/suite-overlap.d.ts +30 -1
- package/dist/suite-overlap.d.ts.map +1 -1
- package/dist/suite-overlap.js +171 -34
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +214 -24
- package/dist/trace-artifacts.d.ts +71 -0
- package/dist/trace-artifacts.d.ts.map +1 -1
- package/dist/trace-artifacts.js +398 -12
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utilities.d.ts +32 -12
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js +101 -33
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
import { posix } from 'path';
|
|
10
|
-
import { commandCutRun, CUT_AT_BUDGET, cutRunSentence, suiteRunExitCode } from './cut-run.js';
|
|
10
|
+
import { commandCutRun, CUT_AT_BUDGET, cutRunSentence, suiteRunExitCode, suiteSummary, } from './cut-run.js';
|
|
11
11
|
import { addChangeSpan, changedSpan, countLines, renderEditExcerpt, renderSmallFile, } from './edit-excerpt.js';
|
|
12
12
|
import { guardToolExecute, missingParamError, ToolInputError } from './input-normalizer.js';
|
|
13
13
|
import { diffLineCount } from './line-diff.js';
|
|
@@ -31,6 +31,19 @@ const waitedByTask = new Map();
|
|
|
31
31
|
const logBytesByTask = new Map();
|
|
32
32
|
/** The file a background command writes its own output to, when it redirects it. */
|
|
33
33
|
const outputFileByTask = new Map();
|
|
34
|
+
/**
|
|
35
|
+
* Task ids whose launch put the suite on {@link PLAYWRIGHT_FAILURES_INLINE_ENV} — the inline
|
|
36
|
+
* failure switch, announced by the launch's own change list and written as an `export` at the
|
|
37
|
+
* head of the command.
|
|
38
|
+
*
|
|
39
|
+
* The wait note may promise that each failure's own error sits under its ✘ line only when the run
|
|
40
|
+
* was actually given the switch: a run whose shape withheld the rewrite prints its failures only
|
|
41
|
+
* in the end-of-run summary, and the note that promised inline reports sent the model grepping a
|
|
42
|
+
* file they were not in (the m99 class, recurring at xr-molecule-flash-m173 +17:07, +39:14).
|
|
43
|
+
* Process memory, like {@link outputFileByTask}: a task this process did not launch recovers it
|
|
44
|
+
* from the script on disk, which carries the rewritten command.
|
|
45
|
+
*/
|
|
46
|
+
const inlineFailuresByTask = new Set();
|
|
34
47
|
/**
|
|
35
48
|
* How each background task was started: the command as it was actually run (after
|
|
36
49
|
* {@link streamingBackgroundCommand} rewrote it) and the directory it ran in.
|
|
@@ -158,6 +171,105 @@ export async function taskStopCommand(backend, taskId) {
|
|
|
158
171
|
return fallback;
|
|
159
172
|
}
|
|
160
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* How often a wait re-asks whether a task whose exit file has not appeared has ended. The exit
|
|
176
|
+
* file is read every tick; this probe is a process test plus the task's own output, and 3 s is
|
|
177
|
+
* close enough that a run which ended is never waited out (m182: 281 s on a walk that ended in 20).
|
|
178
|
+
*/
|
|
179
|
+
const TASK_END_LOOK_MS = 3_000;
|
|
180
|
+
/** How much of a task's own output the end test reads — a runner's tally is its last lines. */
|
|
181
|
+
const TASK_OUTPUT_END_BYTES = 4_000;
|
|
182
|
+
/**
|
|
183
|
+
* The shell probe behind {@link taskEndState}: the pid the launcher wrote, and the end of the
|
|
184
|
+
* file the command redirects its own output to.
|
|
185
|
+
*
|
|
186
|
+
* The pid test is the one `molecule-dev/api/src/ai/background-tasks.ts` applies in `liveness` —
|
|
187
|
+
* a written exit code ends the task, a live pid keeps it running, and a handle the sandbox cannot
|
|
188
|
+
* account for stays unknown — so this package and that one cannot disagree about whether a task
|
|
189
|
+
* is still walking.
|
|
190
|
+
*
|
|
191
|
+
* @param taskId - The task's `mol-bg-…` handle (format already checked by the caller).
|
|
192
|
+
* @param own - The file the command redirects its own output to, when the launch could tell.
|
|
193
|
+
* @returns The command; its first line is `MOL_TASK_STATE <alive|gone|unknown>`, the rest the tail.
|
|
194
|
+
*/
|
|
195
|
+
const taskStateCommand = (taskId, own) => `P=$(cat /tmp/${taskId}.pid 2>/dev/null); ` +
|
|
196
|
+
`if [ -z "$P" ] || [ ! -f /tmp/${taskId}.sh ]; then echo MOL_TASK_STATE unknown; ` +
|
|
197
|
+
`elif kill -0 "$P" 2>/dev/null; then echo MOL_TASK_STATE alive; ` +
|
|
198
|
+
`else echo MOL_TASK_STATE gone; fi; ` +
|
|
199
|
+
(own ? `tail -c ${TASK_OUTPUT_END_BYTES} ${shellQuote(own)} 2>/dev/null` : 'true');
|
|
200
|
+
/**
|
|
201
|
+
* The ending a task's own output already records, read from the file its command redirects to.
|
|
202
|
+
*
|
|
203
|
+
* A command can put its real work in a subshell and leave the platform's wrapper waiting on
|
|
204
|
+
* something else — `( runner > /tmp/full-run.log; echo EXIT=$? >> /tmp/full-run.log ) &` — so
|
|
205
|
+
* the task log stays empty and the exit file may never appear while the run itself is over. The
|
|
206
|
+
* run's own file is where its outcome is: an `EXIT=<n>` line the command appended, or the
|
|
207
|
+
* runner's closing tally (Playwright's status lines, Vitest's `Tests …` line, Hurl's
|
|
208
|
+
* `Executed files:`), which is the last thing a finished run prints.
|
|
209
|
+
*
|
|
210
|
+
* @param text - The tail of the task's own output file.
|
|
211
|
+
* @returns Whether the output records an ending, and the code when it recorded one.
|
|
212
|
+
*/
|
|
213
|
+
function outputEnding(text) {
|
|
214
|
+
const trimmed = text.trimEnd();
|
|
215
|
+
if (!trimmed)
|
|
216
|
+
return { ended: false, exitCode: null };
|
|
217
|
+
// An explicit marker the command appended is the run's own verdict, whatever precedes it.
|
|
218
|
+
const marker = /(?:^|\n)EXIT=(\d+)\s*$/.exec(trimmed);
|
|
219
|
+
if (marker)
|
|
220
|
+
return { ended: true, exitCode: Number(marker[1]) };
|
|
221
|
+
const lastLine = trimmed.slice(trimmed.lastIndexOf('\n') + 1).trim();
|
|
222
|
+
// A tally is an ending only as the LAST line: a second walk starts by printing its own header,
|
|
223
|
+
// so a file whose last line is still the first walk's tally is between the two.
|
|
224
|
+
const tallyLine = /^\d+\s+(?:passed|failed|flaky|skipped|interrupted|timed out|did not run)\b/.test(lastLine) ||
|
|
225
|
+
/^Tests\s+.+\(\d+\)$/.test(lastLine) ||
|
|
226
|
+
/\bExecuted files:\s*\d+/.test(lastLine);
|
|
227
|
+
if (!tallyLine)
|
|
228
|
+
return { ended: false, exitCode: null };
|
|
229
|
+
return { ended: suiteSummary(trimmed)?.finished ?? false, exitCode: null };
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Whether a background task has ENDED, asked of the task itself rather than of a note about it.
|
|
233
|
+
*
|
|
234
|
+
* A missing exit file alone is not "running": the launcher writes that file from the wrapper it
|
|
235
|
+
* started, and a command that backgrounds its real work leaves the file missing after the run is
|
|
236
|
+
* over. X1 xr-molecule-flash-m182 (+30:25) waited 281 s — its whole remaining ceiling — on a walk
|
|
237
|
+
* that had ended in 20 s, and a `sleep 240; tail` on the same handle was answered "is live". The
|
|
238
|
+
* end is read the way `molecule-dev/api/src/ai/background-tasks.ts` reads it — exit file, then
|
|
239
|
+
* the pid — plus the one signal this package has and that tracker does not: the task's own output
|
|
240
|
+
* file already holding its ending.
|
|
241
|
+
*
|
|
242
|
+
* @param backend - The execution backend the task runs on.
|
|
243
|
+
* @param taskId - The task's `mol-bg-…` handle.
|
|
244
|
+
* @returns Whether it has ended, and the code its own output recorded when it recorded one.
|
|
245
|
+
*/
|
|
246
|
+
async function taskEndState(backend, taskId) {
|
|
247
|
+
const own = outputFileByTask.get(taskId);
|
|
248
|
+
let stdout;
|
|
249
|
+
try {
|
|
250
|
+
const r = await backend.run(taskStateCommand(taskId, own), { timeout: 5_000 });
|
|
251
|
+
stdout = String(r.stdout ?? '');
|
|
252
|
+
}
|
|
253
|
+
catch (_error) {
|
|
254
|
+
// A sandbox that cannot answer is not evidence of an ending: the quiet failure (a wait) beats
|
|
255
|
+
// the loud one (a result handed back for a run that is still walking).
|
|
256
|
+
return { ended: false, exitCode: null };
|
|
257
|
+
}
|
|
258
|
+
const [stateLine = '', ...rest] = stdout.split('\n');
|
|
259
|
+
const state = /MOL_TASK_STATE (alive|gone|unknown)/.exec(stateLine)?.[1] ?? 'unknown';
|
|
260
|
+
const ownEnding = outputEnding(rest.join('\n'));
|
|
261
|
+
// The run's own output can end the task while its wrapper is still alive: the wrapper may be
|
|
262
|
+
// waiting on the wrong thing (m182's was blocked) while the run it started is over. An explicit
|
|
263
|
+
// `EXIT=<n>` is that verdict; a bare tally is trusted only once the pid is gone, because the
|
|
264
|
+
// instant between a walk's tally and its next walk's header reads the same.
|
|
265
|
+
if (ownEnding.ended && (ownEnding.exitCode !== null || state === 'gone'))
|
|
266
|
+
return ownEnding;
|
|
267
|
+
// A pid this sandbox can account for and that is gone, with no exit file: the wrapper that
|
|
268
|
+
// writes the exit code was killed or exited, so the task ended and has no verdict to invent.
|
|
269
|
+
if (state === 'gone')
|
|
270
|
+
return { ended: true, exitCode: null };
|
|
271
|
+
return { ended: false, exitCode: null };
|
|
272
|
+
}
|
|
161
273
|
/** A millisecond span the way a model reads it: seconds under 90, else minutes. */
|
|
162
274
|
function durationText(ms) {
|
|
163
275
|
const s = Math.max(0, Math.round(ms / 1000));
|
|
@@ -369,17 +481,27 @@ async function backgroundTaskState(backend, command, seconds, ceilingMs) {
|
|
|
369
481
|
const own = outputFileByTask.get(id);
|
|
370
482
|
return own !== undefined && command.includes(own);
|
|
371
483
|
};
|
|
484
|
+
// A task is only a candidate to WAIT on while it is still walking: the exit file and the same
|
|
485
|
+
// end test `wait_for_task` applies both say when it ended, so a sleep is never held for a handle
|
|
486
|
+
// whose run is already over (m182 +30:25: `sleep 240; tail /tmp/full-run.log` was answered "is
|
|
487
|
+
// live" for a task that had ended 20 s after it started).
|
|
488
|
+
const stateOf = async (id) => {
|
|
489
|
+
const exitCode = await exitCodeOf(id);
|
|
490
|
+
if (exitCode !== null)
|
|
491
|
+
return { id, ended: true, exitCode };
|
|
492
|
+
return { id, ...(await taskEndState(backend, id)) };
|
|
493
|
+
};
|
|
372
494
|
const newestFirst = [...ids].reverse();
|
|
373
495
|
const namedId = newestFirst.find(names);
|
|
374
496
|
let target = namedId
|
|
375
|
-
?
|
|
497
|
+
? await stateOf(namedId)
|
|
376
498
|
: null;
|
|
377
499
|
if (!target) {
|
|
378
500
|
// Bounded: a long session can leave many finished tasks behind, and each look costs a read.
|
|
379
501
|
for (const id of newestFirst.slice(0, 8)) {
|
|
380
|
-
const
|
|
381
|
-
if (
|
|
382
|
-
target =
|
|
502
|
+
const state = await stateOf(id);
|
|
503
|
+
if (!state.ended) {
|
|
504
|
+
target = state;
|
|
383
505
|
break;
|
|
384
506
|
}
|
|
385
507
|
}
|
|
@@ -395,7 +517,7 @@ async function backgroundTaskState(backend, command, seconds, ceilingMs) {
|
|
|
395
517
|
// No slice: the note still says the task's state and how to get its result.
|
|
396
518
|
}
|
|
397
519
|
const secondsText = `Did not sleep ${Math.round(seconds)} s: background task \`${target.id}\``;
|
|
398
|
-
if (target.
|
|
520
|
+
if (!target.ended) {
|
|
399
521
|
const facts = waitProgressClauses({
|
|
400
522
|
taskId: target.id,
|
|
401
523
|
slice,
|
|
@@ -414,15 +536,19 @@ async function backgroundTaskState(backend, command, seconds, ceilingMs) {
|
|
|
414
536
|
const counter = logProgress(slice);
|
|
415
537
|
const progress = counter ? `, at ${counter.done} of ${counter.total} in its log` : '';
|
|
416
538
|
const failures = slice.trim() ? '; the failures in its log are in outputSoFar' : '';
|
|
539
|
+
// No exit file and no code in the run's own output: it ended and there is no verdict to invent.
|
|
540
|
+
const verdict = target.exitCode === null
|
|
541
|
+
? 'no exit code — its process is gone and its output recorded none'
|
|
542
|
+
: `exit code ${target.exitCode}`;
|
|
417
543
|
return {
|
|
418
|
-
note: `${secondsText} had already ended (
|
|
544
|
+
note: `${secondsText} had already ended (${verdict})${progress}${failures} — ` +
|
|
419
545
|
`\`wait_for_task ${target.id}\` returns its result now.`,
|
|
420
546
|
slice,
|
|
421
547
|
};
|
|
422
548
|
}
|
|
423
549
|
import { suiteCommandTarget } from './suite-overlap.js';
|
|
424
550
|
import { diagnosisTraceCommand } from './trace-artifacts.js';
|
|
425
|
-
import { checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIRS, directoryReadHint, earlyReturnCause, emptyCallError, failureCausesNote, findPathArgs, findPatternArgs, fusedLine, htmlOutline, isCommandTimeout, isEnvFilePath, isOutsideRoot, isPlaywrightRunCommand, isSuiteRunCommand, isValidGlob, linesWithinSerialized, literalDirPrefix, 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, printsOnlySource, 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, suiteRunPipelinePlacement, suiteRunPriorityLaunch, TOOL_RESULT_CHARS, truncateMiddle, universalCause, whitespaceTolerantReplace, withoutSuiteTimeout, } from './utilities.js';
|
|
551
|
+
import { checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIRS, directoryReadHint, earlyReturnCause, emptyCallError, failureCausesNote, findPathArgs, findPatternArgs, fusedLine, htmlOutline, isCommandTimeout, isEnvFilePath, isOutsideRoot, isPlaywrightRunCommand, isSuiteRunCommand, isValidGlob, linesWithinSerialized, literalDirPrefix, 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, PLAYWRIGHT_FAILURES_INLINE_ENV, printsOnlySource, 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, suiteRunPipelinePlacement, suiteRunPriorityLaunch, TOOL_RESULT_CHARS, truncateMiddle, universalCause, whitespaceTolerantReplace, withoutSuiteTimeout, } from './utilities.js';
|
|
426
552
|
/**
|
|
427
553
|
* How long exec_command waits for a command it backgrounded only because the
|
|
428
554
|
* command asked for more than the tool's ceiling, before handing back a task id.
|
|
@@ -715,7 +841,7 @@ function packageCatalog(path) {
|
|
|
715
841
|
* @returns Array of AITool objects ready to pass to an AI provider
|
|
716
842
|
*/
|
|
717
843
|
export function buildTools(backend, config) {
|
|
718
|
-
const { include, exclude, pathGuards = true, symlinkGuards = false, redactSecrets: doRedact = true, blockDangerousCommands = false, blockCommand, execTimeoutMs = 120_000, commandBudgetMs, overCeilingGraceMs = OVER_CEILING_GRACE_MS, searchExcludedDirs, outlineLargeHtml, excludedTestTitles, onAfterWrite, onFileDiff, onFileChange, } = config ?? {};
|
|
844
|
+
const { include, exclude, pathGuards = true, symlinkGuards = false, redactSecrets: doRedact = true, blockDangerousCommands = false, blockCommand, execTimeoutMs = 120_000, commandBudgetMs, overCeilingGraceMs = OVER_CEILING_GRACE_MS, searchExcludedDirs, outlineLargeHtml, excludedTestTitles, requiredSuiteEnv, onAfterWrite, onFileDiff, onFileChange, } = config ?? {};
|
|
719
845
|
const root = backend.projectRoot;
|
|
720
846
|
// A host-filesystem backend with escape guards off is the combination the
|
|
721
847
|
// audit flagged: `pathGuards` off lets `..` paths out of the workspace,
|
|
@@ -2445,6 +2571,10 @@ export function buildTools(backend, config) {
|
|
|
2445
2571
|
const ownFile = ownTarget === null ? null : posix.resolve(cwd, ownTarget);
|
|
2446
2572
|
if (ownFile)
|
|
2447
2573
|
outputFileByTask.set(id, ownFile);
|
|
2574
|
+
// Whether the run's failures print as they fail, so a wait can promise that only when
|
|
2575
|
+
// it is true (see inlineFailuresByTask).
|
|
2576
|
+
if (streaming.command.startsWith(`export ${PLAYWRIGHT_FAILURES_INLINE_ENV}=1; `))
|
|
2577
|
+
inlineFailuresByTask.add(id);
|
|
2448
2578
|
runByTask.set(id, { command: streaming.command, cwd });
|
|
2449
2579
|
await backend.writeFile(script, `${streaming.command}\n`);
|
|
2450
2580
|
// The clock the grace return below reports a stopped run against: the command is
|
|
@@ -2760,13 +2890,19 @@ export function buildTools(backend, config) {
|
|
|
2760
2890
|
/^mol-bg-[a-z0-9]+-[a-z0-9]+$/.test(taskId)) {
|
|
2761
2891
|
outputFileProbed.add(taskId);
|
|
2762
2892
|
try {
|
|
2763
|
-
const
|
|
2893
|
+
const script = await backend.readFile(`/tmp/${taskId}.sh`);
|
|
2894
|
+
const target = outputRedirectTarget(script);
|
|
2764
2895
|
// A relative target was written against the command's own cwd, which
|
|
2765
2896
|
// the handle does not carry; the project root is where a background
|
|
2766
2897
|
// command runs unless the caller passed one. An absolute target is
|
|
2767
2898
|
// already resolved and stays as written.
|
|
2768
2899
|
if (target)
|
|
2769
2900
|
outputFileByTask.set(taskId, posix.resolve(root, target));
|
|
2901
|
+
// The rewritten command is on disk with the `export` head it was given: a task this
|
|
2902
|
+
// process did not launch still says whether its failures print as they fail
|
|
2903
|
+
// (see inlineFailuresByTask).
|
|
2904
|
+
if (script.startsWith(`export ${PLAYWRIGHT_FAILURES_INLINE_ENV}=1; `))
|
|
2905
|
+
inlineFailuresByTask.add(taskId);
|
|
2770
2906
|
}
|
|
2771
2907
|
catch (_error) {
|
|
2772
2908
|
// No script under that id: this process did not start the task, so
|
|
@@ -2824,6 +2960,13 @@ export function buildTools(backend, config) {
|
|
|
2824
2960
|
};
|
|
2825
2961
|
}
|
|
2826
2962
|
const log = `/tmp/${taskId}.log`;
|
|
2963
|
+
// The file every note below must point the executor at: the one its own reads and
|
|
2964
|
+
// `outputSoFar` come from. A command that redirects its output (`> /tmp/pw-full.log`) leaves
|
|
2965
|
+
// the task log holding a word, so a grep composed against THAT prints nothing — xr-molecule-
|
|
2966
|
+
// flash-m173 (+17:07) obeyed the +12:18 note's `grep … /tmp/mol-bg-….log`, every grep
|
|
2967
|
+
// printed empty, and the whole mid-run diagnosis window was lost. The task's own wrapper log
|
|
2968
|
+
// stays `log` wherever something is read from both (the size probe and the slice do).
|
|
2969
|
+
const readLog = outputFileByTask.get(taskId) ?? log;
|
|
2827
2970
|
const exitFile = `/tmp/${taskId}.exit`;
|
|
2828
2971
|
// Leave the outer tool ceiling a margin so this returns a result rather
|
|
2829
2972
|
// than being killed by it.
|
|
@@ -2870,6 +3013,8 @@ export function buildTools(backend, config) {
|
|
|
2870
3013
|
const started = runByTask.get(taskId);
|
|
2871
3014
|
let midRunNote = null;
|
|
2872
3015
|
let lastCauseLookAt = startedAt - repeatingCauseLookMs();
|
|
3016
|
+
let lastEndLookAt = startedAt - TASK_END_LOOK_MS;
|
|
3017
|
+
let endedWithoutCode = false;
|
|
2873
3018
|
let exitCode = await readExit();
|
|
2874
3019
|
while (exitCode === null && Date.now() - startedAt < budgetMs) {
|
|
2875
3020
|
await new Promise((r) => setTimeout(r, Math.min(2_000, budgetMs - (Date.now() - startedAt))));
|
|
@@ -2878,6 +3023,19 @@ export function buildTools(backend, config) {
|
|
|
2878
3023
|
// its real result instead of a note about it.
|
|
2879
3024
|
if (exitCode !== null)
|
|
2880
3025
|
break;
|
|
3026
|
+
// A missing exit file is not "running": the launcher writes that file from its wrapper,
|
|
3027
|
+
// and a command that backgrounds its real work leaves it missing after the run is over.
|
|
3028
|
+
// The same end test the sleep peek uses answers here, before a cause look can `continue`
|
|
3029
|
+
// past it — m182 (+30:25) waited 281 s on a walk that had ended in 20 s.
|
|
3030
|
+
if (Date.now() - lastEndLookAt >= TASK_END_LOOK_MS) {
|
|
3031
|
+
lastEndLookAt = Date.now();
|
|
3032
|
+
const state = await taskEndState(backend, taskId);
|
|
3033
|
+
if (state.ended) {
|
|
3034
|
+
exitCode = state.exitCode;
|
|
3035
|
+
endedWithoutCode = state.exitCode === null;
|
|
3036
|
+
break;
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
2881
3039
|
if (repeatingCauseNoted.has(taskId))
|
|
2882
3040
|
continue;
|
|
2883
3041
|
if (Date.now() - lastCauseLookAt < repeatingCauseLookMs())
|
|
@@ -2923,7 +3081,7 @@ export function buildTools(backend, config) {
|
|
|
2923
3081
|
waitedMs: earlyMs,
|
|
2924
3082
|
note: repeatingFailureNote(noted, {
|
|
2925
3083
|
taskId,
|
|
2926
|
-
log,
|
|
3084
|
+
log: readLog,
|
|
2927
3085
|
stop: await taskStopCommand(backend, taskId),
|
|
2928
3086
|
universal: stopCause,
|
|
2929
3087
|
...(started ? { run: started } : {}),
|
|
@@ -2947,7 +3105,7 @@ export function buildTools(backend, config) {
|
|
|
2947
3105
|
const editsInvalidateRun = started === undefined || suiteCommandTarget(started.command) === 'local';
|
|
2948
3106
|
midRunNote = repeatingFailureNote(found, {
|
|
2949
3107
|
taskId,
|
|
2950
|
-
log,
|
|
3108
|
+
log: readLog,
|
|
2951
3109
|
stop: '',
|
|
2952
3110
|
universal: null,
|
|
2953
3111
|
...(started ? { run: started } : {}),
|
|
@@ -2957,7 +3115,10 @@ export function buildTools(backend, config) {
|
|
|
2957
3115
|
}
|
|
2958
3116
|
const waitedMs = Date.now() - startedAt;
|
|
2959
3117
|
waitedByTask.set(taskId, waitedBefore + waitedMs);
|
|
2960
|
-
|
|
3118
|
+
// A task the end test found over with no exit code is FINISHED, not still walking: its
|
|
3119
|
+
// result is read below from its own output. Only a task still alive (or a sandbox that
|
|
3120
|
+
// could not answer) reaches the running/stuck answers.
|
|
3121
|
+
if (exitCode === null && !endedWithoutCode) {
|
|
2961
3122
|
const grownTo = await logBytes();
|
|
2962
3123
|
const lastSize = logBytesByTask.get(taskId);
|
|
2963
3124
|
if (grownTo !== null)
|
|
@@ -3009,7 +3170,7 @@ export function buildTools(backend, config) {
|
|
|
3009
3170
|
const secondWalk = secondSuiteWalk(soFar) !== null;
|
|
3010
3171
|
const stopInstead = secondWalk
|
|
3011
3172
|
? ` Stop it (\`exec_command: ${await taskStopCommand(backend, taskId)}\`) and read the ` +
|
|
3012
|
-
`first walk's tally in ${
|
|
3173
|
+
`first walk's tally in ${readLog} — the second walk measures nothing new.`
|
|
3013
3174
|
: null;
|
|
3014
3175
|
if (stillWriting && waitedBefore + waitedMs >= stuckAfterMs()) {
|
|
3015
3176
|
waitedByTask.set(taskId, 0);
|
|
@@ -3031,7 +3192,7 @@ export function buildTools(backend, config) {
|
|
|
3031
3192
|
status: 'stuck',
|
|
3032
3193
|
waitedMs: waitedBefore + waitedMs,
|
|
3033
3194
|
note: `${Math.round((waitedBefore + waitedMs) / 1000)}s of waiting and it has not exited — it is ` +
|
|
3034
|
-
`stuck, not slow. See what it printed with exec_command (tail
|
|
3195
|
+
`stuck, not slow. See what it printed with exec_command (tail ${readLog} — ` +
|
|
3035
3196
|
`read_file cannot reach /tmp), kill it (\`exec_command: ` +
|
|
3036
3197
|
`${await taskStopCommand(backend, taskId)}\`) and move on; do not wait on it again.`,
|
|
3037
3198
|
};
|
|
@@ -3050,11 +3211,19 @@ export function buildTools(backend, config) {
|
|
|
3050
3211
|
`keep waiting — its result carries the log output. ` +
|
|
3051
3212
|
(soFar.trim()
|
|
3052
3213
|
? `outputSoFar is the failure lines so far (up to ${RUNNING_FAILURE_LINES}) and then the end of ` +
|
|
3053
|
-
`the log, not the whole run — \`grep -n '✘' ${
|
|
3054
|
-
`\`grep -n -A 20 '<test name>' ${
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3214
|
+
`the log, not the whole run — \`grep -n '✘' ${readLog} | head -40\` lists every failure, ` +
|
|
3215
|
+
`\`grep -n -A 20 '<test name>' ${readLog}\` reads one failure's error: ` +
|
|
3216
|
+
// The promise is made only when the launch actually set the inline switch
|
|
3217
|
+
// (inlineFailuresByTask). A run whose shape withheld it prints each failure's
|
|
3218
|
+
// error in the end-of-run summary alone, and telling the model to grep under
|
|
3219
|
+
// the ✘ row sent it through greps that could not match (xr-molecule-flash-m173
|
|
3220
|
+
// +17:07, +39:14 — the m99 class, recurring).
|
|
3221
|
+
(inlineFailuresByTask.has(taskId)
|
|
3222
|
+
? `this run writes each failure's own report into the log as that test fails, ` +
|
|
3223
|
+
`right under its ✘ line, not only in the summary at the end. `
|
|
3224
|
+
: `this run prints each failure's error only in the summary at the end; until ` +
|
|
3225
|
+
`then the ✘ rows are all there is. `)
|
|
3226
|
+
: `Nothing has been printed yet — \`grep -n '✘' ${readLog} | head -40\` lists failures as they appear. `) +
|
|
3058
3227
|
// What an edit does to this run depends on what the run MEASURES: the sandbox's own
|
|
3059
3228
|
// app is re-served from app/src as it is edited, so the run's result stops counting; a
|
|
3060
3229
|
// run against the deployed build is untouched by a local edit, and the executor can
|
|
@@ -3100,12 +3269,20 @@ export function buildTools(backend, config) {
|
|
|
3100
3269
|
// failing tests instead of leaving the executor to re-run the whole suite (xr-molecule-
|
|
3101
3270
|
// flash-m101 +12:13: 139 tests, ~4 minutes, to check two fixes).
|
|
3102
3271
|
const run = runByTask.get(taskId);
|
|
3272
|
+
// What the REQUEST requires of this suite and the run left out: the narrowed re-run below
|
|
3273
|
+
// is composed from the run's own command, so without these it would measure the same wrong
|
|
3274
|
+
// configuration again (m182: the request names `TEST_MODE=fullstack`, the run and its
|
|
3275
|
+
// re-run both omitted it, and the walk measured the `spa` suite). The consumer's reading,
|
|
3276
|
+
// asked once per finished run; a failure to read answers "nothing required".
|
|
3277
|
+
const requiredEnv = run && requiredSuiteEnv
|
|
3278
|
+
? ((await requiredSuiteEnv(run.command, run.cwd).catch(() => [])) ?? [])
|
|
3279
|
+
: [];
|
|
3103
3280
|
// The tests the request excludes are not causes to fix, and the re-run below inverts them
|
|
3104
3281
|
// out — a result must never ask the executor to fix a test it also says does not count.
|
|
3105
3282
|
// The log's own path rides along so a recap that leaves causes out can hand over the ONE
|
|
3106
3283
|
// grep that prints their bodies: the stdout above is cut in the middle, so the log is where
|
|
3107
3284
|
// they still are whole.
|
|
3108
|
-
const causes = failureCausesNote(output, excludedTestTitles?.() ?? [], run ? { ...run, log: ownFile ?? log } : undefined);
|
|
3285
|
+
const causes = failureCausesNote(output, excludedTestTitles?.() ?? [], run ? { ...run, log: ownFile ?? log, env: requiredEnv } : undefined);
|
|
3109
3286
|
// A backgrounded run is under no tool budget, and the exit file hands back the PIPELINE's
|
|
3110
3287
|
// code — so a suite killed at a `timeout 280` the command carried behind a `| tail` reports
|
|
3111
3288
|
// 0 here too. The run's start is in its own id ({@link taskStartedAt}), so the bound it used
|
|
@@ -3139,7 +3316,16 @@ export function buildTools(backend, config) {
|
|
|
3139
3316
|
? suiteRunPipelinePlacement(run.command)
|
|
3140
3317
|
: { piped: false, unplaced: false };
|
|
3141
3318
|
const reported = suiteRunExitCode(exitCode, output, placement.piped);
|
|
3142
|
-
|
|
3319
|
+
// A run that ended with no code at all is not a filtered pipeline: the sentence below says
|
|
3320
|
+
// where its result came from, and claiming a stage after the runner would contradict it.
|
|
3321
|
+
const noCodeNote = endedWithoutCode ? null : suiteExitCodeNote(placement, reported);
|
|
3322
|
+
// The task ended and no exit file recorded a verdict: say so, and say where the result came
|
|
3323
|
+
// from, so the executor reads it instead of waiting on a handle that can never answer.
|
|
3324
|
+
const endedNote = endedWithoutCode
|
|
3325
|
+
? 'It ended without writing an exit code — its process is gone' +
|
|
3326
|
+
(ownFile ? `, and its own output (${ownFile}) is the result below` : '') +
|
|
3327
|
+
'. Read that result; do not wait on this task again.'
|
|
3328
|
+
: null;
|
|
3143
3329
|
// A FINISHED result says so, even when the code it would report is withheld: a filtered
|
|
3144
3330
|
// pipeline's code is not the run's verdict ({@link FILTERED_EXIT_NOTE}), so `exitCode` alone
|
|
3145
3331
|
// cannot tell a caller this is the delivered result rather than a progress return — and a
|
|
@@ -3149,8 +3335,12 @@ export function buildTools(backend, config) {
|
|
|
3149
3335
|
status: 'completed',
|
|
3150
3336
|
exitCode: reported,
|
|
3151
3337
|
waitedMs,
|
|
3152
|
-
...(causes || noCodeNote
|
|
3153
|
-
? {
|
|
3338
|
+
...(causes || noCodeNote || endedNote
|
|
3339
|
+
? {
|
|
3340
|
+
note: [causes, noCodeNote, endedNote]
|
|
3341
|
+
.filter((n) => Boolean(n))
|
|
3342
|
+
.join(' '),
|
|
3343
|
+
}
|
|
3154
3344
|
: {}),
|
|
3155
3345
|
stdout: sanitizeOutput(truncateMiddle(output, MAX_OUTPUT_SIZE)),
|
|
3156
3346
|
...(output.length > MAX_OUTPUT_SIZE ? { truncated: true, fullOutput: log } : {}),
|
|
@@ -139,6 +139,17 @@ export interface TraceAction {
|
|
|
139
139
|
pageId?: string;
|
|
140
140
|
/** The frame the action ran in, from the same snapshot. */
|
|
141
141
|
frameId?: string;
|
|
142
|
+
/**
|
|
143
|
+
* The selector a `fill`/`type`/`selectOption` acted on (`textarea[name="bio"]`), from the
|
|
144
|
+
* trace's own params. Kept so the note can compare what the test typed with what the page
|
|
145
|
+
* submitted (m173: the field it typed into was sent empty).
|
|
146
|
+
*/
|
|
147
|
+
selector?: string;
|
|
148
|
+
/**
|
|
149
|
+
* The value a `fill`/`type`/`selectOption` typed or chose, from the trace's own params —
|
|
150
|
+
* absent when the action carried none (a `selectOption` by label only).
|
|
151
|
+
*/
|
|
152
|
+
value?: string;
|
|
142
153
|
}
|
|
143
154
|
/**
|
|
144
155
|
* What a browser context OTHER than the failing page's recorded — the second context a
|
|
@@ -179,6 +190,29 @@ export interface TraceMissingText {
|
|
|
179
190
|
/** The path of the response that carried it (`/api/tags`). */
|
|
180
191
|
path: string;
|
|
181
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* A write the trace recorded answering a boolean field, and a LATER GET of the same resource
|
|
195
|
+
* answering the opposite for that field.
|
|
196
|
+
*
|
|
197
|
+
* This is the pair that reads as a frontend race and is not one: xr-molecule-flash-m181's follow
|
|
198
|
+
* test sent `POST /api/profiles/:username/follow` and the API answered
|
|
199
|
+
* `{"profile":{…,"following":true}}`, then a `GET /api/profiles/:username` answered
|
|
200
|
+
* `{"profile":{…,"following":false}}` — the READ route never saw the viewer, so it hydrated
|
|
201
|
+
* `following` from nobody. The run rewrote the profile component twice, the API client once, and
|
|
202
|
+
* added optimistic state before anyone read the route's middleware; the write itself was fine.
|
|
203
|
+
*/
|
|
204
|
+
export interface TraceReadContradiction {
|
|
205
|
+
/** The boolean field both answered (`following`, `favorited`). */
|
|
206
|
+
field: string;
|
|
207
|
+
/** What the write's response said it is. */
|
|
208
|
+
writeValue: boolean;
|
|
209
|
+
/** What the later read's response said it is. */
|
|
210
|
+
readValue: boolean;
|
|
211
|
+
/** The write that answered it (`POST /api/profiles/x/follow`). */
|
|
212
|
+
write: TraceRequest;
|
|
213
|
+
/** The later GET of the same resource (`GET /api/profiles/x`). */
|
|
214
|
+
read: TraceRequest;
|
|
215
|
+
}
|
|
182
216
|
/** What one trace says: the test it belongs to, the requests it made, and its console lines. */
|
|
183
217
|
export interface TraceArtifact {
|
|
184
218
|
/** The failure's spec file, relative to the run's directory, when the trace names one. */
|
|
@@ -255,6 +289,15 @@ export interface TraceArtifact {
|
|
|
255
289
|
* read before this field existed.
|
|
256
290
|
*/
|
|
257
291
|
missingText?: TraceMissingText;
|
|
292
|
+
/**
|
|
293
|
+
* A write's answer a later GET of the same resource contradicted — the read route does not see
|
|
294
|
+
* the viewer (xr-molecule-flash-m181's `following`). The note leads with it and sends the run at
|
|
295
|
+
* the route's middleware, not the page's state handling.
|
|
296
|
+
*
|
|
297
|
+
* Absent when no write and later read in the trace answered the same boolean field differently,
|
|
298
|
+
* and on traces read before this field existed.
|
|
299
|
+
*/
|
|
300
|
+
readContradiction?: TraceReadContradiction;
|
|
258
301
|
}
|
|
259
302
|
/** How many traces one read reports, newest first. */
|
|
260
303
|
export declare const MAX_TRACE_ARTIFACTS = 12;
|
|
@@ -419,6 +462,20 @@ export interface TraceRunReport {
|
|
|
419
462
|
*/
|
|
420
463
|
authEndpoints?: readonly string[];
|
|
421
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* Whether a request PATH asks the app to mint a credential — a login, a registration, a token
|
|
467
|
+
* endpoint — as opposed to a protected resource that presents one.
|
|
468
|
+
*
|
|
469
|
+
* This is the path half of {@link isCredentialExchange}, exported so a caller holding only a
|
|
470
|
+
* `METHOD path` reads the same classification: a Hurl failing entry says
|
|
471
|
+
* `POST /api/users/login` and nothing about the body, and the whole-suite note must not explain
|
|
472
|
+
* a wrong-password login that answered 200 as a cookie-jar effect (xr-molecule-flash-m176).
|
|
473
|
+
*
|
|
474
|
+
* @param path - The request path (`/api/users/login`); a query or fragment is ignored.
|
|
475
|
+
* @param authEndpoints - The endpoints the app's auth config names (`/users/login`).
|
|
476
|
+
* @returns True when the path names a credential exchange.
|
|
477
|
+
*/
|
|
478
|
+
export declare function isCredentialExchangePath(path: string, authEndpoints?: readonly string[]): boolean;
|
|
422
479
|
/**
|
|
423
480
|
* The note a failed suite run's result carries: what each failing test's page actually sent, and
|
|
424
481
|
* what came back.
|
|
@@ -458,6 +515,20 @@ export interface TraceRunReport {
|
|
|
458
515
|
* context and the assertion's page cannot be identified, the note lists the requests and makes NO
|
|
459
516
|
* causal claim — no "the test's last action", no "the page stayed at …" — instead of merging them.
|
|
460
517
|
*
|
|
518
|
+
* A field the test filled and the page submitted EMPTY ({@link formResetOf}) leads the note: the
|
|
519
|
+
* trace holds both facts — the value typed into `textarea[name="bio"]` and the `PUT /api/user`
|
|
520
|
+
* whose body carried `"bio": ""` — so the form's state was reset between the typing and the
|
|
521
|
+
* submit. The note names the effect that re-seeds a form from data whose identity changed and the
|
|
522
|
+
* fix at the source (seed the form once). xr-molecule-flash-m173 lost a deploy-and-walk cycle to
|
|
523
|
+
* this on the deployed URL only, where the background session verification lands later than it
|
|
524
|
+
* does locally.
|
|
525
|
+
*
|
|
526
|
+
* A write whose response said a boolean field is true and a LATER GET of the same resource that
|
|
527
|
+
* said it is false leads the note first ({@link readContradictionSentence}): the read route never
|
|
528
|
+
* saw the viewer, so the fix is on that route's middleware, not in the page. xr-molecule-flash-m181
|
|
529
|
+
* spent ~8 minutes rewriting the profile component over exactly that pair — the write answered
|
|
530
|
+
* `{"following":true}` and the next profile GET answered `false`.
|
|
531
|
+
*
|
|
461
532
|
* WHICH rows it spends is evidence, not artifact order (xr-molecule-flash-m112 +53:46): a row
|
|
462
533
|
* needs a recorded response, a real failure or a console line ({@link traceRowEvidence}), rows are
|
|
463
534
|
* deduplicated by the test's location, and they are ordered real failure → repeated from an
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-artifacts.d.ts","sourceRoot":"","sources":["../src/trace-artifacts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,iGAAiG;IACjG,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAA;IACX,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB;;;;OAIG;IACH,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAA;IACX,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"trace-artifacts.d.ts","sourceRoot":"","sources":["../src/trace-artifacts.ts"],"names":[],"mappings":"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"}
|