@molecule/api-ai-tools 1.16.3 → 1.16.4

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.
Files changed (2) hide show
  1. package/README.md +161 -136
  2. 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-11-04T11:19:09.206Z
6
+ Generated: 2026-11-04T14:19:49.511Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-ai-tools
@@ -1266,165 +1266,76 @@ Allows consumers to customize security, callbacks, and tool selection.
1266
1266
 
1267
1267
  ```typescript
1268
1268
  interface ToolBuildConfig {
1269
- /** Which tools to include. Defaults to all. */
1269
+ /** Which tools to include. */
1270
1270
  include?: string[]
1271
1271
 
1272
- /** Which tools to exclude. Applied after include. */
1272
+ /** Which tools to exclude. */
1273
1273
  exclude?: string[]
1274
1274
 
1275
- /** Whether to validate paths stay within projectRoot. Default: true. */
1275
+ /** Whether to validate paths stay within projectRoot. */
1276
1276
  pathGuards?: boolean
1277
1277
 
1278
- /** Whether to check symlinks resolve within projectRoot. Default: false (sandbox-only). */
1278
+ /** Whether to check symlinks resolve within projectRoot. */
1279
1279
  symlinkGuards?: boolean
1280
1280
 
1281
- /** Whether to redact secrets in file reads and command output. Default: true. */
1281
+ /** Whether to redact secrets in file reads and command output. */
1282
1282
  redactSecrets?: boolean
1283
1283
 
1284
- /** Whether to block dangerous shell commands (env dumps, /proc access). Default: false. */
1284
+ /** Whether to block dangerous shell commands (env dumps, /proc access). */
1285
1285
  blockDangerousCommands?: boolean
1286
1286
 
1287
- /**
1288
- * Consumer-specific command guard for `exec_command`, checked BEFORE execution (after
1289
- * the built-in dangerous-command check). Return an error string to block the command —
1290
- * it is returned to the model verbatim, so make it actionable (say what to do instead) —
1291
- * or `null`/`undefined` to allow it. Keeps environment-specific rules (e.g. an IDE
1292
- * sandbox forbidding installs that would break its preinstalled library) out of this
1293
- * shared package.
1294
- *
1295
- * @param command - The shell command the model asked to run.
1296
- * @param cwd - The resolved working directory it would run in.
1297
- * @returns An error string to block, or null/undefined to allow.
1298
- */
1287
+ /** Consumer-specific command guard for `exec_command`, checked BEFORE execution (after the built-in dangerous-command check). */
1299
1288
  blockCommand?: (command: string, cwd: string) => string | null | undefined
1300
1289
 
1301
- /**
1302
- * Timeout (ms) for a single `exec_command` run. `exec_command` legitimately
1303
- * runs LONG — `npm install`, a production build, a test suite — so the default
1304
- * is generous (2 min); the old 30 s hardcap killed those spuriously. A consumer
1305
- * that wraps tool calls in its own outer timeout should set this to match (or
1306
- * slightly exceed) that budget so its own timeout is the effective bound and
1307
- * produces the nicer "tool timed out" message. Quick commands are unaffected —
1308
- * this is only the ceiling before a wedged command is killed.
1309
- */
1290
+ /** Timeout (ms) for a single `exec_command` run. */
1310
1291
  execTimeoutMs?: number
1311
1292
 
1312
- /**
1313
- * Budget (ms) for a single `exec_command`, passed to `backend.run` as
1314
- * `budgetMs`: the backend runs the command under `timeout` in its own shell,
1315
- * so when it overruns it is stopped there and the tool still returns
1316
- * everything it printed until then (exit code 124 plus an `error` naming
1317
- * the limit). Without this, an outer per-tool timeout races the run and
1318
- * discards minutes of build or test output along with the result. Set it a
1319
- * little under that outer timeout. Unset = no budget.
1320
- */
1293
+ /** Budget (ms) for a single `exec_command`, passed to `backend.run` as `budgetMs`: the backend runs the command under `timeout` in its own shell, so when it overr… */
1321
1294
  commandBudgetMs?: number
1322
1295
 
1323
- /**
1324
- * Maximum time (ms) one `wait_for_task` call may wait, independently of the foreground
1325
- * {@link commandBudgetMs}. The caller's requested `timeout` is honoured up to this budget.
1326
- * Leave unset to keep the legacy ceiling: `commandBudgetMs` (or 290 s) less a 10 s result
1327
- * margin. A host that raises this must also give the tool call a longer outer watchdog.
1328
- */
1296
+ /** Maximum time (ms) one `wait_for_task` call may wait, independently of the foreground {@link commandBudgetMs}. */
1329
1297
  waitBudgetMs?: number
1330
1298
 
1331
- /**
1332
- * Opt in to one partial diagnostic return for a task driving this known deployed URL.
1333
- * Return null when the task already returned a wait result or its history is unknown.
1334
- * Only a real suite command with a complete inline failure report can yield; it remains
1335
- * running, with no exit code or completed proof. Absent leaves ordinary waits unchanged.
1336
- */
1299
+ /** Opt in to one partial diagnostic return for a task driving this known deployed URL. */
1337
1300
  yieldOnFirstFailureFor?: (taskId: string) => string | null
1338
1301
 
1339
- /**
1340
- * How long (ms) exec_command waits for a command it backgrounded only because the
1341
- * command asked for more than {@link commandBudgetMs}, before handing back a task
1342
- * id; one that finishes inside it returns like a foreground run. Default 45000.
1343
- */
1302
+ /** How long (ms) exec_command waits for a command it backgrounded only because the command asked for more than {@link commandBudgetMs}, before handing back a task… */
1344
1303
  overCeilingGraceMs?: number
1345
1304
 
1346
- /**
1347
- * Directory names `search_files` and `find_files` skip (VS Code
1348
- * `search.exclude` semantics). Defaults to `DEFAULT_SEARCH_EXCLUDED_DIRS`
1349
- * (node_modules, VCS dirs, build output). Pass the consumer's per-project
1350
- * setting so every search surface shares ONE synchronized set.
1351
- */
1305
+ /** Directory names `search_files` and `find_files` skip (VS Code `search.exclude` semantics). */
1352
1306
  searchExcludedDirs?: string[]
1353
1307
 
1354
- /**
1355
- * Whether a LARGE HTML document should come back as its OUTLINE — the head's
1356
- * tags and the tags that open each body section, one line each, plus a note
1357
- * naming the offset/limit that returns the whole document — instead of its
1358
- * whole text. Over {@link MAX_HTML_INLINE_CHARS}, and only when the read named
1359
- * no line window.
1360
- *
1361
- * A getter, not a boolean, because the answer belongs to the TURN, not to the
1362
- * tool set: a host that plans first and builds after wants an outline while the
1363
- * executor is researching (where a read it cannot act on is pure context cost)
1364
- * and the document itself while it is writing the page. Unset means every big
1365
- * HTML read returns its text, which is what a host with no such phases wants.
1366
- *
1367
- * @returns True when a large HTML read should be outlined rather than returned.
1368
- */
1308
+ /** Whether a LARGE HTML document should come back as its OUTLINE — the head's tags and the tags that open each body section, one line each, plus a note naming the… */
1369
1309
  outlineLargeHtml?: () => boolean
1370
1310
 
1371
- /**
1372
- * The test titles the person's request EXCLUDES by name (molecule-dev's `excludedTestTitles`),
1373
- * asked when a finished suite run's cause note is built. Their failures are not causes to fix:
1374
- * the note drops them, says so at the end, and inverts them out of the narrowed re-run it hands
1375
- * over — a result must never name a test beside "it does not count" (an executor once spent a
1376
- * turn and an edit on the excluded test).
1377
- *
1378
- * A getter, not an array, because the request is read per turn while the tool set is built
1379
- * once. Unset means no test is excluded.
1380
- *
1381
- * @returns The quoted titles the request carves out.
1382
- */
1311
+ /** The test titles the person's request EXCLUDES by name (molecule-dev's `excludedTestTitles`), asked when a finished suite run's cause note is built. */
1383
1312
  excludedTestTitles?: () => readonly string[]
1384
1313
 
1385
- /**
1386
- * The `NAME=value` settings the person's request REQUIRES of a suite run (molecule-dev's
1387
- * `requiredRunSettings` — its mode, say), asked when the cause note composes a narrowed re-run
1388
- * of a finished run's failures. A re-run composed from the executor's own command inherits what
1389
- * that command set — and nothing it left out, so a run that measured the suite in `spa` handed
1390
- * back a re-run that would measure `spa` again (the request names `TEST_MODE=fullstack`, and
1391
- * both the run and its re-run omitted it).
1392
- *
1393
- * A getter, not an array: the request is read per turn while the tool set is built once, and
1394
- * what the suite's own files read is the consumer's reading. Unset answers "nothing required".
1395
- *
1396
- * @param command - The command the finished run was started with.
1397
- * @param cwd - The resolved working directory it ran in.
1398
- * @returns The settings to put on a re-run of that command.
1399
- */
1314
+ /** The `NAME=value` settings the person's request REQUIRES of a suite run (molecule-dev's `requiredRunSettings` — its mode, say), asked when the cause note compos… */
1400
1315
  requiredSuiteEnv?: (
1401
1316
  command: string,
1402
1317
  cwd: string,
1403
1318
  ) => Promise<readonly { name: string; value: string }[] | null | undefined>
1404
1319
 
1405
- /**
1406
- * The supplied suite's own budget, when the Playwright config a command would load sets
1407
- * different settings, asked BEFORE the run executes. The consumer knows where the suite and its
1408
- * base config live; this shared package does not, so the reading is the consumer's and the
1409
- * mechanics — putting the flags on the runner's own arguments, before the pipeline and outside
1410
- * any redirect or group closer, and pointing `--config` at the derived config that carries the
1411
- * settings no flag can — are this tool's.
1412
- *
1413
- * Called for a Playwright suite command only, and only the LAST suite step is touched. A run
1414
- * that already keeps the suite's settings, or a sandbox with no supplied suite, answers `null`.
1415
- * Unset (or a hook that throws) changes nothing: the command runs as the model wrote it.
1416
- *
1417
- * @param command - The shell command, as the model sent it.
1418
- * @param cwd - The resolved working directory it will run in.
1419
- * @returns The flags, the derived config and the sentence, or null when nothing is put back.
1420
- */
1320
+ /** The supplied suite's own budget, when the Playwright config a command would load sets different settings, asked BEFORE the run executes. */
1421
1321
  suiteBudget?: (command: string, cwd: string) => Promise<SuiteBudgetPin | null | undefined>
1422
1322
 
1423
- /**
1424
- * A whole walk's duration in ms, as the consumer measured it. A suite run the executor detached
1425
- // … truncated — the full declaration is in node_modules/@molecule/api-ai-tools/dist/types.d.ts
1323
+ /** A whole walk's duration in ms, as the consumer measured it. */
1324
+ suiteRunMs?: (command: string, cwd: string) => Promise<number | null | undefined>
1325
+
1326
+ /** Post-write hook (e.g. auto-format via Prettier/ESLint). */
1327
+ onAfterWrite?: (path: string) => Promise<void>
1328
+
1329
+ /** Diff tracking callback. */
1330
+ onFileDiff?: (event: FileDiffEvent) => void
1331
+
1332
+ /** Structural change callback. */
1333
+ onFileChange?: (event: FileChangeEvent) => void
1334
+ }
1426
1335
  ```
