@molecule/api-ai-tools 1.10.5 → 1.10.7

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-19T06:38:37.559Z
6
+ Generated: 2026-10-19T22:30:20.727Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-ai-tools
@@ -58,6 +58,28 @@ npm install @molecule/api-ai-tools @molecule/api-ai
58
58
 
59
59
  ### Interfaces
60
60
 
61
+ #### `BrowserProbeLeak`
62
+
63
+ A browser launch bound to a variable, proven to have no cleanup path.
64
+
65
+ ```typescript
66
+ interface BrowserProbeLeak {
67
+ /** The variable the launched browser is bound to (`browser` in the m257 probe). */
68
+ readonly variable: string
69
+ }
70
+ ```
71
+
72
+ #### `ForegroundBrowserProbe`
73
+
74
+ A foreground command that directly executes such a script.
75
+
76
+ ```typescript
77
+ interface ForegroundBrowserProbe extends BrowserProbeLeak {
78
+ /** The script file as the command named it. */
79
+ readonly script: string
80
+ }
81
+ ```
82
+
61
83
  #### `CommandSegment`
62
84
 
63
85
  One statement or pipeline stage of a shell command: what it runs, and with what.
@@ -222,6 +244,13 @@ interface CutRun {
222
244
  * is slow, so the sentence must not send it to the background (xr-molecule-flash-m200 +03:45).
223
245
  */
224
246
  inlineScript?: string | null
247
+ /**
248
+ * The variable a leaked standalone browser launch is bound to, when the command ran such a probe
249
+ * and the cut reader could only classify it after the run (xr-molecule-flash-m257). A leaked
250
+ * handle is not a slow workload: the background is the one place it must not be sent, so the
251
+ * sentence names the close instead.
252
+ */
253
+ browserProbe?: string | null
225
254
  }
226
255
  ```
227
256
 
@@ -584,6 +613,13 @@ selector. xr-molecule-flash-m169 (+13:09) spent its fix rounds on the wrong comp
584
613
  markup detail while `GET /api/tags` was returning the missing "trending" and `PopularTags`
585
614
  sliced the response to its first 20 entries (the m99 top-N class, in the frontend).
586
615
 
616
+ The text must be a value the response held, never a substring of one: a whole JSON string or
617
+ number value, or a word bounded by non-alphanumerics. A text of 2 characters or fewer, or one
618
+ made of digits only, must be a whole JSON value. xr-molecule-flash-m208's pagination assertion
619
+ waited for "2" and the raw substring hit `pag1792394785820` in a tags response, so the note led
620
+ with a response that had nothing to do with the failure; when no response holds the text that
621
+ way, the field is absent and the note leads with its next finding.
622
+
587
623
  ```typescript
588
624
  interface TraceMissingText {
589
625
  /** The text the assertion waited for (`trending`). */
@@ -765,6 +801,15 @@ interface TraceArtifact {
765
801
  * leaving the run to probe computed styles (xr-molecule-flash-m197).
766
802
  */
767
803
  hiddenBox?: TraceHiddenBox
804
+ /**
805
+ * The method+path groups this test's page sent {@link TRACE_NOTE_LOOP_REPEATS} times or more,
806
+ * most-repeated first — a render loop the note leads with (xr-molecule-flash-m215: 2,106
807
+ * `GET /api/articles/<slug>` in one test, printed as four identical `→ 200` lines). Counted over
808
+ * every network entry of the failing page, not the capped {@link TraceArtifact.requests} list.
809
+ *
810
+ * Absent when no group reached the threshold, and on traces read before this field existed.
811
+ */
812
+ repeated?: TraceRequestRepeat[]
768
813
  }
769
814
  ```
770
815
 
@@ -819,6 +864,13 @@ interface TraceRunReport {
819
864
  * Empty when the caller could not read the app's config.
820
865
  */
821
866
  authEndpoints?: readonly string[]
867
+ /**
868
+ * The app source files whose code sends a repeated request, read by the caller from the
869
+ * project (`app/src/**`) before this note is written. A loop's sentence names the component to
870
+ * read instead of leaving the run to search for it (xr-molecule-flash-m215's `Editor.tsx`).
871
+ * Empty when the caller could not read the app or no file states the path.
872
+ */
873
+ callSites?: readonly { method: string; path: string; file: string }[]
822
874
  }
