@molecule/api-ai-tools 1.11.1 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-10-21T08:55:11.822Z
6
+ Generated: 2026-10-22T00:38:26.332Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-ai-tools
@@ -360,6 +360,101 @@ interface RunnerOutputFilter {
360
360
  }
361
361
  ```
362
362
 
363
+ #### `PlaywrightReportAttachment`
364
+
365
+ One artifact the runner saved for one test, as the report records it.
366
+
367
+ ```typescript
368
+ interface PlaywrightReportAttachment {
369
+ /** The attachment's name (`trace`, `screenshot`, …). */
370
+ name: string
371
+ /** Its media type, when the runner recorded one. */
372
+ contentType: string | null
373
+ /** Where the runner saved it, as the report wrote the path. */
374
+ path: string
375
+ }
376
+ ```
377
+
378
+ #### `PlaywrightReportTest`
379
+
380
+ One failing (or flaky) test's identity and evidence, as the runner recorded them.
381
+
382
+ The identity fields are Playwright's own — never reconstructed from printed headings — so a
383
+ reader can tell exactly which test an attachment belongs to.
384
+
385
+ ```typescript
386
+ interface PlaywrightReportTest {
387
+ /** The spec's stable id, when the report carries one. */
388
+ id: string | null
389
+ /** The Playwright project the test ran in. */
390
+ project: string | null
391
+ /** The spec file, relative to the config's root directory as the report writes it. */
392
+ file: string
393
+ /** The test's declaration line. */
394
+ line: number
395
+ /** The test's declaration column. */
396
+ column: number
397
+ /** The full title path (`['describe', …, 'test title']`), empty when none is readable. */
398
+ titlePath: string[]
399
+ /** The test's own title (the last entry of {@link titlePath}). */
400
+ title: string
401
+ /** Playwright's outcome for the test: `unexpected`, `flaky`, `skipped` or `expected`. */
402
+ status: string
403
+ /** How many attempts the runner made (1 when it was not retried). */
404
+ attempts: number
405
+ /** The retry index of the attempt whose evidence is reported (0 when not retried). */
406
+ retry: number
407
+ /** That attempt's own duration, in milliseconds. */
408
+ durationMs: number
409
+ /** That attempt's error message, bounded and redacted, or null. */
410
+ error: string | null
411
+ /** The artifacts the runner saved for THAT attempt — `trace` first. */
412
+ attachments: PlaywrightReportAttachment[]
413
+ }
414
+ ```
415
+
416
+ #### `PlaywrightReportStats`
417
+
418
+ The runner's own tally, read straight from the report. Never a verdict this module derives.
419
+
420
+ ```typescript
421
+ interface PlaywrightReportStats {
422
+ /** Tests that ended as expected. */
423
+ expected: number
424
+ /** Tests the runner skipped. */
425
+ skipped: number
426
+ /** Tests that did not end as expected. */
427
+ unexpected: number
428
+ /** Tests that failed and then passed on a retry. */
429
+ flaky: number
430
+ /** The run's own duration, in milliseconds. */
431
+ durationMs: number
432
+ }
433
+ ```
434
+
435
+ #### `PlaywrightRunReport`
436
+
437
+ What one run's standard machine report says, bounded for a tool result.
438
+
439
+ A reader that needs evidence this record does not carry reads {@link path} in the sandbox.
440
+
441
+ ```typescript
442
+ interface PlaywrightRunReport {
443
+ /** How much of the report was read — see {@link PlaywrightReportStatus}. */
444
+ status: PlaywrightReportStatus
445
+ /** Where the report file is, for the full evidence. Always the runner's own file. */
446
+ path: string
447
+ /** One short phrase saying why a record is not `complete`, when it is not. */
448
+ reason?: string
449
+ /** The runner's tally, or null when the report did not carry one. */
450
+ stats: PlaywrightReportStats | null
451
+ /** The failing and flaky tests, in report order, bounded by {@link MAX_REPORTED_FAILURES}. */
452
+ failures: PlaywrightReportTest[]
453
+ /** How many failing tests did not fit the bound above. */
454
+ omittedFailures: number
455
+ }
456
+ ```
457
+
363
458
  #### `ToolSchema`
364
459
 
365
460
  JSON-schema-backed definition for a single agent tool.
@@ -444,6 +539,35 @@ interface DiagnosisRunContext {
444
539
  }
445
540
  ```