1427
1336
 
1337
+ _(Member comments are shortened to their first sentence to fit; the full declaration is in `node_modules/@molecule/api-ai-tools/dist/types.d.ts`.)_
1338
+
1428
1339
  #### `FileDiffEvent`
1429
1340
 
1430
1341
  Payload emitted when a tracked file changes contents.
@@ -2936,8 +2847,24 @@ deployed URL, where a network blip is likeliest and the retries it dropped are t
2936
2847
  absorb it).
2937
2848
 
2938
2849
  `--max-failures=0` is Playwright's own "no cap" ({@link boundsFailures}), so it is not a
2939
-
2940
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/suite-overlap.d.ts`.)_
2850
+ diagnosis. A command that starts no Playwright run is not one either (false): the question is
2851
+ about a run already read as a Playwright suite.
2852
+
2853
+ A `--grep-invert` is only a narrowing when it excludes MORE than the request already excludes.
2854
+ When the caller passes those approved titles ({@link DiagnosisRunContext}) and the inverted
2855
+ pattern names one of them — the request's own "except …" scope written as the flag, which
2856
+ molecule-dev's `invertDecision` reads the same way — the run still walks the whole proof scope,
2857
+ and it is not a diagnosis. The deployed proof carried exactly
2858
+ that exclusion, the rewriter added `--retries=0` to it, and the run lost the suite's retries on
2859
+ the one walk where a network blip is likeliest.
2860
+
2861
+ A command the PLATFORM composed and launched AS the graded proof keeps the suite's retries for
2862
+ the SELECTION it composed — the failures a redeploy re-runs, named as files and `file:line`
2863
+ ({@link DiagnosisRunContext} `platformProof`). Only that selection is excused: a cap, a title
2864
+ filter, a last-failed set and a local targeted selection stay diagnoses, so the mark cannot turn a walk of
2865
+ part of the suite into the graded measurement. Which targets are local is
2866
+ {@link suiteCommandTarget}'s answer, and the launch rewrite asks it on the same reading
2867
+ ({@link ./utilities.js} `streamingBackgroundCommand`).
2941
2868
 
2942
2869
  ```typescript
