@molecule/api-ai-tools 1.6.4 → 1.6.5
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 +210 -3
- package/dist/command-position.d.ts +1 -1
- package/dist/command-position.d.ts.map +1 -1
- package/dist/command-position.js +55 -21
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/suite-overlap.d.ts +132 -0
- package/dist/suite-overlap.d.ts.map +1 -0
- package/dist/suite-overlap.js +208 -0
- package/dist/tools.d.ts +25 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +215 -14
- package/dist/utilities.d.ts +38 -2
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js +76 -12
- package/package.json +1 -1
package/dist/utilities.d.ts
CHANGED
|
@@ -691,6 +691,27 @@ export declare function failuresByCause(log: string): FailureCause[];
|
|
|
691
691
|
* @returns The note, or null.
|
|
692
692
|
*/
|
|
693
693
|
export declare function failureCausesNote(log: string): string | null;
|
|
694
|
+
/**
|
|
695
|
+
* The command that re-runs the tests at `locations` the way the run IN FLIGHT ran them: the same
|
|
696
|
+
* invocation, in the same directory, narrowed to those tests — or null when the running command
|
|
697
|
+
* is not a Playwright run this can narrow.
|
|
698
|
+
*
|
|
699
|
+
* The `locations` are the paths the run's own log printed, which are relative to the directory
|
|
700
|
+
* that run started in, so a re-run has to resolve them there: the command names that directory
|
|
701
|
+
* unless it already changes into one of its own, because the executor's next command starts
|
|
702
|
+
* wherever it starts. The returned command is for AFTER the run ends — it is a second run against
|
|
703
|
+
* the same app and database, and that is exactly what is refused while the run walks
|
|
704
|
+
* ({@link suiteRunInTheWay}).
|
|
705
|
+
*
|
|
706
|
+
* @param run - The run in flight: the command it was started with, as it was run, and the
|
|
707
|
+
* directory that command ran in.
|
|
708
|
+
* @param locations - The failing `file:line`s to re-run, as the run's log printed them.
|
|
709
|
+
* @returns The re-run command, or null when there is no suite to narrow.
|
|
710
|
+
*/
|
|
711
|
+
export declare function rerunOfRunningSuite(run: {
|
|
712
|
+
command: string;
|
|
713
|
+
cwd?: string;
|
|
714
|
+
}, locations: readonly string[]): string | null;
|
|
694
715
|
/**
|
|
695
716
|
* The sentence that names a cause repeating among a running suite's failures, mid-run.
|
|
696
717
|
*
|
|
@@ -705,10 +726,21 @@ export declare function failureCausesNote(log: string): string | null;
|
|
|
705
726
|
* stopped eight runs at their first repeating cause in 14.5 minutes and never finished one, so
|
|
706
727
|
* the note must not say to stop when the run still has other causes to name.
|
|
707
728
|
*
|
|
729
|
+
* The run is STILL WALKING while this note is written — both callers produce it mid-run — so a
|
|
730
|
+
* re-run of one of its tests is a second run against the same app and database, and the platform
|
|
731
|
+
* refuses that ({@link suiteRunInTheWay}, the same rule its overlap hold answers with):
|
|
732
|
+
* xr-molecule-flash-m89 (2026-10-16) read *"Start on them now, while the run keeps walking.
|
|
733
|
+
* `null-fields.spec.ts:53` alone reproduces the first one."* and sent exactly that re-run 23 s
|
|
734
|
+
* later, where the hold answered *"A playwright suite is already running against this app and
|
|
735
|
+
* database … Wait for it."* The note therefore hands over the read-and-fix to do NOW and the
|
|
736
|
+
* re-run for after the run ends — the exact command where the caller knows how the run was
|
|
737
|
+
* started ({@link rerunOfRunningSuite}), the timing alone where it does not.
|
|
738
|
+
*
|
|
708
739
|
* @param found - What {@link repeatingFailure} found.
|
|
709
740
|
* @param o - The run's facts: its `taskId`, its `log` path, `stop` — the shell command that
|
|
710
|
-
* stops it, printed only for a {@link UniversalCause} —
|
|
711
|
-
* {@link universalCause} found (absent means the run is not failing whole)
|
|
741
|
+
* stops it, printed only for a {@link UniversalCause} — `universal`, what
|
|
742
|
+
* {@link universalCause} found (absent means the run is not failing whole), and `run`, how the
|
|
743
|
+
* run was started ({@link rerunOfRunningSuite}) when the caller knows it.
|
|
712
744
|
* @returns The note.
|
|
713
745
|
*/
|
|
714
746
|
export declare function repeatingFailureNote(found: RepeatingFailure, o: {
|
|
@@ -716,6 +748,10 @@ export declare function repeatingFailureNote(found: RepeatingFailure, o: {
|
|
|
716
748
|
log: string;
|
|
717
749
|
stop: string;
|
|
718
750
|
universal?: UniversalCause | null;
|
|
751
|
+
run?: {
|
|
752
|
+
command: string;
|
|
753
|
+
cwd?: string;
|
|
754
|
+
};
|
|
719
755
|
}): string;
|
|
720
756
|
/**
|
|
721
757
|
* Attempt a whitespace-tolerant replacement when an exact `old_string` match
|
package/dist/utilities.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
|
package/dist/utilities.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { posix } from 'path';
|
|
8
8
|
import { commandSegments } from './command-position.js';
|
|
9
9
|
import { commandRunsNoTests } from './no-test-run.js';
|
|
10
|
+
import { isDiagnosisRun, scopedRerunCommand, suiteCommandTarget, suiteRunInTheWay, withoutHeredocs, } from './suite-overlap.js';
|
|
10
11
|
/**
|
|
11
12
|
* Shell-safe quoting using single quotes. Unlike JSON.stringify (double quotes),
|
|
12
13
|
* single-quoted strings prevent command substitution ($(), backticks) and variable expansion.
|
|
@@ -386,8 +387,11 @@ export function streamingBackgroundCommand(command) {
|
|
|
386
387
|
// A diagnosis or a re-run (capped, last-failed, grepped, or named files) walks each failure
|
|
387
388
|
// once: the suite's own `retries` doubled every failure of X1 flash-m71's first whole run,
|
|
388
389
|
// which had dropped the `--retries=0` it used one command earlier. The uncapped proof run
|
|
389
|
-
// keeps the suite's retries
|
|
390
|
-
|
|
390
|
+
// keeps the suite's retries — including the `--max-failures=0` the platform's own note asks
|
|
391
|
+
// for on it (xr-molecule-flash-m89). Which runs those are is {@link isDiagnosisRun}'s answer
|
|
392
|
+
// and nobody else's: the platform's notes ask the same function, so a run cannot be a
|
|
393
|
+
// diagnosis to one of them and the whole suite to the other.
|
|
394
|
+
const diagnosis = isDiagnosisRun(lastStep);
|
|
391
395
|
// The last step's reporters: one printer, and it is `list`. Every branch below only ever moves
|
|
392
396
|
// the command TO that shape — a reporter set is never left with two printers in it.
|
|
393
397
|
const reporters = finalPlaywrightRun ? lastReporterFlag(lastStep) : null;
|
|
@@ -437,7 +441,7 @@ export function streamingBackgroundCommand(command) {
|
|
|
437
441
|
changes.push('Added `--reporter=list` so each test result is written to the log as it finishes ' +
|
|
438
442
|
'(the config reporter may print nothing until the end).');
|
|
439
443
|
}
|
|
440
|
-
if (finalPlaywrightRun &&
|
|
444
|
+
if (finalPlaywrightRun && diagnosis && !/--retries\b/.test(lastStep)) {
|
|
441
445
|
out = `${out.trimEnd()} --retries=0`;
|
|
442
446
|
changes.push('Added `--retries=0`: a diagnosis or re-run walks each failure once; keep the suite’s retries for the proof run.');
|
|
443
447
|
}
|
|
@@ -1707,6 +1711,33 @@ export function failureCausesNote(log) {
|
|
|
1707
1711
|
return (`${total} failure${total === 1 ? '' : 's'} in this run, grouped by cause — fix every cause ` +
|
|
1708
1712
|
`below before the next deploy:\n${lines.join('\n')}${moreCauses}`);
|
|
1709
1713
|
}
|
|
1714
|
+
/**
|
|
1715
|
+
* The command that re-runs the tests at `locations` the way the run IN FLIGHT ran them: the same
|
|
1716
|
+
* invocation, in the same directory, narrowed to those tests — or null when the running command
|
|
1717
|
+
* is not a Playwright run this can narrow.
|
|
1718
|
+
*
|
|
1719
|
+
* The `locations` are the paths the run's own log printed, which are relative to the directory
|
|
1720
|
+
* that run started in, so a re-run has to resolve them there: the command names that directory
|
|
1721
|
+
* unless it already changes into one of its own, because the executor's next command starts
|
|
1722
|
+
* wherever it starts. The returned command is for AFTER the run ends — it is a second run against
|
|
1723
|
+
* the same app and database, and that is exactly what is refused while the run walks
|
|
1724
|
+
* ({@link suiteRunInTheWay}).
|
|
1725
|
+
*
|
|
1726
|
+
* @param run - The run in flight: the command it was started with, as it was run, and the
|
|
1727
|
+
* directory that command ran in.
|
|
1728
|
+
* @param locations - The failing `file:line`s to re-run, as the run's log printed them.
|
|
1729
|
+
* @returns The re-run command, or null when there is no suite to narrow.
|
|
1730
|
+
*/
|
|
1731
|
+
export function rerunOfRunningSuite(run, locations) {
|
|
1732
|
+
if (locations.length === 0)
|
|
1733
|
+
return null;
|
|
1734
|
+
const scoped = scopedRerunCommand(run.command, locations);
|
|
1735
|
+
if (scoped === run.command)
|
|
1736
|
+
return null;
|
|
1737
|
+
if (!run.cwd || commandSegments(withoutHeredocs(run.command)).some((s) => s.program === 'cd'))
|
|
1738
|
+
return scoped;
|
|
1739
|
+
return `cd ${shellQuote(run.cwd)} && ${scoped}`;
|
|
1740
|
+
}
|
|
1710
1741
|
/**
|
|
1711
1742
|
* The sentence that names a cause repeating among a running suite's failures, mid-run.
|
|
1712
1743
|
*
|
|
@@ -1721,10 +1752,21 @@ export function failureCausesNote(log) {
|
|
|
1721
1752
|
* stopped eight runs at their first repeating cause in 14.5 minutes and never finished one, so
|
|
1722
1753
|
* the note must not say to stop when the run still has other causes to name.
|
|
1723
1754
|
*
|
|
1755
|
+
* The run is STILL WALKING while this note is written — both callers produce it mid-run — so a
|
|
1756
|
+
* re-run of one of its tests is a second run against the same app and database, and the platform
|
|
1757
|
+
* refuses that ({@link suiteRunInTheWay}, the same rule its overlap hold answers with):
|
|
1758
|
+
* xr-molecule-flash-m89 (2026-10-16) read *"Start on them now, while the run keeps walking.
|
|
1759
|
+
* `null-fields.spec.ts:53` alone reproduces the first one."* and sent exactly that re-run 23 s
|
|
1760
|
+
* later, where the hold answered *"A playwright suite is already running against this app and
|
|
1761
|
+
* database … Wait for it."* The note therefore hands over the read-and-fix to do NOW and the
|
|
1762
|
+
* re-run for after the run ends — the exact command where the caller knows how the run was
|
|
1763
|
+
* started ({@link rerunOfRunningSuite}), the timing alone where it does not.
|
|
1764
|
+
*
|
|
1724
1765
|
* @param found - What {@link repeatingFailure} found.
|
|
1725
1766
|
* @param o - The run's facts: its `taskId`, its `log` path, `stop` — the shell command that
|
|
1726
|
-
* stops it, printed only for a {@link UniversalCause} —
|
|
1727
|
-
* {@link universalCause} found (absent means the run is not failing whole)
|
|
1767
|
+
* stops it, printed only for a {@link UniversalCause} — `universal`, what
|
|
1768
|
+
* {@link universalCause} found (absent means the run is not failing whole), and `run`, how the
|
|
1769
|
+
* run was started ({@link rerunOfRunningSuite}) when the caller knows it.
|
|
1728
1770
|
* @returns The note.
|
|
1729
1771
|
*/
|
|
1730
1772
|
export function repeatingFailureNote(found, o) {
|
|
@@ -1752,11 +1794,33 @@ export function repeatingFailureNote(found, o) {
|
|
|
1752
1794
|
? `every one with \`${found.message}\``
|
|
1753
1795
|
: `each after ~${found.seconds}s — the same duration to within half a second`;
|
|
1754
1796
|
const first = found.tests[0];
|
|
1755
|
-
const
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1797
|
+
const firstAt = first?.where ?? '';
|
|
1798
|
+
// The re-run this note names, and whether a run is in its way — the SAME rule the platform's
|
|
1799
|
+
// overlap hold answers with (@link suiteRunInTheWay), asked of the same pair: the app the
|
|
1800
|
+
// composed re-run would measure, and the app the run in flight measures (both read off the two
|
|
1801
|
+
// commands, so a re-run aimed anywhere else is not refused).
|
|
1802
|
+
const rerun = firstAt && o.run ? rerunOfRunningSuite(o.run, [firstAt]) : null;
|
|
1803
|
+
const measured = o.run ? suiteCommandTarget(o.run.command) : null;
|
|
1804
|
+
const inTheWay = measured === null
|
|
1805
|
+
? null
|
|
1806
|
+
: suiteRunInTheWay({ target: rerun ? suiteCommandTarget(rerun) : measured }, [
|
|
1807
|
+
// The composer only narrows a `playwright test` run, and the sentence below says the run
|
|
1808
|
+
// is still walking, so the run in flight is a suite either way.
|
|
1809
|
+
{ runsSuite: true, target: measured },
|
|
1810
|
+
]);
|
|
1811
|
+
// Where the run's own app is not known (this process did not start it — a restart between the
|
|
1812
|
+
// launch and the wait), the note still knows the run is WALKING, which is the whole of the
|
|
1813
|
+
// reason the re-run waits: nothing may start against the app it walks.
|
|
1814
|
+
const aRunIsInTheWay = measured === null || inTheWay !== null;
|
|
1815
|
+
const reproduce = firstAt
|
|
1816
|
+
? ` Read \`${firstAt}\` and the code it drives now, and fix it: nothing may run against this ` +
|
|
1817
|
+
`app while the run walks — a second run against the same app and database is refused — so ` +
|
|
1818
|
+
`run it alone once the run has ended.`
|
|
1819
|
+
: '';
|
|
1820
|
+
// Where the note knows how the run was started, it also hands over the exact command for after
|
|
1821
|
+
// it: the whole-suite command it must not send again, narrowed to the failing test, in the
|
|
1822
|
+
// directory the run started in. Without that record it says the timing and nothing more.
|
|
1823
|
+
const thenRun = aRunIsInTheWay && rerun ? `\nSend this once the run ends:\n ${rerun}` : '';
|
|
1760
1824
|
const where = `task ${o.taskId}, log ${o.log}`;
|
|
1761
1825
|
if (o.universal) {
|
|
1762
1826
|
const files = o.universal.files.map(shortFile);
|
|
@@ -1777,13 +1841,13 @@ export function repeatingFailureNote(found, o) {
|
|
|
1777
1841
|
if (isCause)
|
|
1778
1842
|
return (`${found.count} different tests in this run have already failed the same way — ${signature} — ` +
|
|
1779
1843
|
`so one cause is repeating:\n${rows}${more}\n` +
|
|
1780
|
-
`Start fixing it now, while the run keeps walking.${reproduce} ${keepGoing}`);
|
|
1844
|
+
`Start fixing it now, while the run keeps walking.${reproduce} ${keepGoing}${thenRun}`);
|
|
1781
1845
|
return (`${found.count} different tests in this run each failed after ~${found.seconds}s — the same ` +
|
|
1782
1846
|
`duration to within half a second. A shared duration is a lead, not a cause: a suite whose ` +
|
|
1783
1847
|
`config sets a timeout spends that timeout on every failure that waits for anything, so ` +
|
|
1784
1848
|
`different missing elements land on the same number. Read these failures before fixing one ` +
|
|
1785
1849
|
`of them:\n${rows}${more}\n` +
|
|
1786
|
-
`Start on them now, while the run keeps walking.${reproduce} ${keepGoing}`);
|
|
1850
|
+
`Start on them now, while the run keeps walking.${reproduce} ${keepGoing}${thenRun}`);
|
|
1787
1851
|
}
|
|
1788
1852
|
/**
|
|
1789
1853
|
* Attempt a whitespace-tolerant replacement when an exact `old_string` match
|