446
541
 
542
+ #### `DeferredToolCatalogOptions`
543
+
544
+ Options for exposing a small tool set while retaining access to other allowed tools.
545
+
546
+ ```typescript
547
+ interface DeferredToolCatalogOptions {
548
+ /** The caller's current permission/mode-filtered tools. Discovery never grants access. */
549
+ available: () => readonly AITool[]
550
+ /** Tools that should be offered without a discovery call. */
551
+ initialNames: ReadonlySet<string>
552
+ /** Previously loaded names, in load order; useful across turns and compaction. */
553
+ loadedNames?: readonly string[]
554
+ /** Persist names after a successful load. No tool content is passed to this callback. */
555
+ onLoad?: (names: string[]) => void
556
+ }
557
+ ```
558
+
559
+ #### `DeferredToolCatalog`
560
+
561
+ A provider-independent deferred catalog. The caller still executes and authorizes tools.
562
+
563
+ ```typescript
564
+ interface DeferredToolCatalog {
565
+ loader: AITool
566
+ /** Initial tools, loader, then requested tools in stable load order. */
567
+ select: () => AITool[]
568
+ }
569
+ ```
570
+
447
571
  #### `InstalledPackageFacts`
448
572
 
449
573
  What the filesystem says about a write target under `node_modules` — the half
@@ -914,6 +1038,18 @@ interface TraceArtifact {
914
1038
  * Absent when no group reached the threshold, and on traces read before this field existed.
915
1039
  */
916
1040
  repeated?: TraceRequestRepeat[]
1041
+ /**
1042
+ * The directory the trace was read from, relative to the root the reader was given.
1043
+ *
1044
+ * Playwright saves one directory per test attempt under the run's `outputDir`, and every artifact
1045
+ * of that attempt — `trace.zip` included — sits in it. The run's own machine report records each
1046
+ * test that wrote a trace with its attachment path, so this relative directory is the exact mark
1047
+ * binding THIS artifact to the test that wrote it, with no join by spec line needed
1048
+ * ({@link ./playwright-report.js}).
1049
+ *
1050
+ * Absent on traces read before this field existed.
1051
+ */
1052
+ dir?: string
917
1053
  }
918
1054
  ```
919
1055
 
@@ -1533,6 +1669,23 @@ What the transport did when a request never got an answer.
1533
1669
  type ConnectionFailureKind = 'timeout' | 'refused' | 'reset' | 'dns' | 'tls' | 'empty'
1534
1670
  ```
1535
1671
 
1672
+ #### `PlaywrightReportStatus`
1673
+
1674
+ How much of a report this module could account for.
1675
+
1676
+ - `complete` — the runner's stats and its suite tree both parsed: every test entry is present.
1677
+ - `partial` — a report was written but is not a whole run (Playwright's own `errors` are present,
1678
+ the suite tree is missing, or the file is past {@link MAX_REPORT_PARSE_CHARS}). What is listed
1679
+ is real; what is missing must be read at {@link PlaywrightRunReport.path}.
1680
+ - `malformed` — the file exists but is not a Playwright JSON report (truncated, wrong shape).
1681
+ Nothing in it may be treated as runner data.
1682
+ - `missing` — the run left no report (killed before `onEnd`, not a run this wrapper rewrote, or
1683
+ the file was removed). Nothing may be inferred from its absence.
1684
+
1685
+ ```typescript
1686
+ type PlaywrightReportStatus = 'complete' | 'partial' | 'malformed' | 'missing'
1687
+ ```
1688
+
1536
1689
  #### `DiscoveredSkill` _(deprecated)_
1537
1690
 
1538
1691
  Re-export SkillEntry as DiscoveredSkill for backwards compatibility.
