@molecule/api-ai-tools 1.5.20 → 1.6.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 +302 -38
- package/dist/command-position.d.ts +62 -0
- package/dist/command-position.d.ts.map +1 -0
- package/dist/command-position.js +352 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/no-test-run.d.ts +13 -0
- package/dist/no-test-run.d.ts.map +1 -1
- package/dist/no-test-run.js +31 -22
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +10 -4
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +113 -49
- package/dist/utilities.d.ts +189 -38
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js +463 -85
- 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-16T15:16:34.345Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-ai-tools
|
|
@@ -58,6 +58,24 @@ npm install @molecule/api-ai-tools @molecule/api-ai
|
|
|
58
58
|
|
|
59
59
|
### Interfaces
|
|
60
60
|
|
|
61
|
+
#### `CommandSegment`
|
|
62
|
+
|
|
63
|
+
One statement or pipeline stage of a shell command: what it runs, and with what.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
interface CommandSegment {
|
|
67
|
+
/**
|
|
68
|
+
* The word in command position, its directory removed (`/usr/bin/hurl` → `hurl`): the program
|
|
69
|
+
* the shell would run once whatever wrappers stood in front of it are taken away.
|
|
70
|
+
*/
|
|
71
|
+
program: string
|
|
72
|
+
/** The words after it, as written — quotes kept, so a quoted `"a|b"` is one word. */
|
|
73
|
+
args: readonly string[]
|
|
74
|
+
/** The program and its arguments as one line — what a runner pattern is matched against. */
|
|
75
|
+
text: string
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
61
79
|
#### `NormalizableSchema`
|
|
62
80
|
|
|
63
81
|
The JSON-Schema-ish shape every tool in this package declares.
|
|
@@ -358,13 +376,44 @@ A cause repeating among a running suite's failures.
|
|
|
358
376
|
|
|
359
377
|
```typescript
|
|
360
378
|
interface RepeatingFailure {
|
|
361
|
-
/**
|
|
379
|
+
/**
|
|
380
|
+
* How many DISTINCT tests share the signature — a test printed twice (two reporters in the
|
|
381
|
+
* log) or failed twice (a retry) is one test.
|
|
382
|
+
*/
|
|
362
383
|
count: number
|
|
363
384
|
/** The shared error line, when the log carries the failures' bodies (`line` reporter). */
|
|
364
385
|
message: string | null
|
|
365
386
|
/** The shared duration in seconds, when the failures line up by how long they ran. */
|
|
366
387
|
seconds: number | null
|
|
367
|
-
/** The
|
|
388
|
+
/** The distinct tests that share it, in log order. */
|
|
389
|
+
tests: FailedTest[]
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
#### `UniversalCause`
|
|
394
|
+
|
|
395
|
+
A repeating cause that is failing the WHOLE run — see {@link universalCause}.
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
interface UniversalCause {
|
|
399
|
+
/** How many distinct tests share it. */
|
|
400
|
+
count: number
|
|
401
|
+
/** The distinct spec files they live in, in the order the log named them. */
|
|
402
|
+
files: string[]
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
#### `FailureCause`
|
|
407
|
+
|
|
408
|
+
One cause of failure in a run, and the tests it hit.
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
interface FailureCause {
|
|
412
|
+
/** The error line its tests all reported, or null when only the duration ties them together. */
|
|
413
|
+
message: string | null
|
|
414
|
+
/** The duration they shared in seconds, or null when the error line is the signature. */
|
|
415
|
+
seconds: number | null
|
|
416
|
+
/** The distinct tests it hit, in the order the log named them. */
|
|
368
417
|
tests: FailedTest[]
|
|
369
418
|
}
|
|
370
419
|
```
|
|
@@ -419,6 +468,37 @@ function createSandboxBackend(sandbox: SandboxLike, projectRoot?: string): Execu
|
|
|
419
468
|
|
|
420
469
|
**Returns:** A backend that proxies all filesystem calls into the sandbox.
|
|
421
470
|
|
|
471
|
+
#### `commandSegments(command)`
|
|
472
|
+
|
|
473
|
+
The segments of a command, each with its program and arguments — the answer every classifier
|
|
474
|
+
that reads a command as "this runs the suite" is asking for.
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
function commandSegments(command: string): CommandSegment[]
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
- `command` — The shell command.
|
|
481
|
+
|
|
482
|
+
**Returns:** One entry per statement or pipeline stage that runs something, in order.
|
|
483
|
+
|
|
484
|
+
#### `runsInCommandPosition(command, pattern)`
|
|
485
|
+
|
|
486
|
+
Whether any segment of the command runs a program whose command-position text matches
|
|
487
|
+
`pattern` — the one question a runner-kind table asks.
|
|
488
|
+
|
|
489
|
+
The pattern is matched against `program` and its arguments as one line, so it must be
|
|
490
|
+
anchored at `^`; it must not carry the `g` flag (a pattern shared between calls would then
|
|
491
|
+
carry its own match position from one segment to the next).
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
function runsInCommandPosition(command: string, pattern: RegExp): boolean
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
- `command` — The shell command.
|
|
498
|
+
- `pattern` — An anchored pattern for the runner's invocation.
|
|
499
|
+
|
|
500
|
+
**Returns:** True when a segment in command position matches.
|
|
501
|
+
|
|
422
502
|
#### `normalizeToolInput(schema, raw)`
|
|
423
503
|
|
|
424
504
|
Move known aliases onto the declared parameter names and report what is still
|
|
@@ -504,6 +584,12 @@ function guardAITool(tool: T, options?: GuardOptions): T
|
|
|
504
584
|
Whether a shell command invokes a test runner and EVERY such invocation only prints — so the
|
|
505
585
|
command runs no test at all.
|
|
506
586
|
|
|
587
|
+
A runner counts only where a shell would RUN it ({@link commandSegments}): the word in command
|
|
588
|
+
position of a segment, after its wrapper prefixes. A runner named in an argument is not an
|
|
589
|
+
invocation — `head -30 run-api-tests-hurl.sh` and `grep -n playwright e2e/README.md` name a
|
|
590
|
+
file to read, and a `--list` written inside a file the command writes is not a flag anyone runs
|
|
591
|
+
with (flash-m81).
|
|
592
|
+
|
|
507
593
|
A command that invokes no runner is NOT one of these (false): "the command runs no test" is
|
|
508
594
|
then true for `ls`, which is not the question any caller is asking. The question is whether
|
|
509
595
|
the runner invocation each caller read as a run is one.
|
|
@@ -753,16 +839,15 @@ killed (X1 run flash-m15 lost 20 of its 60 minutes this way, 2026-10-15):
|
|
|
753
839
|
often `html`, which prints nothing per test. `--reporter=list` is added
|
|
754
840
|
when the playwright run is the command's last step and nothing is piped or
|
|
755
841
|
redirected from it: it writes each result as it finishes, and it is the
|
|
756
|
-
shape the platform reads a background suite back in
|
|
757
|
-
fail-fast note and the Tests bar both parse `list` lines). A run that names
|
|
758
|
-
`--reporter=line` is switched to `list` for the same reason — `line` writes
|
|
759
|
-
`[n/N] <title>` with no ✓/✘ mark and no duration, so on X1 flash-m62 an
|
|
760
|
-
8.3-minute walk of one suite could never trip the fail-fast note.
|
|
842
|
+
shape the platform reads a background suite back in.
|
|
761
843
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
844
|
+
The run ends up with exactly ONE reporter that prints each failure — `list`. A run that names
|
|
845
|
+
any other printing reporter has it REPLACED, never joined: two of them write every test result
|
|
846
|
+
into the log twice, which on X1 flash-m83 (2026-10-16) made a `--reporter=list,line` run (its
|
|
847
|
+
`line` added by this function one run earlier) report two distinct failures as "4 of this run's
|
|
848
|
+
tests have already failed the same way", and the executor stopped a 139-test walk at test 21
|
|
849
|
+
with a single cause in hand. `line` alone is no use either: it writes `[n/N] <title>` with no
|
|
850
|
+
✓/✘ mark and no duration, so on X1 flash-m62 an 8.3-minute walk of one suite could never trip
|
|
766
851
|
|
|
767
852
|
_(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/utilities.d.ts`.)_
|
|
768
853
|
|
|
@@ -793,13 +878,17 @@ function isSuiteRunCommand(command: string): boolean
|
|
|
793
878
|
|
|
794
879
|
#### `isPlaywrightRunCommand(command)`
|
|
795
880
|
|
|
796
|
-
Whether a command starts a Playwright run — `playwright test` in
|
|
881
|
+
Whether a command starts a Playwright run — a `playwright test` in command position, in a form
|
|
882
|
+
that runs something.
|
|
797
883
|
|
|
798
884
|
`npx playwright test --list` matched every `\bplaywright\s+test\b` test in the platform and was
|
|
799
885
|
then treated as a run: held (flash-m79's config check), backgrounded for a run that outlasts
|
|
800
886
|
the tool's ceiling, and rewritten with `--reporter`. A list takes two seconds, prints its lines
|
|
801
887
|
and exits, so it is none of those; {@link commandRunsNoTests} is what decides.
|
|
802
888
|
|
|
889
|
+
A `playwright test` named as an argument is not a run either (`head -30 run-tests.sh`,
|
|
890
|
+
`grep -n "playwright test" e2e/README.md`): the command that runs is the reader.
|
|
891
|
+
|
|
803
892
|
```typescript
|
|
804
893
|
function isPlaywrightRunCommand(command: string): boolean
|
|
805
894
|
```
|
|
@@ -989,6 +1078,38 @@ function sliceLines(
|
|
|
989
1078
|
|
|
990
1079
|
**Returns:** The window plus its position, or null when neither was given.
|
|
991
1080
|
|
|
1081
|
+
#### `serializedChars(text)`
|
|
1082
|
+
|
|
1083
|
+
A file's text as the request counts it: the length of its JSON string.
|
|
1084
|
+
|
|
1085
|
+
JSON escaping (`\n` → `\\n`, `"` → `\"`) costs characters, and the request
|
|
1086
|
+
side counts the SERIALIZED tool result. A window of 59,000 characters of
|
|
1087
|
+
source — 1,200 lines — arrives as ~60,200 characters of JSON, over the
|
|
1088
|
+
ceiling it was sized for, so a window is measured with this rather than by
|
|
1089
|
+
its raw text length.
|
|
1090
|
+
|
|
1091
|
+
```typescript
|
|
1092
|
+
function serializedChars(text: string): number
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
- `text` — The text.
|
|
1096
|
+
|
|
1097
|
+
**Returns:** Its serialized length, without the surrounding quotes.
|
|
1098
|
+
|
|
1099
|
+
#### `linesWithinSerialized(content, chars)`
|
|
1100
|
+
|
|
1101
|
+
How many leading lines of a file fit inside a budget of SERIALIZED chars,
|
|
1102
|
+
the way `read_file` sizes a window (see {@link serializedChars}).
|
|
1103
|
+
|
|
1104
|
+
```typescript
|
|
1105
|
+
function linesWithinSerialized(content: string, chars: number): number
|
|
1106
|
+
```
|
|
1107
|
+
|
|
1108
|
+
- `content` — The file's full text.
|
|
1109
|
+
- `chars` — The budget in serialized chars.
|
|
1110
|
+
|
|
1111
|
+
**Returns:** The line count, at least one.
|
|
1112
|
+
|
|
992
1113
|
#### `looksLikeHtml(text)`
|
|
993
1114
|
|
|
994
1115
|
Whether `text` is an HTML document (a doctype or an `<html` root tag).
|
|
@@ -1111,41 +1232,117 @@ The cause repeating among a running suite's failures, or null.
|
|
|
1111
1232
|
|
|
1112
1233
|
Playwright's `list` reporter prints one line per test as it finishes — its mark, its title
|
|
1113
1234
|
path and how long it ran — and defers each failure's error to the summary at the end, so
|
|
1114
|
-
mid-run the only signature those lines carry is the duration.
|
|
1115
|
-
failure bodies
|
|
1116
|
-
which is stronger (it needs no assumption about how long a
|
|
1117
|
-
message is looked for first.
|
|
1235
|
+
mid-run the only signature those lines carry is the duration. Where the log carries the
|
|
1236
|
+
failure bodies (a `line` reporter's output, or a finished run's summary) the repeated error
|
|
1237
|
+
message itself is the signature, which is stronger (it needs no assumption about how long a
|
|
1238
|
+
failure should take), so the message is looked for first.
|
|
1118
1239
|
|
|
1119
1240
|
Either way the point is the same: a suite whose failures repeat one cause spends its whole
|
|
1120
1241
|
runtime proving that one cause, and the executor watching it can be told so at the third
|
|
1121
1242
|
failure instead of at the last. X1 flash-m76 walked 15 tests in 4.0 minutes where 15.6 s
|
|
1122
1243
|
each was the test timeout and one missing `navigate('/')` was the cause of all of them.
|
|
1123
1244
|
|
|
1245
|
+
The quorum is of DISTINCT tests — {@link REPEATING_FAILURE_MIN} of them — because a log that
|
|
1246
|
+
prints each failure twice (a second reporter, a retry) had X1 flash-m83 told that four of its
|
|
1247
|
+
tests had failed the same way when two had, so the executor stopped a 139-test walk at test 21
|
|
1248
|
+
with one cause in hand (2026-10-16).
|
|
1249
|
+
|
|
1124
1250
|
```typescript
|
|
1125
1251
|
function repeatingFailure(log: string): RepeatingFailure | null
|
|
1126
1252
|
```
|
|
1127
1253
|
|
|
1128
1254
|
- `log` — The log so far.
|
|
1129
1255
|
|
|
1130
|
-
**Returns:** The repeating cause, or null when no signature has {@link REPEATING_FAILURE_MIN}
|
|
1256
|
+
**Returns:** The repeating cause, or null when no signature has {@link REPEATING_FAILURE_MIN} distinct tests behind it.
|
|
1257
|
+
|
|
1258
|
+
#### `universalCause(log, found)`
|
|
1259
|
+
|
|
1260
|
+
Whether a repeating cause is failing the whole run — the one case where stopping it is the
|
|
1261
|
+
right call.
|
|
1262
|
+
|
|
1263
|
+
The test is: the cause accounts for every failure the log names, it has hit
|
|
1264
|
+
{@link UNIVERSAL_CAUSE_FILES} spec files or more, and nothing has passed since its first
|
|
1265
|
+
failure. An app that is not up, a 5xx on every request, or a selector that is missing on every
|
|
1266
|
+
page all look like that, and every remaining test will fail the same way — so the run's
|
|
1267
|
+
remaining minutes measure nothing. Anything less is NOT this: a cause that stops at one file,
|
|
1268
|
+
or that leaves other tests passing, or that shares the run with failures of another shape,
|
|
1269
|
+
leaves the run with something to say, and the run is the only thing that will say it. X1
|
|
1270
|
+
flash-m83 (2026-10-16) stopped eight local runs at their first repeating cause over 14.5
|
|
1271
|
+
minutes and never finished one; three of its deploys each fixed a single cause that a finished
|
|
1272
|
+
run would have listed alongside the others.
|
|
1273
|
+
|
|
1274
|
+
```typescript
|
|
1275
|
+
function universalCause(log: string, found: RepeatingFailure): UniversalCause | null
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
- `log` — The log so far.
|
|
1279
|
+
- `found` — The repeating cause {@link repeatingFailure} found in it.
|
|
1280
|
+
|
|
1281
|
+
**Returns:** The cause's count and files, or null when the run is not failing whole.
|
|
1282
|
+
|
|
1283
|
+
#### `failuresByCause(log)`
|
|
1284
|
+
|
|
1285
|
+
Every failure a run names, grouped by the cause behind it — one group per cause, with the
|
|
1286
|
+
tests it hit.
|
|
1287
|
+
|
|
1288
|
+
The point is that ONE run yields EVERY cause. A Playwright report prints its failures one
|
|
1289
|
+
after another with no statement of which of them share a cause, so a run of 19 failures is 19
|
|
1290
|
+
bodies to read; X1 flash-m83 (2026-10-16) spent three deploys (6.7 minutes) each fixing a
|
|
1291
|
+
single cause, two of them found by runs stopped before they walked the rest.
|
|
1292
|
+
|
|
1293
|
+
The signature is the failures' own error line where the log carries their bodies (a finished
|
|
1294
|
+
run, or a `line` reporter), and how long they took where it does not (a still-running `list`
|
|
1295
|
+
log). A test the log printed twice, or failed twice, is one test.
|
|
1296
|
+
|
|
1297
|
+
```typescript
|
|
1298
|
+
function failuresByCause(log: string): FailureCause[]
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
- `log` — The log of a finished or running run.
|
|
1302
|
+
|
|
1303
|
+
**Returns:** The causes, the one with the most tests first.
|
|
1304
|
+
|
|
1305
|
+
#### `failureCausesNote(log)`
|
|
1306
|
+
|
|
1307
|
+
The one-line-per-cause summary of a finished run's failures, or null when the run named fewer
|
|
1308
|
+
than two of them.
|
|
1309
|
+
|
|
1310
|
+
This is what makes a run worth finishing: every cause the run found, in the result the
|
|
1311
|
+
executor reads, so one round of fixes covers all of them rather than the one cause a run
|
|
1312
|
+
stopped early happened to reach.
|
|
1313
|
+
|
|
1314
|
+
```typescript
|
|
1315
|
+
function failureCausesNote(log: string): string | null
|
|
1316
|
+
```
|
|
1317
|
+
|
|
1318
|
+
- `log` — The finished run's output.
|
|
1319
|
+
|
|
1320
|
+
**Returns:** The note, or null.
|
|
1131
1321
|
|
|
1132
1322
|
#### `repeatingFailureNote(found, o)`
|
|
1133
1323
|
|
|
1134
|
-
The sentence that names a cause repeating among a running suite's failures,
|
|
1135
|
-
that stops the run so the cause can be fixed first.
|
|
1324
|
+
The sentence that names a cause repeating among a running suite's failures, mid-run.
|
|
1136
1325
|
|
|
1137
1326
|
Kept here, beside {@link repeatingFailure}, so the two stay in step: every word below is about
|
|
1138
|
-
what that function could actually see in the log
|
|
1327
|
+
what that function could actually see in the log — including the count, which is of DISTINCT
|
|
1328
|
+
tests, so the note never names one or two tests as a cause.
|
|
1329
|
+
|
|
1330
|
+
The note names the cause early so the executor can START FIXING while the run keeps walking,
|
|
1331
|
+
and it asks for the run to be stopped only when {@link universalCause} says the cause is
|
|
1332
|
+
failing the whole run. X1 flash-m76 (2026-10-16) spent 4.0 minutes walking 15 tests whose one
|
|
1333
|
+
cause was certain at the third, 47 s in, and the note answers exactly that; X1 flash-m83 then
|
|
1334
|
+
stopped eight runs at their first repeating cause in 14.5 minutes and never finished one, so
|
|
1335
|
+
the note must not say to stop when the run still has other causes to name.
|
|
1139
1336
|
|
|
1140
1337
|
```typescript
|
|
1141
1338
|
function repeatingFailureNote(
|
|
1142
1339
|
found: RepeatingFailure,
|
|
1143
|
-
o: { taskId: string; log: string; stop: string },
|
|
1340
|
+
o: { taskId: string; log: string; stop: string; universal?: UniversalCause | null },
|
|
1144
1341
|
): string
|
|
1145
1342
|
```
|
|
1146
1343
|
|
|
1147
1344
|
- `found` — What {@link repeatingFailure} found.
|
|
1148
|
-
- `o` — The run's facts: its `taskId`, its `log` path,
|
|
1345
|
+
- `o` — The run's facts: its `taskId`, its `log` path, `stop` — the shell command that stops it, printed only for a {@link UniversalCause} — and `universal`, what {@link universalCause} found (absent means the run is not failing whole).
|
|
1149
1346
|
|
|
1150
1347
|
**Returns:** The note.
|
|
1151
1348
|
|
|
@@ -1272,34 +1469,67 @@ const MAX_SEARCH_CONTEXT_LINES: 40
|
|
|
1272
1469
|
#### `MAX_BATCH_READ_FILES`
|
|
1273
1470
|
|
|
1274
1471
|
Most files one batched `read_file` call returns. The cap exists so a survey
|
|
1275
|
-
of a large tree cannot swallow the turn's context in one result;
|
|
1276
|
-
|
|
1472
|
+
of a large tree cannot swallow the turn's context in one result; every path
|
|
1473
|
+
past it is named in the result's `note` and listed with its own `error`, so
|
|
1474
|
+
the model continues from there.
|
|
1277
1475
|
|
|
1278
1476
|
```typescript
|
|
1279
1477
|
const MAX_BATCH_READ_FILES: 25
|
|
1280
1478
|
```
|
|
1281
1479
|
|
|
1282
|
-
#### `
|
|
1480
|
+
#### `MAX_READ_CALL_CHARS`
|
|
1481
|
+
|
|
1482
|
+
The most one `read_file` RESULT may carry, in chars of its JSON — every file
|
|
1483
|
+
the call returns, the envelope and the note included. That is how the request
|
|
1484
|
+
side counts a tool result, so it is how this tool counts one too
|
|
1485
|
+
({@link serializedChars}).
|
|
1486
|
+
|
|
1487
|
+
One tool result is ONE block in the request, and the request side caps a
|
|
1488
|
+
block: molecule-dev cuts any block over `MAX_TAIL_BLOCK_CHARS` (60,000) in
|
|
1489
|
+
place, keeping ~30 KB of each end. A batched read that crossed it lost its
|
|
1490
|
+
MIDDLE — the cut lands between two `"content"` values, so whole files fell
|
|
1491
|
+
out and the note in their place said only "N characters cut here" — while
|
|
1492
|
+
this tool's own note had promised each of those files that it "fits in one
|
|
1493
|
+
call, so it is not paged": X0 flash-m81 (2026-10-16) read ten e2e specs in
|
|
1494
|
+
one call (121,467 chars), lost the middle six, and bought them again in six
|
|
1495
|
+
further calls (52,908 chars).
|
|
1496
|
+
|
|
1497
|
+
So the CALL gets the ceiling the request gives it. Whole files are returned
|
|
1498
|
+
up to it; the paths that did not fit are named in `note` and listed in
|
|
1499
|
+
`files` with their own `error`, the shape every other entry has. No file is
|
|
1500
|
+
ever cut, and no read result reaches the request-side cut. A test in
|
|
1501
|
+
molecule-dev's `context-fit` asserts the two ceilings still agree.
|
|
1502
|
+
|
|
1503
|
+
```typescript
|
|
1504
|
+
const MAX_READ_CALL_CHARS: 60000
|
|
1505
|
+
```
|
|
1506
|
+
|
|
1507
|
+
#### `READ_RESULT_ENVELOPE_CHARS`
|
|
1283
1508
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1509
|
+
Room inside one read result for what is not file content: the `path`, the
|
|
1510
|
+
offset/line fields, and the note.
|
|
1511
|
+
|
|
1512
|
+
A batch sizes each file against what the call has left
|
|
1513
|
+
({@link MAX_READ_CALL_CHARS} less this), so the entry that does not fit is
|
|
1514
|
+
caught here rather than by the request-side cut.
|
|
1286
1515
|
|
|
1287
1516
|
```typescript
|
|
1288
|
-
const
|
|
1517
|
+
const READ_RESULT_ENVELOPE_CHARS: 1000
|
|
1289
1518
|
```
|
|
1290
1519
|
|
|
1291
1520
|
#### `MAX_READ_RETURN_CHARS`
|
|
1292
1521
|
|
|
1293
1522
|
The most one read_file call returns for ONE file when no window was asked
|
|
1294
|
-
for, in chars
|
|
1295
|
-
saying how to read the rest.
|
|
1523
|
+
for, in serialized chars: larger files come back as their first window, with
|
|
1524
|
+
a note saying how to read the rest.
|
|
1296
1525
|
|
|
1297
1526
|
MAX_READ_SIZE (5 MB) is a bound on what the tool will open, not on what it
|
|
1298
1527
|
should hand a model: a single batched read that returned a 1.2 MB README
|
|
1299
1528
|
put the next three provider calls at 366k tokens (~330k of them fresh)
|
|
1300
|
-
against a 120k-token context cap (X0 run x5, call 26).
|
|
1301
|
-
|
|
1302
|
-
|
|
1529
|
+
against a 120k-token context cap (X0 run x5, call 26). This is the call's
|
|
1530
|
+
own ceiling ({@link MAX_READ_CALL_CHARS}) less the room its envelope takes,
|
|
1531
|
+
so one read result — one file or twenty-five — fits inside what the request
|
|
1532
|
+
side carries without being cut.
|
|
1303
1533
|
|
|
1304
1534
|
```typescript
|
|
1305
1535
|
const MAX_READ_RETURN_CHARS: number
|
|
@@ -1422,7 +1652,8 @@ const REPEATING_CAUSE_TAIL_BYTES: 40000
|
|
|
1422
1652
|
|
|
1423
1653
|
#### `REPEATING_FAILURE_MIN`
|
|
1424
1654
|
|
|
1425
|
-
|
|
1655
|
+
DISTINCT tests that must share one signature before a running suite's repeating cause is named.
|
|
1656
|
+
A test the log prints twice, or a test that failed twice, is still one test.
|
|
1426
1657
|
|
|
1427
1658
|
```typescript
|
|
1428
1659
|
const REPEATING_FAILURE_MIN: 3
|
|
@@ -1436,6 +1667,35 @@ How many of a repeating cause's failures the note lists before it says "and N mo
|
|
|
1436
1667
|
const REPEATING_FAILURE_LISTED: 5
|
|
1437
1668
|
```
|
|
1438
1669
|
|
|
1670
|
+
#### `FAILURE_CAUSES_LISTED`
|
|
1671
|
+
|
|
1672
|
+
How many causes a finished run's summary lists before it says "and N more".
|
|
1673
|
+
|
|
1674
|
+
```typescript
|
|
1675
|
+
const FAILURE_CAUSES_LISTED: 5
|
|
1676
|
+
```
|
|
1677
|
+
|
|
1678
|
+
#### `FAILURE_CAUSE_TESTS_LISTED`
|
|
1679
|
+
|
|
1680
|
+
How many of one cause's tests that summary names before it says "and N more".
|
|
1681
|
+
|
|
1682
|
+
```typescript
|
|
1683
|
+
const FAILURE_CAUSE_TESTS_LISTED: 6
|
|
1684
|
+
```
|
|
1685
|
+
|
|
1686
|
+
#### `UNIVERSAL_CAUSE_FILES`
|
|
1687
|
+
|
|
1688
|
+
Distinct spec FILES a repeating cause must span — with every failure sharing it and nothing
|
|
1689
|
+
passing since — before a run is called broken for the whole suite.
|
|
1690
|
+
|
|
1691
|
+
One file's failures can be that file's own setup, so a cause confined to one file is never
|
|
1692
|
+
this. Across {@link UNIVERSAL_CAUSE_FILES} files, on the other hand, whatever it is is a
|
|
1693
|
+
property of the run rather than of a page.
|
|
1694
|
+
|
|
1695
|
+
```typescript
|
|
1696
|
+
const UNIVERSAL_CAUSE_FILES: 3
|
|
1697
|
+
```
|
|
1698
|
+
|
|
1439
1699
|
#### `PARSE_CHECKABLE`
|
|
1440
1700
|
|
|
1441
1701
|
Files a parse check can vouch for cheaply right after a write.
|
|
@@ -1470,9 +1730,13 @@ Peer dependencies:
|
|
|
1470
1730
|
- **`read_file` takes `paths` as well as `path`.** An agent that issues one
|
|
1471
1731
|
tool call per model round-trip pays a full round-trip per file, so a project
|
|
1472
1732
|
survey costs minutes; batched, the same reads cost one call each 25 files
|
|
1473
|
-
(`MAX_BATCH_READ_FILES`
|
|
1474
|
-
|
|
1475
|
-
path
|
|
1733
|
+
(`MAX_BATCH_READ_FILES`). One result is capped at `MAX_READ_CALL_CHARS`, the
|
|
1734
|
+
ceiling the request side puts on a single tool result: whole files are
|
|
1735
|
+
returned up to it and every path past that is named in `note` and listed as
|
|
1736
|
+
`not returned`, so a file is never handed back in part — the shape that lost
|
|
1737
|
+
the middle of a ten-file batch to the request-side cut (X0 flash-m81). Each
|
|
1738
|
+
entry carries its own content or its own error, so one bad path never fails
|
|
1739
|
+
the batch.
|
|
1476
1740
|
- **`edit_file` shows the result, so the model need not re-read.** A
|
|
1477
1741
|
successful edit returns `excerpt`: each edited region as it now reads, with
|
|
1478
1742
|
1-based line numbers (`N: text`) and a few lines of context, capped at
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command position: which program a shell segment actually RUNS, and which words are only
|
|
3
|
+
* arguments to something else.
|
|
4
|
+
*
|
|
5
|
+
* Every classifier that read a command as "this runs the suite" matched the runner's NAME
|
|
6
|
+
* anywhere in the text, so a runner named in an argument was read as an invocation: X1
|
|
7
|
+
* xr-molecule-flash-m81 (+20:03) sent
|
|
8
|
+
* `cd /workspace/fixtures/realworld/specs/api && ls && head -30 run-api-tests-hurl.sh` — two
|
|
9
|
+
* reads of a file that was already there — and the suite-overlap hold answered "a Playwright
|
|
10
|
+
* suite is already running against this app and database … wait for it", costing a minute of
|
|
11
|
+
* forced idling on a command that writes nothing and runs nothing. `cat`, `grep`, `sed -n`,
|
|
12
|
+
* `wc`, `ls` and `git show` of a runner script are the same shape.
|
|
13
|
+
*
|
|
14
|
+
* So this parser answers it in one place, for every caller: split the command at its pipeline
|
|
15
|
+
* and statement separators, take each segment's word in command position — after the wrapper
|
|
16
|
+
* prefixes a shell puts in front of it (`HOST=x sudo nice -n 10 npx`, `bash`, `timeout 280`) —
|
|
17
|
+
* and let the caller match its runner against THAT segment's text, never against the raw
|
|
18
|
+
* command. `{@link commandSegments}` returns the segments, and
|
|
19
|
+
* {@link runsInCommandPosition} asks one anchored pattern of them all.
|
|
20
|
+
*
|
|
21
|
+
* Not command position, and therefore not an invocation: a runner named as an argument
|
|
22
|
+
* (`head -30 run-api-tests-hurl.sh`, `grep -n playwright e2e/README.md`,
|
|
23
|
+
* `git show HEAD:run-api-tests.sh`), and a runner named in a heredoc body — a file a command
|
|
24
|
+
* WRITES is the caller's business, so a command with a heredoc goes through the caller's own
|
|
25
|
+
* stripper first (`withoutHeredocs` in molecule-dev's suite checks).
|
|
26
|
+
*
|
|
27
|
+
* @module
|
|
28
|
+
*/
|
|
29
|
+
/** One statement or pipeline stage of a shell command: what it runs, and with what. */
|
|
30
|
+
export interface CommandSegment {
|
|
31
|
+
/**
|
|
32
|
+
* The word in command position, its directory removed (`/usr/bin/hurl` → `hurl`): the program
|
|
33
|
+
* the shell would run once whatever wrappers stood in front of it are taken away.
|
|
34
|
+
*/
|
|
35
|
+
program: string;
|
|
36
|
+
/** The words after it, as written — quotes kept, so a quoted `"a|b"` is one word. */
|
|
37
|
+
args: readonly string[];
|
|
38
|
+
/** The program and its arguments as one line — what a runner pattern is matched against. */
|
|
39
|
+
text: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The segments of a command, each with its program and arguments — the answer every classifier
|
|
43
|
+
* that reads a command as "this runs the suite" is asking for.
|
|
44
|
+
*
|
|
45
|
+
* @param command - The shell command.
|
|
46
|
+
* @returns One entry per statement or pipeline stage that runs something, in order.
|
|
47
|
+
*/
|
|
48
|
+
export declare function commandSegments(command: string): CommandSegment[];
|
|
49
|
+
/**
|
|
50
|
+
* Whether any segment of the command runs a program whose command-position text matches
|
|
51
|
+
* `pattern` — the one question a runner-kind table asks.
|
|
52
|
+
*
|
|
53
|
+
* The pattern is matched against `program` and its arguments as one line, so it must be
|
|
54
|
+
* anchored at `^`; it must not carry the `g` flag (a pattern shared between calls would then
|
|
55
|
+
* carry its own match position from one segment to the next).
|
|
56
|
+
*
|
|
57
|
+
* @param command - The shell command.
|
|
58
|
+
* @param pattern - An anchored pattern for the runner's invocation.
|
|
59
|
+
* @returns True when a segment in command position matches.
|
|
60
|
+
*/
|
|
61
|
+
export declare function runsInCommandPosition(command: string, pattern: RegExp): boolean;
|
|
62
|
+
//# sourceMappingURL=command-position.d.ts.map
|
|
@@ -0,0 +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;CACb;AAqRD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAEjE;AA+BD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK/E"}
|