2943
2870
  function isDiagnosisRun(command: string, context?: DiagnosisRunContext): boolean
@@ -3128,7 +3055,11 @@ A path INSIDE the link is still decided by what resolves there: a link into a
3128
3055
  real tree is refused, because removing or writing through it reaches the
3129
3056
  install.
3130
3057
 
3131
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/tools.d.ts`.)_
3058
+ The restore route is named because the model that has ALREADY clobbered a file
3059
+ (this refusal is too late for it) is the one who needs it, and because the
3060
+ obvious repair — `npm install <pkg>` — is itself refused in the pre-installed
3061
+ sandbox. `npm pack` + a `tar` extraction over the package directory is the
3062
+ repair both guards leave alone.
3132
3063
 
3133
3064
  ```typescript
3134
3065
  function installedPackageWriteRefusal(
@@ -3176,8 +3107,15 @@ or still in flight when the test ended; it is kept too, but as what it is, not a
3176
3107
  A trace.zip holds ONE trace member per browser context the test used (beside the runner's own
3177
3108
  `test.trace`), and the archive's member order is not the test's chronology. Each member is read
3178
3109
  as its own context: actions and requests keep their context id, requests and frame snapshots
3110
+ keep the pageId Playwright records, and the failing assertion's page — the page its own step id
3111
+ ran on — decides which actions, snapshots and requests become the test's row. What the test's
3112
+ other browser contexts recorded is reported apart, as `otherContexts`.
3179
3113
 
3180
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/trace-artifacts.d.ts`.)_
3114
+ A request answered 4xx by the app's OWN API also keeps what the page SENT and the first of what
3115
+ came back: Playwright stores either inline (`text`) or in a resource entry (`_file`), and both
3116
+ are read. That is where a wrapped body shows: a helper passed
3117
+ `{ data: body }` as app-http's second argument, so every POST/PUT was `{"data":{…}}` and the API
3118
+ validated `{}`. Status alone said only "422".
3181
3119
 
3182
3120
  ```typescript
3183
3121
  function traceArtifactsScript(): string
@@ -3362,6 +3300,38 @@ is `data`, the note names the call shape that produces it.
3362
3300
  Every row opens with the test's LAST user action before the failing assertion and the requests
3363
3301
  that action caused ({@link TraceArtifact.lastAction}) — started after it, before the assertion,
3364
3302
  the app's own API calls first, each with its status and the first 200 characters of its response,
3303
+ then where the page went next. The trace's action clock and each request's `_monotonicTime` are
3304
+ the same clock, so "caused" is the trace's own fact rather than a guess from recording order.
3305
+ A run failed 13 then 12 tests on one unnamed cause while every row led with
3306
+ `GET /api/tags → 200` — the Home page's own fetch after the redirect — and filled its answered
3307
+ slots with the PWA's `/workbox-*.js` and its `/icons/*.svg`; the register `POST /api/users`
3308
+ (answered 201, the page still rendering signed-out) never appeared. With no action clock, the
3309
+ row falls back to {@link TraceArtifact.lead}: the page's last answered fetch/xhr.
3310
+
3311
+ The action, the URL and the requests are the FAILING ASSERTION'S PAGE's ({@link
3312
+ TraceArtifact.lastAction}), never the archive's last context: a test that creates its data in a
3313
+ second browser context writes that context's click and `/editor` snapshot into the same zip, and
3314
+ reading the concatenation made them the failing page. The other
3315
+ contexts' requests are named separately as set-up work. When the trace holds more than one used
3316
+ context and the assertion's page cannot be identified, the note lists the requests and makes NO
3317
+ causal claim — no "the test's last action", no "the page stayed at …" — instead of merging them.
3318
+
3319
+ A field the test filled and the page submitted EMPTY ({@link formResetOf}) leads the note: the
3320
+ trace holds both facts — the value typed into `textarea[name="bio"]` and the `PUT /api/user`
3321
+ whose body carried `"bio": ""` — so the form's state was reset between the typing and the
3322
+ submit. The note names the effect that re-seeds a form from data whose identity changed and the
3323
+ fix at the source (seed the form once). A deploy-and-walk cycle is lost to this on the
3324
+ deployed URL only, where the background session verification lands later than it does locally.
3325
+
3326
+ A write whose response said a boolean field is true and a LATER GET of the same resource that
3327
+ said it is false leads the note first ({@link readContradictionSentence}): the read route never
3328
+ saw the viewer, so the fix is on that route's middleware, not in the page. Rewriting the
3329
+ profile component over exactly that pair costs ~8 minutes — the write answered
3330
+ `{"following":true}` and the next profile GET answered `false`.
3331
+
3332
+ WHICH rows it spends is evidence, not artifact order: a row
3333
+ needs a recorded response, a real failure or a console line ({@link traceRowEvidence}), rows are
3334
+ deduplicated by the test's location, and they are ordered real failure → repeated from an
3365
3335
 
3366
3336
  _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/trace-artifacts.d.ts`.)_
3367
3337
 
@@ -3437,8 +3407,22 @@ between passing and timing out. This flag was added for exactly that failure: it
3437
3407
  deployed proof run left only an `error-context.md` because the suite traces
3438
3408
  `on-first-retry` and the run had no retries. That need is met without the flag — the graded
3439
3409
  deployed run keeps the suite's own retries, so a failing test leaves its retry's trace — and
3410
+ the platform's re-run note carries `--trace=on` for a run that did leave none.
3440
3411
 
3441
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/trace-artifacts.d.ts`.)_
3412
+ Which runs are proof-capable is {@link suiteCommandTarget}'s answer: a run against a deployed
3413
+ URL. A LOCAL run is never left to its config, because the launcher gives every local run
3414
+ `--retries=0` (`@molecule/api-ai-tools` `streamingBackgroundCommand`), so its retry trace would
3415
+ never happen. A run that pins `--retries=0` itself is in the same position, whatever its target.
3416
+
3417
+ A proof-capable run is left alone WHATEVER its config traces. `--trace` is a per-run override of
3418
+ the suite's own `use.trace` (Playwright merges the CLI's `use` into every project's), and a test
3419
+ record carries the project settings it ran under: a run with the flag is not the suite's own
3420
+ measurement, so it can never count as deployed proof. Added to a deployed walk, the flag made the
3421
+ walk unprovable, and the platform's own answer — "run the current selection" — was a command this
3422
+ same rewrite then flagged again: X1 P140–P173 had 22 deployed walks the executor started, and
3423
+ not one moved the native proof counts (xr-molecule-flash-l1255 walked 73/73 green twice, at
3424
+ +18.2 and +22.9, and neither counted). A failure in a suite that keeps no trace at all is still
3425
+ readable: the platform's re-run note carries `--trace=on` for a run that left none.
3442
3426
 