@@ -1763,6 +1916,43 @@ function statementArgumentEnd(
1763
1916
 
1764
1917
  **Returns:** The offset to write the option at, or null when the statement cannot be placed here.
1765
1918
 
1919
+ #### `statementBoundary(command, start, end)`
1920
+
1921
+ Where a statement's own text ends, and whether it leaves a group open.
1922
+
1923
+ A statement can be written inside a subshell or a brace group, and the tokenizer attaches an
1924
+ adjacent closer to its last word because no separator comes between them: `( … | tail -25)`
1925
+ parses its last stage as `tail` with the argument `-25)`. {@link LocatedCommandSegment.end}
1926
+ therefore says one past the `)`, and a caller cutting that stage out of the command takes the
1927
+ group's closer with it — the rewritten command is then `( … 2>&1`, which no shell parses
1928
+ (xr-molecule-flash-m418 +23:31: a heredoc config plus a parenthesized Playwright pipeline came
1929
+ back as `end of file unexpected` from the background runner).
1930
+
1931
+ The parse's own group depths answer which closers belong to an enclosing group: the depth a
1932
+ statement was written at is its first character's depth (an opener is recorded at the depth
1933
+ BEFORE it opens), and every character of that statement's own words is at that depth or deeper.
1934
+ A closer at a LOWER depth closes a group opened before the statement, so it is not the
1935
+ statement's text. A character inside a quote (`-1`) is literal text and stops the walk: `grep
1936
+ 'a)b'` ends on its own quote, not on a closer.
1937
+
1938
+ The same depths answer the other dangerous cut: a stage that OPENS a group it does not close
1939
+ (`| { cat` when the `}` follows a `;`) has its closer outside the stage, so dropping the stage
1940
+ alone leaves that closer dangling.
1941
+
1942
+ ```typescript
1943
+ function statementBoundary(
1944
+ command: string,
1945
+ start: number | null,
1946
+ end: number | null,
1947
+ ): { textEnd: number; leavesGroupOpen: boolean } | null
1948
+ ```
1949
+
1950
+ - `command` — The shell command.
1951
+ - `start` — The statement's first character ({@link LocatedCommandSegment.start}).
1952
+ - `end` — One past the statement's last character ({@link LocatedCommandSegment.end}).
1953
+
1954
+ **Returns:** The offset of the first character that is not the statement's own text, and whether the statement leaves a group it opened still open; null when it cannot be placed in this command.
1955
+
1766
1956
  #### `commandTimeoutSeconds(command)`
1767
1957
 
1768
1958
  The bound a command puts on its own run: the largest `timeout <N>` any of its segments runs
@@ -2226,12 +2416,112 @@ function pipelineExitCodeNote(command: string, exitCode: number, output: string)
2226
2416
 
2227
2417
  **Returns:** One sentence naming the stage the code came from, or null.
2228
2418
 
2419
+ #### `reportCarriesIdentities(status)`
2420
+
2421
+ The report statuses for which the report's own per-test identities and attachments may be used.
2422
+
2423
+ `partial` is included because a partial report's suite tree, where it parsed, is still the
2424
+ runner's own record of which test owns which attachment; `malformed` and `missing` are not,
2425
+ because nothing about them is runner data.
2426
+
2427
+ ```typescript
2428
+ function reportCarriesIdentities(status: PlaywrightReportStatus): boolean
2429
+ ```
2430
+
2431
+ - `status` — One record's {@link PlaywrightReportStatus}.
2432
+
2433
+ **Returns:** True when the record's tests and attachments are the runner's own.
2434
+
2435
+ #### `reportTestAttachmentPaths(test)`
2436
+
2437
+ The attachment paths a stored test record carries, `trace` first.
2438
+
2439
+ ```typescript
2440
+ function reportTestAttachmentPaths(test: PlaywrightReportTest): string[]
2441
+ ```
2442
+
2443
+ - `test` — One entry of {@link PlaywrightRunReport.failures}, as stored.
2444
+
2445
+ **Returns:** Every saved path the record can prove, in its own order.
2446
+
2447
+ #### `reportTestArtifactDir(test)`
2448
+
2449
+ The directory a test result's own artifacts were saved in, or null when the report names none.
2450
+
2451
+ Playwright writes one directory per test attempt under the run's `outputDir`, and every artifact
2452
+ of that attempt — `trace.zip` included — sits in it. The directory is therefore the exact
2453
+ ownership mark for a trace: two tests' traces are never in one another's directory. A damaged
2454
+ record whose attachment entries carry no path answers null, so nothing is claimed from it.
2455
+
2456
+ ```typescript
2457
+ function reportTestArtifactDir(test: PlaywrightReportTest): string | null
2458
+ ```
2459
+
2460
+ - `test` — One entry of {@link PlaywrightRunReport.failures}, as stored.
2461
+
2462
+ **Returns:** The posix-normalized directory, or null.
2463
+
2464
+ #### `summarizePlaywrightReport(text, options)`
2465
+
2466
+ Summarize one Playwright `json` report into the bounded record a tool result carries.
2467
+
2468
+ Pure text in, record out: the caller reads the file (and decides whether it may), so this is
2469
+ testable against genuine reports and against malformed controls alike.
2470
+
2471
+ ```typescript
2472
+ function summarizePlaywrightReport(
2473
+ text: string,
2474
+ options: { path: string; sanitize?: (text: string) => string },
2475
+ ): PlaywrightRunReport
2476
+ ```
2477
+
2478
+ - `text` — The report file's text, exactly as written.
2479
+ - `options` — Where the file is, and the consumer's redactor for error text.
2480
+ - `options.path` — The report file's path, carried on the record for full evidence.
2481
+ - `options.sanitize` — Redactor applied to error text (defaults to the identity).
2482
+
2483
+ **Returns:** The bounded record; never a verdict.
2484
+
2485
+ #### `commandWritesReportTo(command, expectedPath)`
2486
+
2487
+ The report path a command was launched with, when it is the one this platform sets.
2488
+
2489
+ Read back from the launched script (and from a completed task's own command) so a record written
2490
+ before an API restart is still found: the path is the task's own id derived by
2491
+ {@link playwrightReportPathFor}, never a path parsed out of the executor's command.
2492
+
2493
+ ```typescript
2494
+ function commandWritesReportTo(command: string, expectedPath: string): boolean
2495
+ ```
2496
+
2497
+ - `command` — The command as it was launched.
2498
+ - `expectedPath` — The one path this task's report may be at.
2499
+
2500
+ **Returns:** True when the command sets {@link PLAYWRIGHT_REPORT_ENV} to that exact path.
2501
+
2502
+ #### `playwrightReportPathFor(taskId)`
2503
+
2504
+ The report file a background task's own scratch files live beside.
2505
+
2506
+ Derived from the task id, never from the command: the id is unique per launch, so two runs can
2507
+ never read one another's report, and the path survives a process restart the same way the task's
2508
+ log and exit file do.
2509
+
2510
+ ```typescript
2511
+ function playwrightReportPathFor(taskId: string): string
2512
+ ```
2513
+
2514
+ - `taskId` — The `mol-bg-…` handle the launch returned.
2515
+
2516
+ **Returns:** The report file's absolute path.
2517
+
2229
2518
  #### `startsServerProgram(command)`
2230
2519
 
2231
2520
  Whether a command, read from its TEXT alone, starts a server that stays up in the foreground.
2232
2521
 
2233
2522
  The over-budget reader's shape: at that point the command has already run, and only its text is
2234
- left to say whether "run a smaller unit" was ever the right advice.
2523
+ left to say whether "run a smaller unit" was ever the right advice. Inline/stdin programs
2524
+ remain unclassified and use the normal bounded command runner.
2235
2525
 
2236
2526
  ```typescript