823
875
  ```
824
876
 
@@ -1446,6 +1498,58 @@ function createSandboxBackend(sandbox: SandboxLike, projectRoot?: string): Execu
1446
1498
 
1447
1499
  **Returns:** A backend that proxies all filesystem calls into the sandbox.
1448
1500
 
1501
+ #### `standaloneBrowserLeak(source)`
1502
+
1503
+ The browser variable a standalone script launches and never closes, when that can be proven from
1504
+ the source alone.
1505
+
1506
+ The proof is a closed world: one plain TOP-LEVEL launch binding whose engine is genuinely
1507
+ Playwright's, every reference to it a known non-closing method call, and no cleanup, escape or
1508
+ persistent-process path anywhere in the source. A source with two launches is read one binding
1509
+ at a time — a proven leak in either one is enough, because that handle alone keeps Node alive.
1510
+
1511
+ ```typescript
1512
+ function standaloneBrowserLeak(source: string): BrowserProbeLeak | null
1513
+ ```
1514
+
1515
+ - `source` — The script's source, as read from disk.
1516
+
1517
+ **Returns:** The leaking binding, or null when the script is clean or ambiguous.
1518
+
1519
+ #### `browserProbeRefusal(probe, budgetSeconds, piped)`
1520
+
1521
+ The refusal for a foreground command that would run a leaking browser probe: it never returns,
1522
+ and the one move that makes it return is closing the browser (or letting the Playwright runner
1523
+ own it), never moving the leak to the background.
1524
+
1525
+ ```typescript
1526
+ function browserProbeRefusal(
1527
+ probe: ForegroundBrowserProbe,
1528
+ budgetSeconds: number,
1529
+ piped?: boolean,
1530
+ ): string
1531
+ ```
1532
+
1533
+ - `probe` — The leaked probe, from `foregroundBrowserProbe`.
1534
+ - `budgetSeconds` — The tool's budget, which the probe would consume whole.
1535
+ - `piped` — Whether the command pipes through `tail`/`head`, which withholds the probe's output.
1536
+
1537
+ **Returns:** The refusal sentence.
1538
+
1539
+ #### `browserProbeOverBudgetAdvice(probe)`
1540
+
1541
+ The over-budget advice for a leak discovered at cut time (the preflight could not read the script
1542
+ before the run — e.g. the same command wrote it). It names the lifecycle fix and says explicitly
1543
+ that the background is not one: a leaked handle hangs there too.
1544
+
1545
+ ```typescript
1546
+ function browserProbeOverBudgetAdvice(probe: ForegroundBrowserProbe): string
1547
+ ```
1548
+
1549
+ - `probe` — The leaked probe.
1550
+
1551
+ **Returns:** The sentence the cut result carries.
1552
+
1449
1553
  #### `durationSeconds(word)`
1450
1554
 
1451
1555
  The seconds a duration word stands for.
@@ -1767,7 +1871,12 @@ function allConnectionFailures(failures: readonly (RunFailureClass | null)[]): b
1767
1871
  The interpreter of an INLINE program that only reads and writes local files — the shape that gets
1768
1872
  {@link INLINE_SCRIPT_BUDGET_MS} instead of the tool's command budget.
1769
1873
 
1770
- An inline program with any external effect keeps the full budget: no network, install, test
1874
+ EVERY statement of the command must be proven local, not just one of them: each is either an
1875
+ inline interpreter program or a plain file utility ({@link LOCAL_UTILITY}). A statement that runs
1876
+ a script FILE (`node smoke.mjs`, `python3 x.py`, `bash x.sh`) or names a program this module does
1877
+ not know can do anything at all, so the command keeps the full budget.
1878
+
1879
+ An inline program with any external effect keeps the full budget too: no network, install, test
1771
1880
  runner, build or server verb may appear anywhere in the command ({@link EXTERNAL_EFFECT}), and
1772
1881
  the command must not be a suite run or a foreground server (the platform's own classifiers).
1773
1882
 
@@ -2010,6 +2119,29 @@ function foregroundServerCommand(
2010
2119
 
2011
2120
  **Returns:** The serving program, or null when the command starts no server in the foreground.
2012
2121
 
2122
+ #### `foregroundBrowserProbe(command, readScript)`
2123
+
2124
+ A FOREGROUND command that directly runs a standalone script which launches a browser and never
2125
+ closes it — the same never-returns lifecycle class as {@link foregroundServerCommand}, read from
2126
+ the script's SOURCE by {@link standaloneBrowserLeak}.
2127
+
2128
+ The boundaries are the server preflight's, so the two readers cannot disagree about what they are
2129
+ allowed to touch: a backgrounded launch, a test runner and a test file are left alone, and a
2130
+ script the backend will not answer for is a command this reading cannot classify, never a
2131
+ refusal. A Playwright suite is owned by its runner's browser fixture and is never read here.
2132
+
2133
+ ```typescript
2134
+ function foregroundBrowserProbe(
2135
+ command: string,
2136
+ readScript: (path: string) => Promise<string>,
2137
+ ): Promise<ForegroundBrowserProbe | null>
2138
+ ```
2139
+
2140
+ - `command` — The command as the executor sent it.
2141
+ - `readScript` — Reads a script file the command names (`backend.readFile`).
2142
+
2143
+ **Returns:** The leaked probe's variable and script path, or null when the command is not one.
2144
+
2013
2145
  #### `serverCommandRefusal(server, budgetSeconds)`
2014
2146
 
2015
2147
  The refusal for a foreground command that starts a server: why it would never return, and the
@@ -4112,6 +4244,21 @@ How many requests the note names per test.
4112
4244
  const MAX_TRACE_NOTE_REQUESTS: 4
4113
4245
  ```
