@molecule/api-ai-tools 1.6.4 → 1.6.6
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 +520 -3
- package/dist/command-position.d.ts +27 -1
- package/dist/command-position.d.ts.map +1 -1
- package/dist/command-position.js +109 -28
- package/dist/cut-run.d.ts +124 -0
- package/dist/cut-run.d.ts.map +1 -0
- package/dist/cut-run.js +267 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -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 +45 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +333 -27
- package/dist/utilities.d.ts +113 -2
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js +171 -12
- package/package.json +1 -1
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-
|
|
6
|
+
Generated: 2026-10-16T21:18:13.332Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-ai-tools
|
|
@@ -73,6 +73,37 @@ interface CommandSegment {
|
|
|
73
73
|
args: readonly string[]
|
|
74
74
|
/** The program and its arguments as one line — what a runner pattern is matched against. */
|
|
75
75
|
text: string
|
|
76
|
+
/**
|
|
77
|
+
* The seconds the segment's own `timeout` wrapper allows the command it runs
|
|
78
|
+
* (`timeout 280 hurl --test …` → 280), or null when it carries none.
|
|
79
|
+
*/
|
|
80
|
+
timeoutSeconds: number | null
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### `CutRun`
|
|
85
|
+
|
|
86
|
+
A run a budget stopped, as its result reports it.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
interface CutRun {
|
|
90
|
+
/** The bound the run was allowed, in seconds. */
|
|
91
|
+
seconds: number
|
|
92
|
+
/** Whether this tool's budget stopped it or the `timeout` the command carried. */
|
|
93
|
+
stoppedBy: CutBy
|
|
94
|
+
/**
|
|
95
|
+
* The exit code the run's own process reported, or null when the code in the result belongs to
|
|
96
|
+
* the pipeline's filter (`… | tail`) rather than to the run — the case that read as success.
|
|
97
|
+
*/
|
|
98
|
+
exitCode: number | null
|
|
99
|
+
/** How many files or tests the runner's own output shows finishing, or null when it shows none. */
|
|
100
|
+
ran: number | null
|
|
101
|
+
/** How many the run was walking, when the runner printed it (Playwright's `[n/K]`), or null. */
|
|
102
|
+
total: number | null
|
|
103
|
+
/** The noun the runner counts in. */
|
|
104
|
+
noun: 'files' | 'tests'
|
|
105
|
+
/** The last thing the run printed — the line a reader looks at first. */
|
|
106
|
+
doing: string | null
|
|
76
107
|
}
|
|
77
108
|
```
|
|
78
109
|
|
|
@@ -132,6 +163,29 @@ interface ToolSchema {
|
|
|
132
163
|
}
|
|
133
164
|
```
|
|
134
165
|
|
|
166
|
+
#### `SuiteRunInFlight`
|
|
167
|
+
|
|
168
|
+
One suite run, as the rule that decides whether a second may start beside it reads it.
|
|
169
|
+
|
|
170
|
+
Both callers describe the runs in flight the same way and ask the same question of them; what
|
|
171
|
+
differs is only which runs each one knows about — the hold reads its ledger of background runs,
|
|
172
|
+
the note reads the one run it is waiting on.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
interface SuiteRunInFlight {
|
|
176
|
+
/** Whether the run invokes a suite at all: a `vitest`/`jest` run is not one, and cannot be. */
|
|
177
|
+
runsSuite: boolean
|
|
178
|
+
/** The app and database the run measures, as {@link suiteCommandTarget} keys it. */
|
|
179
|
+
target: string
|
|
180
|
+
/**
|
|
181
|
+
* Whether the command being judged STOPS this run before starting its own — a kill comes first,
|
|
182
|
+
* so a run the command itself stops is not in the way (xr-molecule-flash-m87's
|
|
183
|
+
* `kill 19408 … ; npx playwright test …`).
|
|
184
|
+
*/
|
|
185
|
+
stoppedByCommand?: boolean
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
135
189
|
#### `ExecutionBackend`
|
|
136
190
|
|
|
137
191
|
Abstraction over the execution environment.
|
|
@@ -420,6 +474,22 @@ interface FailureCause {
|
|
|
420
474
|
|
|
421
475
|
### Types
|
|
422
476
|
|
|
477
|
+
#### `CommandRunState`
|
|
478
|
+
|
|
479
|
+
What a command's result records: a run that ended, or one a budget stopped.
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
type CommandRunState = 'ran' | typeof CUT_AT_BUDGET
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
#### `CutBy`
|
|
486
|
+
|
|
487
|
+
What stopped a run.
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
type CutBy = 'tool-budget' | 'command-timeout'
|
|
491
|
+
```
|
|
492
|
+
|
|
423
493
|
#### `DiscoveredSkill` _(deprecated)_
|
|
424
494
|
|
|
425
495
|
Re-export SkillEntry as DiscoveredSkill for backwards compatibility.
|
|
@@ -468,6 +538,18 @@ function createSandboxBackend(sandbox: SandboxLike, projectRoot?: string): Execu
|
|
|
468
538
|
|
|
469
539
|
**Returns:** A backend that proxies all filesystem calls into the sandbox.
|
|
470
540
|
|
|
541
|
+
#### `durationSeconds(word)`
|
|
542
|
+
|
|
543
|
+
The seconds a duration word stands for.
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
function durationSeconds(word: string): number | null
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
- `word` — A duration (`280`, `20s`, `1m`).
|
|
550
|
+
|
|
551
|
+
**Returns:** The seconds, or null when the word is not a duration.
|
|
552
|
+
|
|
471
553
|
#### `commandSegments(command)`
|
|
472
554
|
|
|
473
555
|
The segments of a command, each with its program and arguments — the answer every classifier
|
|
@@ -481,6 +563,25 @@ function commandSegments(command: string): CommandSegment[]
|
|
|
481
563
|
|
|
482
564
|
**Returns:** One entry per statement or pipeline stage that runs something, in order.
|
|
483
565
|
|
|
566
|
+
#### `commandTimeoutSeconds(command)`
|
|
567
|
+
|
|
568
|
+
The bound a command puts on its own run: the largest `timeout <N>` any of its segments runs
|
|
569
|
+
under (`timeout 280 hurl --test …` → 280), or null when it carries none.
|
|
570
|
+
|
|
571
|
+
This is the bound `man timeout` enforces by KILLING the command — so a run that used it did not
|
|
572
|
+
finish, whatever the pipeline's own exit status says. It is read here, from the same parse every
|
|
573
|
+
other command reader uses, rather than matched as text: `timeout` in an argument
|
|
574
|
+
(`grep -n 'timeout 280' notes.md`) bounds nothing, and `-k 5` is the grace before the kill, not
|
|
575
|
+
the bound ({@link WRAPPER_VALUE_FLAGS}).
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
function commandTimeoutSeconds(command: string): number | null
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
- `command` — The shell command.
|
|
582
|
+
|
|
583
|
+
**Returns:** The seconds the command allows itself, or null.
|
|
584
|
+
|
|
484
585
|
#### `runsInCommandPosition(command, pattern)`
|
|
485
586
|
|
|
486
587
|
Whether any segment of the command runs a program whose command-position text matches
|
|
@@ -499,6 +600,102 @@ function runsInCommandPosition(command: string, pattern: RegExp): boolean
|
|
|
499
600
|
|
|
500
601
|
**Returns:** True when a segment in command position matches.
|
|
501
602
|
|
|
603
|
+
#### `commandRunState(result)`
|
|
604
|
+
|
|
605
|
+
The state a command's result records — THE reader every verdict about a run goes through.
|
|
606
|
+
|
|
607
|
+
A result that carries no state is a run that ended: the state is written where the run is
|
|
608
|
+
stopped ({@link commandCutRun}), so a result without it was never stopped by a budget this
|
|
609
|
+
platform set or can see. Results produced before this state existed read the same way, which is
|
|
610
|
+
what keeps a past turn's tally readable.
|
|
611
|
+
|
|
612
|
+
```typescript
|
|
613
|
+
function commandRunState(result: unknown): CommandRunState
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
- `result` — The exec_command / wait_for_task result.
|
|
617
|
+
|
|
618
|
+
**Returns:** The state the result records.
|
|
619
|
+
|
|
620
|
+
#### `suiteTally(text)`
|
|
621
|
+
|
|
622
|
+
Whether text carries a runner's closing summary ({@link SUITE_TALLY}).
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
function suiteTally(text: string): boolean
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
- `text` — The run's stdout and stderr.
|
|
629
|
+
|
|
630
|
+
**Returns:** True when the runner's own end-of-run summary is there.
|
|
631
|
+
|
|
632
|
+
#### `commandCutRun(command, result, elapsedMs, budgetSeconds)`
|
|
633
|
+
|
|
634
|
+
The run a command's result records as stopped by a budget, or null when the result is a run that
|
|
635
|
+
ended (or says nothing about a run).
|
|
636
|
+
|
|
637
|
+
Evidence, in order — never a guess:
|
|
638
|
+
|
|
639
|
+
- `timeout`'s own 124 (the code the backend's wrapper returns whenever the TOOL's budget fired,
|
|
640
|
+
whatever the pipeline ended with) — and, when the clock says the command's own smaller bound
|
|
641
|
+
ran out first and less than the budget, that bound instead.
|
|
642
|
+
- the command carried its own `timeout <N>`, N is inside this tool's budget (a larger one never
|
|
643
|
+
fires — the tool's does), the run used N, and no runner printed a closing summary: the run was
|
|
644
|
+
killed at its own bound. Its exit code, when the pipeline handed one back, is the filter's.
|
|
645
|
+
- the run used this tool's whole budget behind a filter that withheld its output, and printed no
|
|
646
|
+
closing summary: the budget stopped it, and no code in the result is the run's.
|
|
647
|
+
|
|
648
|
+
```typescript
|
|
649
|
+
function commandCutRun(
|
|
650
|
+
command: string,
|
|
651
|
+
result: unknown,
|
|
652
|
+
elapsedMs: number,
|
|
653
|
+
budgetSeconds?: number,
|
|
654
|
+
): CutRun | null
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
- `command` — The command the executor sent.
|
|
658
|
+
- `result` — Its result.
|
|
659
|
+
- `elapsedMs` — How long the command ran, in ms.
|
|
660
|
+
- `budgetSeconds` — This tool's foreground budget, in seconds (0 when it has none).
|
|
661
|
+
|
|
662
|
+
**Returns:** The stopped run, or null.
|
|
663
|
+
|
|
664
|
+
#### `cutRunFacts(result)`
|
|
665
|
+
|
|
666
|
+
The facts a result records about the run a budget stopped it in — what a reader needs to say
|
|
667
|
+
how far the run got WITHOUT re-reading its log or re-deriving the counts.
|
|
668
|
+
|
|
669
|
+
The numbers are read from the runner's own output where it printed them (Hurl's per-file lines,
|
|
670
|
+
Playwright's `[n/K]`), so a caller that can also see the suite itself — the file count of the
|
|
671
|
+
`*.hurl` directory the run walked — fills in the `total` this could not know, and both then say
|
|
672
|
+
the same sentence ({@link cutRunSentence}).
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
function cutRunFacts(result: unknown): CutRun | null
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
- `result` — The exec_command / wait_for_task result.
|
|
679
|
+
|
|
680
|
+
**Returns:** The facts the result carries, or null when it records no stopped run.
|
|
681
|
+
|
|
682
|
+
#### `cutRunSentence(run)`
|
|
683
|
+
|
|
684
|
+
The first line of a stopped run's result: how long it was allowed, what stopped it, how far it
|
|
685
|
+
got, and the last thing it printed.
|
|
686
|
+
|
|
687
|
+
Written to be quotable by the model in one sentence and to leave no room for "nearly passing":
|
|
688
|
+
the counts come from the runner's own output ({@link runProgress}), and a `total` the caller
|
|
689
|
+
read elsewhere (the suite's own file count) fills in the "M of K" it can then state.
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
function cutRunSentence(run: CutRun): string
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
- `run` — The stopped run.
|
|
696
|
+
|
|
697
|
+
**Returns:** The sentence.
|
|
698
|
+
|
|
502
699
|
#### `normalizeToolInput(schema, raw)`
|
|
503
700
|
|
|
504
701
|
Move known aliases onto the declared parameter names and report what is still
|
|
@@ -606,6 +803,108 @@ function commandRunsNoTests(command: string): boolean
|
|
|
606
803
|
|
|
607
804
|
**Returns:** True when the command invokes a runner only to print.
|
|
608
805
|
|
|
806
|
+
#### `withoutHeredocs(command)`
|
|
807
|
+
|
|
808
|
+
A command with its heredoc bodies removed: the runs, kills and hosts it names in a file it
|
|
809
|
+
WRITES are not what the command itself does.
|
|
810
|
+
|
|
811
|
+
The header is kept (`cat > run.sh <<'EOF' …EOF` leaves `cat > run.sh`), which is what the
|
|
812
|
+
readers here want: everything before the body is still readable as the command's own words.
|
|
813
|
+
|
|
814
|
+
```typescript
|
|
815
|
+
function withoutHeredocs(command: string): string
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
- `command` — The shell command.
|
|
819
|
+
|
|
820
|
+
**Returns:** The command without its heredoc bodies.
|
|
821
|
+
|
|
822
|
+
#### `suiteCommandTarget(command)`
|
|
823
|
+
|
|
824
|
+
The server a suite command points at, as a comparable key: the host it names (`HOST=`,
|
|
825
|
+
`BASE_URL=`, `PLAYWRIGHT_BASE_URL=`, `--variable host=`, or a bare URL), or `local` for a run
|
|
826
|
+
that names none — a suite run in the sandbox goes to the sandbox's own app unless the command
|
|
827
|
+
says otherwise. Every localhost spelling collapses to `local` (one sandbox, one app, one
|
|
828
|
+
database).
|
|
829
|
+
|
|
830
|
+
```typescript
|
|
831
|
+
function suiteCommandTarget(command: string): string
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
- `command` — The suite command.
|
|
835
|
+
|
|
836
|
+
**Returns:** The target key.
|
|
837
|
+
|
|
838
|
+
#### `scopedRerunCommand(command, locations)`
|
|
839
|
+
|
|
840
|
+
The whole-suite command made scoped to the tests it should re-run instead: the same
|
|
841
|
+
invocation — same directory, same settings — with the named `file:line`s in place of the whole
|
|
842
|
+
suite, `--last-failed` dropped (it re-runs the tests that never ran too, X1 flash-m60) and
|
|
843
|
+
`--retries=0` set (a re-run of a known failure does not need to pay for retries).
|
|
844
|
+
|
|
845
|
+
```typescript
|
|
846
|
+
function scopedRerunCommand(command: string, locations: readonly string[]): string
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
- `command` — The whole-suite run's command.
|
|
850
|
+
- `locations` — The failing `file:line`s to re-run, as the run's own log printed them — or, for a run that started outside the suite, the absolute form Playwright matches each file argument against.
|
|
851
|
+
|
|
852
|
+
**Returns:** The scoped command, or the command unchanged when it runs no Playwright suite.
|
|
853
|
+
|
|
854
|
+
#### `suiteRunInTheWay(candidate, inFlight)`
|
|
855
|
+
|
|
856
|
+
The run in flight that makes a second run a hazard, or null when nothing is in the way.
|
|
857
|
+
|
|
858
|
+
This is the ONE rule the mid-run note and the suite-overlap hold both answer with: a suite run
|
|
859
|
+
may start only when this returns null, because two suites against one app and database share its
|
|
860
|
+
rows — the failures one causes the other cannot be told from real ones. A run that invokes no
|
|
861
|
+
suite is never in the way, and neither is one the candidate command stops first.
|
|
862
|
+
|
|
863
|
+
```typescript
|
|
864
|
+
function suiteRunInTheWay(candidate: { target: string }, inFlight: readonly T[]): T | null
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
- `candidate` — The run about to start, by the app and database it would measure ({@link suiteCommandTarget}).
|
|
868
|
+
- `inFlight` — The suite runs already going, in the order the caller found them.
|
|
869
|
+
|
|
870
|
+
**Returns:** The first run in the way, or null.
|
|
871
|
+
|
|
872
|
+
#### `isDiagnosisRun(command)`
|
|
873
|
+
|
|
874
|
+
Whether a command walks a PART of a suite instead of all of it: a cap that stops it at a failure
|
|
875
|
+
count, the failures the last run printed (`--last-failed`, `--only-changed`), a title filter, or
|
|
876
|
+
named files/lines.
|
|
877
|
+
|
|
878
|
+
THE one reading of that question, in one place. Two sites act on the answer and must never
|
|
879
|
+
disagree:
|
|
880
|
+
|
|
881
|
+
- the command rewriter that adds `--retries=0` to a background Playwright run
|
|
882
|
+
({@link ./utilities.js} `streamingBackgroundCommand`) — a diagnosis walks each failure once,
|
|
883
|
+
while the run the suite is judged by keeps the suite's own retries; and
|
|
884
|
+
- the platform's own notes (molecule-dev's `suite-cli-override.ts`), which must not tell the
|
|
885
|
+
executor to drop the `--retries=0` the platform itself has just added — the contradiction X1
|
|
886
|
+
flash-m74 and m75 filed, and m76 filed a third time.
|
|
887
|
+
|
|
888
|
+
Until xr-molecule-flash-m89 they were a regex and a predicate that only LOOKED alike, and the
|
|
889
|
+
gap was exactly the run the platform had asked for: its `testRunNote` says "run the whole suite
|
|
890
|
+
once with `--max-failures=0`", and the rewriter read that cap flag as a capped diagnosis and
|
|
891
|
+
stripped the suite's retries from the uncapped proof run that follows a deploy — the one run the
|
|
892
|
+
graded run is compared against (+25:03, +31:39, +36:40 and +49:57, the last two against the
|
|
893
|
+
deployed URL, where a network blip is likeliest and the retries it dropped are the ones that
|
|
894
|
+
absorb it).
|
|
895
|
+
|
|
896
|
+
`--max-failures=0` is Playwright's own "no cap" ({@link boundsFailures}), so it is not a
|
|
897
|
+
|
|
898
|
+
_(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/suite-overlap.d.ts`.)_
|
|
899
|
+
|
|
900
|
+
```typescript
|
|
901
|
+
function isDiagnosisRun(command: string): boolean
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
- `command` — The command as the executor sent it.
|
|
905
|
+
|
|
906
|
+
**Returns:** True when the run is a diagnosis or a re-run, not the whole suite.
|
|
907
|
+
|
|
609
908
|
#### `discoverSkills(backend)`
|
|
610
909
|
|
|
611
910
|
Discover skills from a project directory.
|
|
@@ -683,6 +982,36 @@ function moleculeDistReadNote(path: string): string | null
|
|
|
683
982
|
|
|
684
983
|
**Returns:** The note, or null when the path is not inside a package's `dist`.
|
|
685
984
|
|
|
985
|
+
#### `installedPackageWriteRefusal(path)`
|
|
986
|
+
|
|
987
|
+
The refusal for a write whose target is inside an installed package, or null
|
|
988
|
+
when the path is not under a `node_modules` directory.
|
|
989
|
+
|
|
990
|
+
`node_modules` is not the project's code: nothing written there survives the
|
|
991
|
+
next install, no deploy carries it, and a sandbox whose dependency tree is
|
|
992
|
+
shared (the pre-installed superset) breaks every other run through it. X0
|
|
993
|
+
xr-molecule-flash-m91 (+04:43) called `write_file` on
|
|
994
|
+
`node_modules/@molecule/api-resource-comment/dist/numbers.d.ts` while reading
|
|
995
|
+
the package's declarations and clobbered its runtime module a call later
|
|
996
|
+
(`module.exports = {}` over the ESM handler its own code imports) — the write
|
|
997
|
+
answered `ok: true`, and 18 s went to noticing, `npm pack`-ing the package and
|
|
998
|
+
putting the file back. Reading these files stays allowed (that is how the
|
|
999
|
+
declarations above are read at all).
|
|
1000
|
+
|
|
1001
|
+
The restore route is named because the model that has ALREADY clobbered a file
|
|
1002
|
+
(this refusal is too late for it) is the one who needs it, and because the
|
|
1003
|
+
obvious repair — `npm install <pkg>` — is itself refused in the pre-installed
|
|
1004
|
+
sandbox. `npm pack` + a `tar` extraction over the package directory is what
|
|
1005
|
+
m91 used, and what both guards leave alone.
|
|
1006
|
+
|
|
1007
|
+
```typescript
|
|
1008
|
+
function installedPackageWriteRefusal(path: string): string | null
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
- `path` — An absolute path a tool is about to write.
|
|
1012
|
+
|
|
1013
|
+
**Returns:** The one-line refusal naming the package, or null when nothing is installed there.
|
|
1014
|
+
|
|
686
1015
|
#### `buildTools(backend, config)`
|
|
687
1016
|
|
|
688
1017
|
Build a complete set of AI agent tools bound to an execution backend.
|
|
@@ -1044,6 +1373,105 @@ function findPatternArgs(pattern: string): string
|
|
|
1044
1373
|
|
|
1045
1374
|
**Returns:** A `find` predicate: `-name '…'` for a bare name, else one or more `-path '…'` alternatives, ORed inside parens when there is more than one.
|
|
1046
1375
|
|
|
1376
|
+
#### `findPathArgs(pattern)`
|
|
1377
|
+
|
|
1378
|
+
The `-path` alternatives of {@link findPatternArgs}, for a pattern whose
|
|
1379
|
+
directory the caller has already rooted the search at.
|
|
1380
|
+
|
|
1381
|
+
`find_files` narrows the search root itself when the pattern spells its own
|
|
1382
|
+
directory out (see {@link literalDirPrefix}) — `node_modules` plus
|
|
1383
|
+
`@molecule/api-resource-user/dist/*.d.ts` searched that one directory. The
|
|
1384
|
+
remainder (`*.d.ts`) must then keep the `-path` form rather than collapsing to
|
|
1385
|
+
`-name`: `*` crosses `/` in an fnmatch glob, so the `-path` form still finds a
|
|
1386
|
+
declaration file in a `dist/utilities/` subdirectory, which `-name '*.d.ts'`
|
|
1387
|
+
would drop (a silent partial answer, which is worse than the timeout it
|
|
1388
|
+
replaced).
|
|
1389
|
+
|
|
1390
|
+
```typescript
|
|
1391
|
+
function findPathArgs(pattern: string): string
|
|
1392
|
+
```
|
|
1393
|
+
|
|
1394
|
+
- `pattern` — The pattern's remainder, with a `/` in it or not.
|
|
1395
|
+
|
|
1396
|
+
**Returns:** One or more `-path '…'` alternatives, ORed inside parens when there is more than one.
|
|
1397
|
+
|
|
1398
|
+
#### `literalDirPrefix(pattern)`
|
|
1399
|
+
|
|
1400
|
+
The directory a GLOB pattern spells out, when it spells one out: everything
|
|
1401
|
+
before the pattern's first glob character, trimmed back to the last `/`.
|
|
1402
|
+
|
|
1403
|
+
A pattern is matched against the whole path with a leading "any parent"
|
|
1404
|
+
anchor ({@link findPatternArgs}), so `find` visits every entry below the
|
|
1405
|
+
search root. Handed `/workspace/node_modules` and
|
|
1406
|
+
`@molecule/api-resource-user/dist/*.d.ts` — a directory named outright —
|
|
1407
|
+
`find` walked the sandbox's entire dependency tree and hit the tool's 10 s
|
|
1408
|
+
deadline without printing a result (xr-molecule-flash-m94: the one directory
|
|
1409
|
+
the model meant answered a `list_files` in 0 s). The literal prefix is that
|
|
1410
|
+
directory, and rooting the search at it is what keeps the call instant.
|
|
1411
|
+
|
|
1412
|
+
A BARE first segment (`helpers/*`, `bonds/*`, `e2e/*.spec.ts`) is NOT one:
|
|
1413
|
+
`helpers/*` means "a `helpers/` directory anywhere below the root", which the
|
|
1414
|
+
tool documents and a live run relied on (xr-molecule-flash-m77 — a path
|
|
1415
|
+
pattern is not anchored to one depth). Rooting those at
|
|
1416
|
+
`<root>/helpers` would answer with a SUBSET, silently: the nested
|
|
1417
|
+
`api/src/helpers/` matches would disappear, and a missing file reads as
|
|
1418
|
+
"no such file". So a prefix is returned only when it names a path of two or
|
|
1419
|
+
more segments (`@molecule/api-resource-user/dist`), which is the shape that
|
|
1420
|
+
is a directory rather than a directory name.
|
|
1421
|
+
|
|
1422
|
+
```typescript
|
|
1423
|
+
function literalDirPrefix(pattern: string): string | null
|
|
1424
|
+
```
|
|
1425
|
+
|
|
1426
|
+
- `pattern` — A pattern already accepted by {@link isValidGlob}.
|
|
1427
|
+
|
|
1428
|
+
**Returns:** The literal directory prefix, without a trailing slash, or null when the pattern has no glob character, no `/`, or only a bare name before one.
|
|
1429
|
+
|
|
1430
|
+
#### `isCommandTimeout(error)`
|
|
1431
|
+
|
|
1432
|
+
Whether a backend error is the sandbox's own command deadline.
|
|
1433
|
+
|
|
1434
|
+
The E2B SDK answers a timed-out `exec` with its generic text —
|
|
1435
|
+
`[deadline_exceeded] the operation timed out: … It can be modified by passing
|
|
1436
|
+
'timeoutMs' when making the request. Use '0' to disable the timeout.` — which
|
|
1437
|
+
names an option the executor cannot set and says nothing about the search
|
|
1438
|
+
that died. Handing that sentence to the model is what xr-molecule-flash-m94
|
|
1439
|
+
read after `find_files` spent 10 s walking `node_modules`; the tool answers
|
|
1440
|
+
the deadline in its own words instead (see {@link searchTimeoutError}).
|
|
1441
|
+
|
|
1442
|
+
```typescript
|
|
1443
|
+
function isCommandTimeout(error: unknown): boolean
|
|
1444
|
+
```
|
|
1445
|
+
|
|
1446
|
+
- `error` — The error the backend threw.
|
|
1447
|
+
|
|
1448
|
+
**Returns:** True when the error reads as a timeout or a deadline.
|
|
1449
|
+
|
|
1450
|
+
#### `searchTimeoutError(tool, searched, pattern, seconds, hint)`
|
|
1451
|
+
|
|
1452
|
+
The answer a search tool gives when the backend's deadline fires: what was
|
|
1453
|
+
searched, for what, how long the tool allowed, and the two ways to get an
|
|
1454
|
+
answer — a narrower `path`, or a listing. Never the vendor's `timeoutMs`
|
|
1455
|
+
sentence (see {@link isCommandTimeout}).
|
|
1456
|
+
|
|
1457
|
+
```typescript
|
|
1458
|
+
function searchTimeoutError(
|
|
1459
|
+
tool: string,
|
|
1460
|
+
searched: string,
|
|
1461
|
+
pattern: string,
|
|
1462
|
+
seconds: number,
|
|
1463
|
+
hint: string,
|
|
1464
|
+
): string
|
|
1465
|
+
```
|
|
1466
|
+
|
|
1467
|
+
- `tool` — The tool that timed out (`find_files`, `search_files`).
|
|
1468
|
+
- `searched` — The directory the search actually covered.
|
|
1469
|
+
- `pattern` — The pattern it was searching for.
|
|
1470
|
+
- `seconds` — The tool's own limit, in seconds.
|
|
1471
|
+
- `hint` — What to do differently — the narrower target or the listing tool.
|
|
1472
|
+
|
|
1473
|
+
**Returns:** The message's text.
|
|
1474
|
+
|
|
1047
1475
|
#### `pathArgError(path, tool)`
|
|
1048
1476
|
|
|
1049
1477
|
Validate a file tool's `path` argument is a non-empty string. A weak model
|
|
@@ -1364,6 +1792,31 @@ function failureCausesNote(log: string): string | null
|
|
|
1364
1792
|
|
|
1365
1793
|
**Returns:** The note, or null.
|
|
1366
1794
|
|
|
1795
|
+
#### `rerunOfRunningSuite(run, locations)`
|
|
1796
|
+
|
|
1797
|
+
The command that re-runs the tests at `locations` the way the run IN FLIGHT ran them: the same
|
|
1798
|
+
invocation, in the same directory, narrowed to those tests — or null when the running command
|
|
1799
|
+
is not a Playwright run this can narrow.
|
|
1800
|
+
|
|
1801
|
+
The `locations` are the paths the run's own log printed, which are relative to the directory
|
|
1802
|
+
that run started in, so a re-run has to resolve them there: the command names that directory
|
|
1803
|
+
unless it already changes into one of its own, because the executor's next command starts
|
|
1804
|
+
wherever it starts. The returned command is for AFTER the run ends — it is a second run against
|
|
1805
|
+
the same app and database, and that is exactly what is refused while the run walks
|
|
1806
|
+
({@link suiteRunInTheWay}).
|
|
1807
|
+
|
|
1808
|
+
```typescript
|
|
1809
|
+
function rerunOfRunningSuite(
|
|
1810
|
+
run: { command: string; cwd?: string },
|
|
1811
|
+
locations: readonly string[],
|
|
1812
|
+
): string | null
|
|
1813
|
+
```
|
|
1814
|
+
|
|
1815
|
+
- `run` — The run in flight: the command it was started with, as it was run, and the directory that command ran in.
|
|
1816
|
+
- `locations` — The failing `file:line`s to re-run, as the run's log printed them.
|
|
1817
|
+
|
|
1818
|
+
**Returns:** The re-run command, or null when there is no suite to narrow.
|
|
1819
|
+
|
|
1367
1820
|
#### `repeatingFailureNote(found, o)`
|
|
1368
1821
|
|
|
1369
1822
|
The sentence that names a cause repeating among a running suite's failures, mid-run.
|
|
@@ -1379,15 +1832,30 @@ cause was certain at the third, 47 s in, and the note answers exactly that; X1 f
|
|
|
1379
1832
|
stopped eight runs at their first repeating cause in 14.5 minutes and never finished one, so
|
|
1380
1833
|
the note must not say to stop when the run still has other causes to name.
|
|
1381
1834
|
|
|
1835
|
+
The run is STILL WALKING while this note is written — both callers produce it mid-run — so a
|
|
1836
|
+
re-run of one of its tests is a second run against the same app and database, and the platform
|
|
1837
|
+
refuses that ({@link suiteRunInTheWay}, the same rule its overlap hold answers with):
|
|
1838
|
+
xr-molecule-flash-m89 (2026-10-16) read _"Start on them now, while the run keeps walking.
|
|
1839
|
+
`null-fields.spec.ts:53` alone reproduces the first one."_ and sent exactly that re-run 23 s
|
|
1840
|
+
later, where the hold answered *"A playwright suite is already running against this app and
|
|
1841
|
+
|
|
1842
|
+
_(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/utilities.d.ts`.)_
|
|
1843
|
+
|
|
1382
1844
|
```typescript
|
|
1383
1845
|
function repeatingFailureNote(
|
|
1384
1846
|
found: RepeatingFailure,
|
|
1385
|
-
o: {
|
|
1847
|
+
o: {
|
|
1848
|
+
taskId: string
|
|
1849
|
+
log: string
|
|
1850
|
+
stop: string
|
|
1851
|
+
universal?: UniversalCause | null
|
|
1852
|
+
run?: { command: string; cwd?: string }
|
|
1853
|
+
},
|
|
1386
1854
|
): string
|
|
1387
1855
|
```
|
|
1388
1856
|
|
|
1389
1857
|
- `found` — What {@link repeatingFailure} found.
|
|
1390
|
-
- `o` — The run's facts: its `taskId`, its `log` path, `stop` — the shell command that stops it, printed only for a {@link UniversalCause} —
|
|
1858
|
+
- `o` — The run's facts: its `taskId`, its `log` path, `stop` — the shell command that stops it, printed only for a {@link UniversalCause} — `universal`, what {@link universalCause} found (absent means the run is not failing whole), and `run`, how the run was started ({@link rerunOfRunningSuite}) when the caller knows it.
|
|
1391
1859
|
|
|
1392
1860
|
**Returns:** The note.
|
|
1393
1861
|
|
|
@@ -1469,6 +1937,15 @@ function fusedLine(content: string, newString: string): { line: number; text: st
|
|
|
1469
1937
|
|
|
1470
1938
|
### Constants
|
|
1471
1939
|
|
|
1940
|
+
#### `CUT_AT_BUDGET`
|
|
1941
|
+
|
|
1942
|
+
The state a result carries when a budget stopped its command: a run that did not finish is not a
|
|
1943
|
+
run that passed, and no reader may treat it as one.
|
|
1944
|
+
|
|
1945
|
+
```typescript
|
|
1946
|
+
const CUT_AT_BUDGET: 'cut_at_budget'
|
|
1947
|
+
```
|
|
1948
|
+
|
|
1472
1949
|
#### `TOOL_SCHEMAS`
|
|
1473
1950
|
|
|
1474
1951
|
Canonical tool schemas shared by the agent runtime and documentation.
|
|
@@ -1477,6 +1954,34 @@ Canonical tool schemas shared by the agent runtime and documentation.
|
|
|
1477
1954
|
const TOOL_SCHEMAS: Record<string, ToolSchema>
|
|
1478
1955
|
```
|
|
1479
1956
|
|
|
1957
|
+
#### `SPLIT_WORK_ADVICE`
|
|
1958
|
+
|
|
1959
|
+
The closing advice on an over-budget message for a command that is not a test
|
|
1960
|
+
suite: the work it was chaining is what to split.
|
|
1961
|
+
|
|
1962
|
+
```typescript
|
|
1963
|
+
const SPLIT_WORK_ADVICE: string
|
|
1964
|
+
```
|
|
1965
|
+
|
|
1966
|
+
#### `SUITE_OVER_BUDGET_ADVICE`
|
|
1967
|
+
|
|
1968
|
+
The closing advice on an over-budget message for a command that IS a suite run
|
|
1969
|
+
(Playwright, Vitest, a `hurl` run — {@link isSuiteRunCommand}): its files are not
|
|
1970
|
+
a bigger unit to break up.
|
|
1971
|
+
|
|
1972
|
+
X1 flash-m36 asked for this half and the message kept saying "run a smaller unit"
|
|
1973
|
+
for two months. It is the wrong direction for a suite, and measurably: a run
|
|
1974
|
+
stopped here reports NO tally, so nothing in the result says which test or request
|
|
1975
|
+
hung — the run has to be sent again in the background (off this budget, its output
|
|
1976
|
+
written to a log that can be read mid-run) or, when a consumer knows the runner's
|
|
1977
|
+
per-request limit, with each request bounded. xr-molecule-flash-m93 (+06:22,
|
|
1978
|
+
2026-10-16) lost 4.8 minutes to a Hurl run whose ONE unanswered request had hurl's
|
|
1979
|
+
300 s default per request holding the file, ten seconds past this tool's budget.
|
|
1980
|
+
|
|
1981
|
+
```typescript
|
|
1982
|
+
const SUITE_OVER_BUDGET_ADVICE: string
|
|
1983
|
+
```
|
|
1984
|
+
|
|
1480
1985
|
#### `MAX_READ_SIZE`
|
|
1481
1986
|
|
|
1482
1987
|
Max file size for read_file (5MB).
|
|
@@ -1800,6 +2305,18 @@ Peer dependencies:
|
|
|
1800
2305
|
`newlineNote` hint beside an unrelated-looking parse error, which an executor
|
|
1801
2306
|
repairs by rewriting the fused line's text and fuses the next one. The
|
|
1802
2307
|
`newlineNote` alone is still returned when the file parses.
|
|
2308
|
+
- **A replacement that only changes a line break at its boundary is refused,
|
|
2309
|
+
not applied.** When `new_string` is `old_string` with its trailing newline
|
|
2310
|
+
added or removed and nothing else, the edit can only move text across lines —
|
|
2311
|
+
joining the next line onto the replaced text, or pushing the rest of the line
|
|
2312
|
+
down — which is what a weak model does by accident when it repeats a line it
|
|
2313
|
+
means to keep (flash-m28, m55, m62, m89, five times in the m89 run alone). The
|
|
2314
|
+
replacement is skipped, the rest of the batch is applied, and the result
|
|
2315
|
+
carries `skippedNote`: one line naming the replacement, what applying it would
|
|
2316
|
+
have done, and how to say it on purpose (include the next line in `old_string`).
|
|
2317
|
+
The file's own next character decides: text on the same line is a join or a
|
|
2318
|
+
split and is refused; a blank line after it, or the end of the file, means no
|
|
2319
|
+
text crosses lines and the edit is applied as written.
|
|
1803
2320
|
- **A parameter under another name is not a broken tool.** Every tool's input
|
|
1804
2321
|
is normalized first (`cmd` → `command`, `file` → `path`, camelCase ⇄
|
|
1805
2322
|
snake_case), and a handler that throws returns an error naming the missing
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* (`head -30 run-api-tests-hurl.sh`, `grep -n playwright e2e/README.md`,
|
|
23
23
|
* `git show HEAD:run-api-tests.sh`), and a runner named in a heredoc body — a file a command
|
|
24
24
|
* WRITES is the caller's business, so a command with a heredoc goes through the caller's own
|
|
25
|
-
* stripper first (`withoutHeredocs
|
|
25
|
+
* stripper first (`withoutHeredocs`, in `./suite-overlap.js`).
|
|
26
26
|
*
|
|
27
27
|
* @module
|
|
28
28
|
*/
|
|
@@ -37,7 +37,19 @@ export interface CommandSegment {
|
|
|
37
37
|
args: readonly string[];
|
|
38
38
|
/** The program and its arguments as one line — what a runner pattern is matched against. */
|
|
39
39
|
text: string;
|
|
40
|
+
/**
|
|
41
|
+
* The seconds the segment's own `timeout` wrapper allows the command it runs
|
|
42
|
+
* (`timeout 280 hurl --test …` → 280), or null when it carries none.
|
|
43
|
+
*/
|
|
44
|
+
timeoutSeconds: number | null;
|
|
40
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* The seconds a duration word stands for.
|
|
48
|
+
*
|
|
49
|
+
* @param word - A duration (`280`, `20s`, `1m`).
|
|
50
|
+
* @returns The seconds, or null when the word is not a duration.
|
|
51
|
+
*/
|
|
52
|
+
export declare function durationSeconds(word: string): number | null;
|
|
41
53
|
/**
|
|
42
54
|
* The segments of a command, each with its program and arguments — the answer every classifier
|
|
43
55
|
* that reads a command as "this runs the suite" is asking for.
|
|
@@ -46,6 +58,20 @@ export interface CommandSegment {
|
|
|
46
58
|
* @returns One entry per statement or pipeline stage that runs something, in order.
|
|
47
59
|
*/
|
|
48
60
|
export declare function commandSegments(command: string): CommandSegment[];
|
|
61
|
+
/**
|
|
62
|
+
* The bound a command puts on its own run: the largest `timeout <N>` any of its segments runs
|
|
63
|
+
* under (`timeout 280 hurl --test …` → 280), or null when it carries none.
|
|
64
|
+
*
|
|
65
|
+
* This is the bound `man timeout` enforces by KILLING the command — so a run that used it did not
|
|
66
|
+
* finish, whatever the pipeline's own exit status says. It is read here, from the same parse every
|
|
67
|
+
* other command reader uses, rather than matched as text: `timeout` in an argument
|
|
68
|
+
* (`grep -n 'timeout 280' notes.md`) bounds nothing, and `-k 5` is the grace before the kill, not
|
|
69
|
+
* the bound ({@link WRAPPER_VALUE_FLAGS}).
|
|
70
|
+
*
|
|
71
|
+
* @param command - The shell command.
|
|
72
|
+
* @returns The seconds the command allows itself, or null.
|
|
73
|
+
*/
|
|
74
|
+
export declare function commandTimeoutSeconds(command: string): number | null;
|
|
49
75
|
/**
|
|
50
76
|
* Whether any segment of the command runs a program whose command-position text matches
|
|
51
77
|
* `pattern` — the one question a runner-kind table asks.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAmFD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3D;AAyPD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAEjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOpE;AAoCD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK/E"}
|