3443
3427
  ```typescript
3444
3428
  function diagnosisTraceCommand(args: {
@@ -3684,8 +3668,38 @@ killed (one run lost 20 of its 60 minutes this way):
3684
3668
  machine `json` report stays on the last invocation.
3685
3669
 
3686
3670
  The run ends up with exactly ONE reporter that prints each failure — `list`. A run that names
3687
-
3688
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/utilities.d.ts`.)_
3671
+ any other printing reporter has it REPLACED, never joined: two of them write every test result
3672
+ into the log twice, which made a `--reporter=list,line` run (its
3673
+ `line` added by this function one run earlier) report two distinct failures as "4 of this run's
3674
+ tests have already failed the same way", and the executor stopped a 139-test walk at test 21
3675
+ with a single cause in hand. `line` alone is no use either: it writes `[n/N] <title>` with no
3676
+ ✓/✘ mark and no duration, so an 8.3-minute walk of one suite could never trip
3677
+ the fail-fast note. A reporter set that writes a machine format to a file (`json`, `html`,
3678
+ `junit`) is the
3679
+ executor's own and is left exactly as it is — so is any reporter this build does not know.
3680
+
3681
+ Every background command that is not a no-test invocation is also given
3682
+ {@link PLAYWRIGHT_FAILURES_INLINE_ENV} (inert except for Playwright's `list` reporter), so each
3683
+ failure's own error is in the log as that test fails rather than only at the end: a suite that is
3684
+ still walking is exactly when the executor reads the log, and without it a running log carries
3685
+ `✘` rows and nothing else (~90 s went to greps of one, then to fixing what was
3686
+ guessed; a wrapper-launched run lost 6.5 minutes to the same shape).
3687
+
3688
+ Only the step that runs the suite is touched, and only its reporter, and only when that step
3689
+ runs something: `npx playwright test --list` takes two seconds and writes nothing per test, so
3690
+ neither reporter nor `--retries=0` is added to it ({@link isPlaywrightRunCommand}). A trailing
3691
+ status step (`; echo EXIT $?`, `&& true`) is not the run and is skipped when the run step is
3692
+ found ({@link isStatusOnlyStep}); a run whose output is redirected to a file is still readable
3693
+ through that file, which the launch records as the task's own output.
3694
+
3695
+ A command that starts the suite MORE THAN ONCE is not launched at all: every run it carries is
3696
+ a whole walk of the same suite against the same app, and only the last step is rewritten, so the
3697
+ earlier walks run unmeasured for nothing. Two whole walks of one 138-test suite chained with
3698
+ `;` — 4.5 minutes each — measured nothing the first had not. The platform refuses a second CONCURRENT run against one app and database by the
3699
+ ONE rule ({@link suiteRunInTheWay}) — for every pair, whatever uid a run mints — and this is the
3700
+ same hazard inside one command ({@link suiteRunStatements}). `error` then carries the refusal,
3701
+ naming each suite step and the ONE command to send instead (the last suite step, rewritten as
3702
+ this function rewrites a run), and nothing is launched.
3689
3703
 
3690
3704
  ```typescript
3691
3705
  function streamingBackgroundCommand(
@@ -4167,8 +4181,13 @@ is a directory rather than a directory name.
4167
4181
 
4168
4182
  An npm SCOPE as the first segment, under a `node_modules` root, is the one
4169
4183
  exception that parameter `root` enables: npm installs a scope only directly
4170
-
4171
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/utilities.d.ts`.)_
4184
+ inside a `node_modules` directory, and the walk already prunes every nested
4185
+ `node_modules` (see `findPruneArgs`), so the whole-tree form can only ever
4186
+ match `<root>/@molecule/…` — the scope directory IS the directory the pattern
4187
+ names. Left un-narrowed, a scoped-package pattern walked the sandbox's entire
4188
+ dependency tree and hit the 10 s deadline with no result at all. A bare NAME stays a
4189
+ directory name at any depth:
4190
+ `helpers/*` is unchanged even under a `node_modules` root.
4172
4191
 