4114
4246
 
4247
+ #### `TRACE_NOTE_LOOP_REPEATS`
4248
+
4249
+ How many times ONE test may send the same method+path before the note calls it a render loop.
4250
+
4251
+ xr-molecule-flash-m215 (+27:27 → +29:42): an Editor effect with `[seeded, slug, t]` in its
4252
+ dependency list re-fetched `GET /api/articles/<slug>` 2,106 times in one test. The trace reader
4253
+ caps and de-duplicates its request list, so the note printed four identical `→ 200` lines and
4254
+ the run patched the component's seeding, rebuilt and re-ran before unzipping the trace by hand.
4255
+ Twenty is far above the retries a correct page makes (a few on a flaky call) and far below any
4256
+ render loop.
4257
+
4258
+ ```typescript
4259
+ const TRACE_NOTE_LOOP_REPEATS: 20
4260
+ ```
4261
+
4115
4262
  #### `TRACE_NOTE_URL_CHARS`
4116
4263
 
4117
4264
  How long a URL the note prints, before the middle is cut.
@@ -0,0 +1,82 @@
1
+ /**
2
+ * A standalone Playwright probe that launches a browser and never closes it — the
3
+ * resource-lifecycle hang `exec_command` did not yet classify.
4
+ *
5
+ * X1 xr-molecule-flash-m257 (+10:44 → +15:34) ran
6
+ * `cd /workspace/my-app/app && node /workspace/.mol-scratch/fav-probe.mjs 2>&1 | tail -5`. The
7
+ * 30-line script binds `const browser = await chromium.launch()`, walks a real page, reaches its
8
+ * last `console.log`, and ends without `browser.close()`, `disconnect()`, a disposal scope or
9
+ * `process.exit()`. Chromium is a live handle, so Node never exits: the tool waited its whole 290 s
10
+ * budget, returned `status: cut_at_budget` with empty stdout (the `| tail` held it), and then
11
+ * advised "run it in the background" — advice for a slow workload, not for a leaked handle.
12
+ *
13
+ * That is the same lifecycle class {@link foregroundServerCommand} already refuses: a foreground
14
+ * process that never returns. So the same preflight seam reads it, with a deliberately narrow
15
+ * closed-world proof:
16
+ *
17
+ * - the script is DIRECTLY executed (`node`/`tsx`/`bun`/`deno` naming a script file, never a
18
+ * test-runner invocation or a test/fixture file — those are the runner's business);
19
+ * - the source, with comments and string/template/regex literals blanked, binds a browser by a
20
+ * TOP-LEVEL (brace depth 0) `const|let|var <x> = await chromium|firefox|webkit.launch(`
21
+ * assignment, where the engine (or its namespace) is imported/required from `playwright`,
22
+ * `playwright-core` or `@playwright/test` — a locally bound stub is not Playwright;
23
+ * - every reference to `<x>` is a known browser method that does NOT close it (`newPage`,
24
+ * `newContext`, `on`, `version`, …), and the binding is never aliased, passed to a helper, or
25
+ * read as a property;
26
+ * - nothing in the source is a cleanup path (any `.close(`/`.disconnect(`/`.dispose(`, a `using`
27
+ * scope, a cleanup-named import), an escape (`process.exit`, `eval`, `new Function`, dynamic
28
+ * `import`), or a persistent-process intent (`launchServer`, `connect`, a server `.listen`, a
29
+ * timer or signal handler).
30
+ *
31
+ * Anything ambiguous is left alone. A wrong refusal costs a valid probe — the review that found
32
+ * the m257 leak also proved five harmless scripts a raw substring match would refuse (a local
33
+ * engine stub, the launch text in a string, in a comment, in a template literal, and inside a
34
+ * function that is never called) — and a missed leak costs the same budget the tool already had.
35
+ * This is a lifecycle diagnostic, never an egress or security gate.
36
+ *
37
+ * @module
38
+ */
39
+ /** A browser launch bound to a variable, proven to have no cleanup path. */
40
+ export interface BrowserProbeLeak {
41
+ /** The variable the launched browser is bound to (`browser` in the m257 probe). */
42
+ readonly variable: string;
43
+ }
44
+ /** A foreground command that directly executes such a script. */
45
+ export interface ForegroundBrowserProbe extends BrowserProbeLeak {
46
+ /** The script file as the command named it. */
47
+ readonly script: string;
48
+ }
49
+ /**
50
+ * The browser variable a standalone script launches and never closes, when that can be proven from
51
+ * the source alone.
52
+ *
53
+ * The proof is a closed world: one plain TOP-LEVEL launch binding whose engine is genuinely
54
+ * Playwright's, every reference to it a known non-closing method call, and no cleanup, escape or
55
+ * persistent-process path anywhere in the source. A source with two launches is read one binding
56
+ * at a time — a proven leak in either one is enough, because that handle alone keeps Node alive.
57
+ *
58
+ * @param source - The script's source, as read from disk.
59
+ * @returns The leaking binding, or null when the script is clean or ambiguous.
60
+ */
61
+ export declare function standaloneBrowserLeak(source: string): BrowserProbeLeak | null;
62
+ /**
63
+ * The refusal for a foreground command that would run a leaking browser probe: it never returns,
64
+ * and the one move that makes it return is closing the browser (or letting the Playwright runner
65
+ * own it), never moving the leak to the background.
66
+ *
67
+ * @param probe - The leaked probe, from `foregroundBrowserProbe`.
68
+ * @param budgetSeconds - The tool's budget, which the probe would consume whole.
69
+ * @param piped - Whether the command pipes through `tail`/`head`, which withholds the probe's output.
70
+ * @returns The refusal sentence.
71
+ */
72
+ export declare function browserProbeRefusal(probe: ForegroundBrowserProbe, budgetSeconds: number, piped?: boolean): string;
73
+ /**
74
+ * The over-budget advice for a leak discovered at cut time (the preflight could not read the script
75
+ * before the run — e.g. the same command wrote it). It names the lifecycle fix and says explicitly
76
+ * that the background is not one: a leaked handle hangs there too.
77
+ *
78
+ * @param probe - The leaked probe.
79
+ * @returns The sentence the cut result carries.
80
+ */
81
+ export declare function browserProbeOverBudgetAdvice(probe: ForegroundBrowserProbe): string;
82
+ //# sourceMappingURL=browser-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-probe.d.ts","sourceRoot":"","sources":["../src/browser-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,iEAAiE;AACjE,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AA6aD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAyB7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,sBAAsB,EAC7B,aAAa,EAAE,MAAM,EACrB,KAAK,UAAQ,GACZ,MAAM,CAaR;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CASlF"}