2237
2527
  function startsServerProgram(command: string): boolean
@@ -2244,7 +2534,9 @@ function startsServerProgram(command: string): boolean
2244
2534
  #### `foregroundServerCommand(command, readScript)`
2245
2535
 
2246
2536
  A FOREGROUND command that starts a server, including one that only names a script whose SOURCE
2247
- imports the app's server and calls its `create()`/`listen()`.
2537
+ imports the app's server and calls its `create()`/`listen()`. Inline/stdin programs
2538
+ (`node -e …`, `python3 -c …`) use normal bounded execution: interpreting arbitrary
2539
+ program text is outside this filename/script preflight's contract.
2248
2540
 
2249
2541
  The script read is best-effort: a path the backend will not answer for is a command this reading
2250
2542
  cannot classify, never a refusal. A backgrounded launch, a test runner and a test file are all
@@ -2539,6 +2831,24 @@ function buildAgentPrompt(ctx: PromptContext): string
2539
2831
 
2540
2832
  **Returns:** Fully assembled system prompt text for the coding agent.
2541
2833
 
2834
+ #### `createDeferredToolCatalog(options)`
2835
+
2836
+ Offer common tools and let the model load other schemas by exact name.
2837
+
2838
+ This is ordinary allowlist selection, not semantic routing or authorization.
2839
+ Pass tools already filtered by the current mode and permissions. Loading never
2840
+ executes a tool; the caller must keep its normal execution-time guards. Loaded
2841
+ schemas append in request order and stay available, avoiding an LRU that changes
2842
+ the schema prefix on every request. Only names need persistence across turns.
2843
+
2844
+ ```typescript
2845
+ function createDeferredToolCatalog(options: DeferredToolCatalogOptions): DeferredToolCatalog
2846
+ ```
2847
+
2848
+ - `options` — Allowed tools, initial selection and optional durable load state.
2849
+
2850
+ **Returns:** A loader tool and the current provider-facing selection.
2851
+
2542
2852
  #### `taskStopCommand(backend, taskId)`