4173
4192
  ```typescript
4174
4193
  function literalDirPrefix(pattern: string, root?: string): string | null
@@ -4507,8 +4526,7 @@ each was the test timeout and one missing `navigate('/')` was the cause of all o
4507
4526
  The quorum is of DISTINCT tests — {@link REPEATING_FAILURE_MIN} of them — because a log that
4508
4527
  prints each failure twice (a second reporter, a retry) has told a run that four of its
4509
4528
  tests failed the same way when two had, so the executor stopped a 139-test walk at test 21
4510
-
4511
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/utilities.d.ts`.)_
4529
+ with one cause in hand.
4512
4530
 
4513
4531
  ```typescript
4514
4532
  function repeatingFailure(log: string): RepeatingFailure | null
@@ -4641,7 +4659,11 @@ Both halves are load-bearing, each of them learned from a run that lost minutes
4641
4659
  — read the early return as "stop waiting, edit now", and voided a run that was still walking;
4642
4660
  the second cost a 224 s wait that ended with no result at all.
4643
4661
 
4644
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/utilities.d.ts`.)_
4662
+ Neither half alone is enough, and {@link repeatingFailure} finding a signature is not either:
4663
+ that answers "is a cause repeating among this run's failures", which is worth telling the
4664
+ executor mid-run as a NOTE while the wait goes on. This answers the narrower question the wait
4665
+ needs — is the run over as a measuring instrument — and it is THE one predicate behind both
4666
+ that decision and the note's wording, so the two cannot come to different verdicts.
4645
4667
 
4646
4668
  ```typescript
4647
4669
  function earlyReturnCause(
@@ -4854,9 +4876,12 @@ for — never as a verdict with a stop command in it.
4854
4876
  The run is STILL WALKING while this note is written — both callers produce it mid-run — so a
4855
4877
  re-run of one of its tests is a second run against the same app and database, and the platform
4856
4878
  refuses that ({@link suiteRunInTheWay}, the same rule its overlap hold answers with):
4857
- an executor read *"Start on them now, while the run keeps walking.
4858
-
4859
- _(description truncated — read the full text in `node_modules/@molecule/api-ai-tools/dist/utilities.d.ts`.)_
4879
+ an executor read _"Start on them now, while the run keeps walking.
4880
+ `null-fields.spec.ts:53` alone reproduces the first one."_ and sent exactly that re-run 23 s
4881
+ later, where the hold answered _"A playwright suite is already running against this app and
4882
+ database … Wait for it."_ The note therefore hands over the read-and-fix to do NOW and the
4883
+ re-run for after the run ends — the exact command where the caller knows how the run was
4884
+ started ({@link rerunOfRunningSuite}), the timing alone where it does not.
4860
4885
 
4861
4886
  ```typescript
4862
4887
  function repeatingFailureNote(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-tools",
3
- "version": "1.16.3",
3
+ "version": "1.16.4",
4
4
  "description": "Shared AI agent tools with backend abstraction for sandbox and local execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",