2543
2853
 
2544
2854
  The command that stops a running background task, read from the sandbox's own pid files.
@@ -2996,6 +3306,24 @@ function redactSecretsInCode(s: string): string
2996
3306
 
2997
3307
  **Returns:** A redacted copy that preserves ordinary code verbatim.
2998
3308
 
3309
+ #### `addedRedactionMask(next, previous)`
3310
+
3311
+ The redaction mask `next` adds over `previous`, or null when it adds none.
3312
+
3313
+ `previous` is the file's previous content for `write_file`, and the replacement's own
3314
+ `old_string` for `edit_file` — an edit that carries an existing mask through (a file that
3315
+ already had one, read back and rewritten) adds no occurrence. A new occurrence may
3316
+ be copied output or intentional source; the caller declares the latter explicitly.
3317
+
3318
+ ```typescript
3319
+ function addedRedactionMask(next: string, previous: string): string | null
3320
+ ```
3321
+
3322
+ - `next` — The content about to be written (or the replacement's `new_string`).
3323
+ - `previous` — The content it replaces, already on disk (or the `old_string`).
3324
+
3325
+ **Returns:** The added mask as written (`'[REDACTED]'`, `"[REDACTED]"`, `=[REDACTED]`), or null.
3326
+
2999
3327
  #### `printsOnlySource(command)`
3000
3328
 
3001
3329
  Whether a shell command only PRINTS source files (`cat a.tsx`, `sed -n '1,40p' x.ts`,
@@ -3012,6 +3340,35 @@ function printsOnlySource(command: string): boolean
3012
3340
 
3013
3341
  **Returns:** True when the command prints source files, with only literal headings and filters.
3014
3342
 
3343
+ #### `isReadOnlyInspection(command)`
3344
+
3345
+ Whether a shell command only INSPECTS the workspace WITHOUT printing a file's contents:
3346
+ it prints source files (a pure literal read, {@link printsOnlySource}), lists names
3347
+ (`ls`, `find`), or counts lines (`wc`) — joined by `;`, `&&` or `|`, with literal
3348
+ `echo`/`printf` headings and `cd`.
3349
+
3350
+ Its output is code or names, not an env dump, so it gets the code-safe redaction
3351
+ ({@link redactSecretsInCode}) instead of the name-keyed env-dump passes. Without this,
3352
+ ordinary code values such as `tokenKey: 'jwtToken'` in a mixed source read and
3353
+ `ls | head` command would be masked by the environment-dump rules.
3354
+
3355
+ A RECURSIVE SEARCH IS NOT INSPECTION (`grep -rn x .`, `rg x src/`): its output is the
3356
+ content of whichever files matched, including `.env` files and JSON secret dumps, so it
3357
+ keeps the full grade. A path with no extension is not evidence that it is a directory —
3358
+ `/dev/stdin` and an ordinary `secrets` file read the same way.
3359
+
3360
+ Env dumps keep the full grade: `.env` anywhere in the command, `env`/`printenv`, a
3361
+ non-literal or redirecting form, and an interpreter one-liner (`node -e`, `python -c`)
3362
+ all return false.
3363
+
3364
+ ```typescript
3365
+ function isReadOnlyInspection(command: string): boolean
3366
+ ```
3367
+
3368
+ - `command` — The shell command.
3369
+
3370
+ **Returns:** True when the command only reads or lists workspace content.
3371
+
3015
3372
  #### `isEnvFilePath(path)`
3016
3373
 
3017
3374
  Whether a path is an env file, for which {@link redactSecrets}' full env-dump
@@ -3087,7 +3444,7 @@ function outputRedirectTarget(command: string): string | null
3087
3444
 
3088
3445
  **Returns:** The target, or null (`/dev/null` and `&1`/`&2` are not files).
3089
3446
 
3090
- #### `streamingBackgroundCommand(command, context)`
3447
+ #### `streamingBackgroundCommand(command, context, reportPath)`
3091
3448
 
3092
3449
  Rewrite a command about to run in the background so its log grows while it
3093
3450
  runs. Two shapes left the log empty until exit, and an empty log is what
@@ -3116,13 +3473,44 @@ _(description truncated — read the full text in `node_modules/@molecule/api-ai
3116
3473
  function streamingBackgroundCommand(
3117
3474
  command: string,
3118
3475
  context?: DiagnosisRunContext,
3119
- ): { command: string; changes: string[]; error?: string }
3476
+ reportPath?: string,
3477
+ ): { command: string; changes: string[]; reportPath?: string; error?: string }
3120
3478
  ```
3121
3479
 
3122
3480
  - `command` — The command as the executor sent it.
3123
3481
  - `context` — What the caller knows beyond the command: the tests the person's request excludes by name ({@link DiagnosisRunContext}). A `--grep-invert` of exactly those is the request's own scope, not a diagnosis, so it keeps the suite's retries on a deployed proof (xr-molecule-flash-m170 +33:16).
3482
+ - `reportPath` — Where this run should write Playwright's standard `json` report, when the caller keeps one ({@link ./playwright-report.js}). The reporter is added to the run's own reporter set, never in place of one, and its output goes to that file through `PLAYWRIGHT_JSON_OUTPUT_FILE` — so the log, the executors' own reporters and every verdict stay exactly as they are. Omitted, or a run whose reporter set is not this function's to place (already names `json`, sets the variable itself, or whose runner cannot be located), leaves the command untouched and the result's `reportPath` unset.
3483
+
3484
+ **Returns:** The command to run, one sentence per change made (empty when none), and the report path when one was actually wired — or `error` when the command starts the suite more than once.
3124
3485
 
3125
- **Returns:** The command to run and one sentence per change made (empty when none), or `error` when the command starts the suite more than once.
3486
+ #### `withPlaywrightRunReport(command, reportPath)`
3487
+
3488
+ Put Playwright's standard `json` report on a FOREGROUND run that already names its own reporters.
3489
+
3490
+ A background run is rewritten onto the platform's reporter anyway ({@link
3491
+ streamingBackgroundCommand}), so adding the machine report there costs nothing. A foreground run
3492
+ is not: its reporters are either the command's own flags or the suite's config, and replacing a
3493
+ config reporter would stop writing the artifact the executor configured. So this only ever
3494
+ APPENDS `json` to a `--reporter` set the command already wrote — the log keeps every printing
3495
+ reporter it had, the executor's file reporters keep their place, and the standard report goes to
3496
+ {@link PLAYWRIGHT_REPORT_ENV}'s file.
3497
+
3498
+ A command that names no reporter at all is left exactly as written: its reporters are the suite
3499
+ config's, and this tool does not rewrite those. A command that already names `json`, or sets
3500
+ `PLAYWRIGHT_JSON_OUTPUT_FILE` itself, already has a report of its own — a path the executor chose
3501
+ is never overwritten.
3502
+
3503
+ ```typescript
3504
+ function withPlaywrightRunReport(
3505
+ command: string,
3506
+ reportPath: string,
3507
+ ): { command: string; reportPath: string | null }
3508
+ ```
3509
+
3510
+ - `command` — The command the executor sent, after every other rewrite.
3511
+ - `reportPath` — The file this run's machine report should be written to.
3512
+
3513
+ **Returns:** The command to run and the report path when one was wired; `reportPath` is null when the run was left untouched and no report may be expected.
3126
3514
 
3127
3515
  #### `suiteRunStatements(command)`
3128
3516
 
@@ -3291,6 +3679,10 @@ run writes still holds every failure (xr-molecule-flash-m121 — a `| tail -5; e
3291
3679
  tail, and a 95-second walk's log held only the tally while the platform's own hold had handed
3292
3680
  that command back).
3293
3681
 
3682
+ The command around the dropped stages is left as written: a group they sit in keeps its closer
3683
+ (`( … | tail -25)` → `( … )`, never `( …` — xr-molecule-flash-m418 +23:31), and a stage the cut
3684
+ would leave a closer dangling inside is not dropped at all.
3685
+
3294
3686
  ```typescript
3295
3687
  function stripTrailingSuiteFilters(command: string): SuiteFilterStrip
3296
3688
  ```
@@ -4288,6 +4680,59 @@ is a runaway detector, not a performance budget.
4288
4680
  const INLINE_SCRIPT_BUDGET_MS: 20000
4289
4681
  ```
4290
4682
 
4683
+ #### `PLAYWRIGHT_REPORT_ENV`
4684
+
4685
+ The environment variable Playwright's built-in `json` reporter takes its output path from
4686
+ (`resolveOutputFile("JSON", …)`), resolved against the runner's own working directory. An
4687
+ absolute path is used here, so the file lands in the run's scratch area whatever directory the
4688
+ suite runs from.
4689
+
4690
+ ```typescript
4691
+ const PLAYWRIGHT_REPORT_ENV: 'PLAYWRIGHT_JSON_OUTPUT_FILE'
4692
+ ```
4693
+
4694
+ #### `PLAYWRIGHT_REPORT_SUFFIX`
4695
+
4696
+ The file name a background task's report is written to, beside its own log.
4697
+
4698
+ ```typescript
4699
+ const PLAYWRIGHT_REPORT_SUFFIX: '.playwright.json'
4700
+ ```
4701
+
4702
+ #### `MAX_REPORT_PARSE_CHARS`
4703
+
4704
+ How big a report may be before this module refuses to summarize it. The file stays readable at
4705
+ its path; the record only says so. A whole 139-test suite's report is well under a megabyte; a
4706
+ report past this is not one a tool result should carry.
4707
+
4708
+ ```typescript
4709
+ const MAX_REPORT_PARSE_CHARS: 8000000
4710
+ ```
4711
+
4712
+ #### `MAX_REPORTED_FAILURES`
4713
+
4714
+ How many failing tests a record lists before the rest are counted in `omittedFailures`.
4715
+
4716
+ ```typescript
4717
+ const MAX_REPORTED_FAILURES: 12
4718
+ ```
4719
+
4720
+ #### `MAX_REPORTED_ATTACHMENTS`
4721
+
4722
+ How many attachments one failing test keeps in the record (`trace` first).
4723
+
4724
+ ```typescript
4725
+ const MAX_REPORTED_ATTACHMENTS: 4
4726
+ ```
4727
+
4728
+ #### `MAX_REPORTED_ERROR_CHARS`
4729
+
4730
+ How much of one failure's own error text the record keeps.
4731
+
4732
+ ```typescript
4733
+ const MAX_REPORTED_ERROR_CHARS: 400
4734
+ ```
4735
+
4291
4736
  #### `TOOL_SCHEMAS`
4292
4737
 
4293
4738
  Canonical tool schemas shared by the agent runtime and documentation.
@@ -4310,7 +4755,10 @@ const BACKGROUNDED: RegExp
4310
4755
  A program that SERVES: the scaffold's entry (`server.ts`/`server.js`), a package manager's
4311
4756
  `start`/`dev`/`serve`/`preview` script, a Vite dev or preview server, `next start|dev`, or a
4312
4757
  Python WSGI server. Matched against a command segment's own text, and against a script's SOURCE
4313
- when the command only names the script file.
4758
+ when the command only names the script file — but NEVER against an inline program's code
4759
+ (`node -e …`, `python3 -c …`), where this text is the user's program rather than a file being
4760
+ run: `require('…/node_modules/vite')` imports a module, it does not start a dev server
4761
+ (xr-molecule-flash-m391 +13:13, refused as "node starts a server" for exactly that line).
4314
4762
 
4315
4763
  ```typescript
4316
4764
  const SERVER_PROGRAM: RegExp
@@ -4915,6 +5363,11 @@ Peer dependencies:
4915
5363
  as a broken tool and routes around, taking its verification with it. Use
4916
5364
  `guardAITool` to give tools built elsewhere the same treatment, passing
4917
5365
  `redactError` so a thrown message is masked by your own redactor.
5366
+ - **Defer occasional tools** with `createDeferredToolCatalog`: pass your current
5367
+ permission-filtered tools and a small initial name set, offer `catalog.select()`
5368
+ to the model, and execute `catalog.loader` like any other tool. Loading only
5369
+ exposes schemas, never grants permission or runs a tool. Persist its loaded
5370
+ names with `onLoad` to keep them available across turns and compaction.
4918
5371
  - **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
4919
5372
  should not receive `write_file`/`exec_command`.
4920
5373
  - Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
@@ -205,6 +205,39 @@ export declare function locatedCommandSegments(command: string): LocatedCommandS
205
205
  * @returns The offset to write the option at, or null when the statement cannot be placed here.
206
206
  */
207
207
  export declare function statementArgumentEnd(command: string, start: number | null, end: number | null): number | null;
208
+ /**
209
+ * Where a statement's own text ends, and whether it leaves a group open.
210
+ *
211
+ * A statement can be written inside a subshell or a brace group, and the tokenizer attaches an
212
+ * adjacent closer to its last word because no separator comes between them: `( … | tail -25)`
213
+ * parses its last stage as `tail` with the argument `-25)`. {@link LocatedCommandSegment.end}
214
+ * therefore says one past the `)`, and a caller cutting that stage out of the command takes the
215
+ * group's closer with it — the rewritten command is then `( … 2>&1`, which no shell parses
216
+ * (xr-molecule-flash-m418 +23:31: a heredoc config plus a parenthesized Playwright pipeline came
217
+ * back as `end of file unexpected` from the background runner).
218
+ *
219
+ * The parse's own group depths answer which closers belong to an enclosing group: the depth a
220
+ * statement was written at is its first character's depth (an opener is recorded at the depth
221
+ * BEFORE it opens), and every character of that statement's own words is at that depth or deeper.
222
+ * A closer at a LOWER depth closes a group opened before the statement, so it is not the
223
+ * statement's text. A character inside a quote (`-1`) is literal text and stops the walk: `grep
224
+ * 'a)b'` ends on its own quote, not on a closer.
225
+ *
226
+ * The same depths answer the other dangerous cut: a stage that OPENS a group it does not close
227
+ * (`| { cat` when the `}` follows a `;`) has its closer outside the stage, so dropping the stage
228
+ * alone leaves that closer dangling.
229
+ *
230
+ * @param command - The shell command.
231
+ * @param start - The statement's first character ({@link LocatedCommandSegment.start}).
232
+ * @param end - One past the statement's last character ({@link LocatedCommandSegment.end}).
233
+ * @returns The offset of the first character that is not the statement's own text, and whether
234
+ * the statement leaves a group it opened still open; null when it cannot be placed in this
235
+ * command.
236
+ */
237
+ export declare function statementBoundary(command: string, start: number | null, end: number | null): {
238
+ textEnd: number;
239
+ leavesGroupOpen: boolean;
240
+ } | null;
208
241
  /**
209
242
  * The bound a command puts on its own run: the largest `timeout <N>` any of its segments runs
210
243
  * under (`timeout 280 hurl --test …` → 280), or null when it carries none.
@@ -1 +1 @@
1
- {"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;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;AAgSD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3D;AAynBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AA8GD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAIjE;AAED,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,iGAAiG;IACjG,IAAI,EAAE,MAAM,CAAA;CACb;AAmFD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,EAAE,CAGnE;AAmCD;;;;;;;;;GASG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IAC9B,0FAA0F;IAC1F,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;;;OAGG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB;;;;OAIG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,EAAE,CAE/E;AAmDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,MAAM,GAAG,IAAI,GACjB,MAAM,GAAG,IAAI,CAyDf;AA4GD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOpE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,GAC1C;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAoD7C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK/E"}
1
+ {"version":3,"file":"command-position.d.ts","sourceRoot":"","sources":["../src/command-position.ts"],"names":[],"mappings":"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"}