@ait-co/devtools 0.1.144 → 0.2.1

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 (182) hide show
  1. package/README.en.md +47 -218
  2. package/README.md +36 -246
  3. package/dist/in-app/auto.d.ts +1 -138
  4. package/dist/in-app/auto.js +28 -1102
  5. package/dist/in-app/auto.js.map +1 -1
  6. package/dist/in-app/index.d.ts +38 -547
  7. package/dist/in-app/index.d.ts.map +1 -1
  8. package/dist/in-app/index.js +62 -939
  9. package/dist/in-app/index.js.map +1 -1
  10. package/dist/mcp/cli.d.ts +1 -54
  11. package/dist/mcp/cli.js +33 -9720
  12. package/dist/mcp/cli.js.map +1 -1
  13. package/dist/mcp/server.d.ts +1 -88
  14. package/dist/mcp/server.js +36 -1076
  15. package/dist/mcp/server.js.map +1 -1
  16. package/dist/mock/index.d.ts +35 -21
  17. package/dist/mock/index.d.ts.map +1 -1
  18. package/dist/mock/index.js +81 -2
  19. package/dist/mock/index.js.map +1 -1
  20. package/dist/panel/index.js +80 -104
  21. package/dist/panel/index.js.map +1 -1
  22. package/dist/relay-url-store-CkVSQZMq.cjs +110 -0
  23. package/dist/relay-url-store-CkVSQZMq.cjs.map +1 -0
  24. package/dist/relay-url-store-dkII-DHD.js +109 -0
  25. package/dist/relay-url-store-dkII-DHD.js.map +1 -0
  26. package/dist/stubs/bin-devtools-mcp.js +58 -0
  27. package/dist/stubs/bin-devtools-mcp.js.map +1 -0
  28. package/dist/stubs/bin-devtools-test.d.ts +2 -0
  29. package/dist/stubs/bin-devtools-test.js +55 -0
  30. package/dist/stubs/bin-devtools-test.js.map +1 -0
  31. package/dist/test-runner/config.d.ts +1 -231
  32. package/dist/test-runner/config.js +41 -45
  33. package/dist/test-runner/config.js.map +1 -1
  34. package/dist/{tunnel-BGT9Curk.cjs → tunnel-BKZkOyQp.cjs} +1 -1
  35. package/dist/{tunnel-BGT9Curk.cjs.map → tunnel-BKZkOyQp.cjs.map} +1 -1
  36. package/dist/{tunnel-BOKmLzBO.js → tunnel-CqSCIrdU.js} +1 -1
  37. package/dist/{tunnel-BOKmLzBO.js.map → tunnel-CqSCIrdU.js.map} +1 -1
  38. package/dist/unplugin/index.cjs +9 -18
  39. package/dist/unplugin/index.cjs.map +1 -1
  40. package/dist/unplugin/index.d.cts +26 -5
  41. package/dist/unplugin/index.d.cts.map +1 -1
  42. package/dist/unplugin/index.d.ts +27 -6
  43. package/dist/unplugin/index.d.ts.map +1 -1
  44. package/dist/unplugin/index.js +10 -19
  45. package/dist/unplugin/index.js.map +1 -1
  46. package/package.json +10 -25
  47. package/dist/attach-orchestrator-0F0m_UqQ.js +0 -1845
  48. package/dist/attach-orchestrator-0F0m_UqQ.js.map +0 -1
  49. package/dist/attach-orchestrator-D65KxFy_.js +0 -1831
  50. package/dist/attach-orchestrator-D65KxFy_.js.map +0 -1
  51. package/dist/attach-orchestrator-DL3NQ9ca.js +0 -1846
  52. package/dist/attach-orchestrator-DL3NQ9ca.js.map +0 -1
  53. package/dist/bundle-C796JIwG.d.ts +0 -159
  54. package/dist/bundle-C796JIwG.d.ts.map +0 -1
  55. package/dist/capture-DsP525OZ.d.ts +0 -58
  56. package/dist/capture-DsP525OZ.d.ts.map +0 -1
  57. package/dist/cdp-connection-rP1WdnH5.d.ts +0 -287
  58. package/dist/cdp-connection-rP1WdnH5.d.ts.map +0 -1
  59. package/dist/cell-BaLvusOl.js +0 -68
  60. package/dist/cell-BaLvusOl.js.map +0 -1
  61. package/dist/cell-CBUS3-nT.js +0 -274
  62. package/dist/cell-CBUS3-nT.js.map +0 -1
  63. package/dist/cell-EBKKpAAT.js +0 -307
  64. package/dist/cell-EBKKpAAT.js.map +0 -1
  65. package/dist/chii-relay-B3ZhjGMi.js +0 -304
  66. package/dist/chii-relay-B3ZhjGMi.js.map +0 -1
  67. package/dist/chii-relay-CGMlePMd.cjs +0 -304
  68. package/dist/chii-relay-CGMlePMd.cjs.map +0 -1
  69. package/dist/debug-server-B3ABDrRI.js +0 -456
  70. package/dist/debug-server-B3ABDrRI.js.map +0 -1
  71. package/dist/debug-server-BWhwrVXa.js +0 -1158
  72. package/dist/debug-server-BWhwrVXa.js.map +0 -1
  73. package/dist/debug-server-CfQNxxGW.js +0 -600
  74. package/dist/debug-server-CfQNxxGW.js.map +0 -1
  75. package/dist/devtools-opener-3Drge_RJ.js +0 -75
  76. package/dist/devtools-opener-3Drge_RJ.js.map +0 -1
  77. package/dist/devtools-opener-CJpEsXXQ.js +0 -76
  78. package/dist/devtools-opener-CJpEsXXQ.js.map +0 -1
  79. package/dist/devtools-opener-CxtryS8c.js +0 -75
  80. package/dist/devtools-opener-CxtryS8c.js.map +0 -1
  81. package/dist/in-app/auto.d.ts.map +0 -1
  82. package/dist/mcp/cli.d.ts.map +0 -1
  83. package/dist/mcp/server.d.ts.map +0 -1
  84. package/dist/pool-DcaaOwUq.d.ts +0 -14761
  85. package/dist/pool-DcaaOwUq.d.ts.map +0 -1
  86. package/dist/qr-http-server-C_lqOrgc.js +0 -1644
  87. package/dist/qr-http-server-C_lqOrgc.js.map +0 -1
  88. package/dist/qr-http-server-CopuMbub.js +0 -1644
  89. package/dist/qr-http-server-CopuMbub.js.map +0 -1
  90. package/dist/qr-http-server-DrbIVDjO.js +0 -1645
  91. package/dist/qr-http-server-DrbIVDjO.js.map +0 -1
  92. package/dist/relay-factory-N9QobQxG.js +0 -206
  93. package/dist/relay-factory-N9QobQxG.js.map +0 -1
  94. package/dist/relay-secret-store-BR0YIkNv.cjs +0 -241
  95. package/dist/relay-secret-store-BR0YIkNv.cjs.map +0 -1
  96. package/dist/relay-secret-store-Bmyleu0A.js +0 -154
  97. package/dist/relay-secret-store-Bmyleu0A.js.map +0 -1
  98. package/dist/relay-secret-store-CQenfcSL.js +0 -154
  99. package/dist/relay-secret-store-CQenfcSL.js.map +0 -1
  100. package/dist/relay-secret-store-CYM8CBIF.js +0 -240
  101. package/dist/relay-secret-store-CYM8CBIF.js.map +0 -1
  102. package/dist/relay-secret-store-DKxs7zwq.js +0 -153
  103. package/dist/relay-secret-store-DKxs7zwq.js.map +0 -1
  104. package/dist/relay-secret-store-WJ8EGkIl.js +0 -153
  105. package/dist/relay-secret-store-WJ8EGkIl.js.map +0 -1
  106. package/dist/relay-url-store-BR2XodiO.js +0 -123
  107. package/dist/relay-url-store-BR2XodiO.js.map +0 -1
  108. package/dist/relay-url-store-C1as_m5G.cjs +0 -115
  109. package/dist/relay-url-store-C1as_m5G.cjs.map +0 -1
  110. package/dist/relay-url-store-CH63fVCm.js +0 -122
  111. package/dist/relay-url-store-CH63fVCm.js.map +0 -1
  112. package/dist/relay-url-store-CzFo_84F.js +0 -114
  113. package/dist/relay-url-store-CzFo_84F.js.map +0 -1
  114. package/dist/relay-url-store-DaY1QPes.js +0 -123
  115. package/dist/relay-url-store-DaY1QPes.js.map +0 -1
  116. package/dist/relay-url-store-xmUuTjXA.js +0 -122
  117. package/dist/relay-url-store-xmUuTjXA.js.map +0 -1
  118. package/dist/relay-worker-B5HKkGUY.js +0 -832
  119. package/dist/relay-worker-B5HKkGUY.js.map +0 -1
  120. package/dist/relay-worker-YdlpZQl9.d.ts +0 -214
  121. package/dist/relay-worker-YdlpZQl9.d.ts.map +0 -1
  122. package/dist/rolldown-runtime-DGkTqVfb.js +0 -15
  123. package/dist/rolldown-runtime-DUslC3ob.js +0 -14
  124. package/dist/runtime-kn9DxOeg.d.ts +0 -249
  125. package/dist/runtime-kn9DxOeg.d.ts.map +0 -1
  126. package/dist/test-runner/bin.js +0 -2584
  127. package/dist/test-runner/bin.js.map +0 -1
  128. package/dist/test-runner/bridge-stub.d.ts +0 -125
  129. package/dist/test-runner/bridge-stub.d.ts.map +0 -1
  130. package/dist/test-runner/bridge-stub.js +0 -92
  131. package/dist/test-runner/bridge-stub.js.map +0 -1
  132. package/dist/test-runner/bundle.d.ts +0 -2
  133. package/dist/test-runner/bundle.js +0 -439
  134. package/dist/test-runner/bundle.js.map +0 -1
  135. package/dist/test-runner/capture.d.ts +0 -2
  136. package/dist/test-runner/capture.js +0 -44
  137. package/dist/test-runner/capture.js.map +0 -1
  138. package/dist/test-runner/config.d.ts.map +0 -1
  139. package/dist/test-runner/method-pace.d.ts +0 -82
  140. package/dist/test-runner/method-pace.d.ts.map +0 -1
  141. package/dist/test-runner/method-pace.js +0 -120
  142. package/dist/test-runner/method-pace.js.map +0 -1
  143. package/dist/test-runner/pool.d.ts +0 -2
  144. package/dist/test-runner/pool.js +0 -136
  145. package/dist/test-runner/pool.js.map +0 -1
  146. package/dist/test-runner/relay-factory.d.ts +0 -11245
  147. package/dist/test-runner/relay-factory.d.ts.map +0 -1
  148. package/dist/test-runner/relay-factory.js +0 -206
  149. package/dist/test-runner/relay-factory.js.map +0 -1
  150. package/dist/test-runner/relay-worker.d.ts +0 -2
  151. package/dist/test-runner/relay-worker.js +0 -2
  152. package/dist/test-runner/report.d.ts +0 -163
  153. package/dist/test-runner/report.d.ts.map +0 -1
  154. package/dist/test-runner/report.js +0 -198
  155. package/dist/test-runner/report.js.map +0 -1
  156. package/dist/test-runner/rpc.d.ts +0 -56
  157. package/dist/test-runner/rpc.d.ts.map +0 -1
  158. package/dist/test-runner/rpc.js +0 -98
  159. package/dist/test-runner/rpc.js.map +0 -1
  160. package/dist/test-runner/runtime.d.ts +0 -2
  161. package/dist/test-runner/runtime.js +0 -659
  162. package/dist/test-runner/runtime.js.map +0 -1
  163. package/dist/test-runner/task-graph.d.ts +0 -38
  164. package/dist/test-runner/task-graph.d.ts.map +0 -1
  165. package/dist/test-runner/task-graph.js +0 -182
  166. package/dist/test-runner/task-graph.js.map +0 -1
  167. package/dist/throttle-DKKzX1qC.js +0 -59
  168. package/dist/throttle-DKKzX1qC.js.map +0 -1
  169. package/dist/totp-BqmCLSNA.js +0 -189
  170. package/dist/totp-BqmCLSNA.js.map +0 -1
  171. package/dist/totp-CMHR5lsW.cjs +0 -191
  172. package/dist/totp-CMHR5lsW.cjs.map +0 -1
  173. package/dist/totp-CZLLKfOC.js +0 -200
  174. package/dist/totp-CZLLKfOC.js.map +0 -1
  175. package/dist/totp-DAxys-r0.js +0 -199
  176. package/dist/totp-DAxys-r0.js.map +0 -1
  177. package/dist/totp-DfekTBk3.js +0 -211
  178. package/dist/totp-DfekTBk3.js.map +0 -1
  179. package/dist/totp-Dwft0Kz7.js +0 -3
  180. package/dist/totp-WY6l0ysP.js +0 -190
  181. package/dist/totp-WY6l0ysP.js.map +0 -1
  182. /package/dist/{test-runner/bin.d.ts → stubs/bin-devtools-mcp.d.ts} +0 -0
@@ -1,159 +0,0 @@
1
- //#region src/test-runner/bundle.d.ts
2
- /**
3
- * esbuild-based bundler for user test files.
4
- *
5
- * Bundles a single test file into a self-contained IIFE string that can be
6
- * injected into a WebView via `Runtime.evaluate`. The bundle includes the
7
- * test runtime (`runtime.ts`), which provides `describe/it/test/expect` and
8
- * the `runTestModule(factory)` entry point.
9
- *
10
- * ## How the wiring works
11
- *
12
- * The bundle exposes two exports on `globalThis.__testBundle`:
13
- * - `runTestModule` — the runtime's entry function.
14
- * - `__userFactory` — an async function whose body is the user's top-level
15
- * test registration code (describe/it/test calls).
16
- *
17
- * The Node-side RPC (`rpc.ts`) calls:
18
- * `globalThis.__testBundle.runTestModule(globalThis.__testBundle.__userFactory)`
19
- *
20
- * `runTestModule` then installs `describe/it/test/expect` as globals, invokes
21
- * the factory (which registers all tests), runs them, and returns a `RunReport`.
22
- *
23
- * ## Why a factory wrapper is needed
24
- *
25
- * Naively adding the runtime to `entryPoints` and bundling the user file would
26
- * fail for two reasons:
27
- * 1. `describe/it/test/expect` from the runtime are module-local in the IIFE
28
- * scope. The user's top-level `describe(...)` calls expect them as globals —
29
- * they are not globals until `runTestModule` installs them.
30
- * 2. Even with globals pre-installed, the user file runs at IIFE-evaluation
31
- * time, before the RPC layer calls `runTestModule` to reset state and start
32
- * the test clock.
33
- *
34
- * The factory approach solves both: the user's registration code is deferred
35
- * into a function that `runTestModule` calls AFTER installing the globals.
36
- *
37
- * ## Factory extraction algorithm
38
- *
39
- * The `userFactoryPlugin` reads the user file and splits lines into:
40
- * - **top-level**: `import …` and re-export lines — kept at module scope
41
- * (the only valid position for static `import` in ESM).
42
- * - **body**: all other statements — moved into the body of the exported
43
- * `__userFactory` async function.
44
- *
45
- * esbuild processes the re-generated module, following each static import
46
- * through the normal dependency graph (including the SDK-redirect plugin).
47
- *
48
- * ## SDK redirect
49
- *
50
- * Imports of `@apps-in-toss/web-framework` (and sub-paths) are intercepted via
51
- * the `sdkRedirectPlugin` and replaced with a virtual `window.__sdk` proxy that
52
- * `src/in-app/auto.ts` installs at runtime. This works for both 2.x and 3.x SDK.
53
- *
54
- * SECRET-HANDLING: the returned bundle code is caller-managed; never log it.
55
- */
56
- /** Options accepted by `bundleTestFile`. */
57
- interface BundleOptions {
58
- /**
59
- * Additional esbuild `external` patterns. The SDK package
60
- * (`@apps-in-toss/web-framework` and `@apps-in-toss/web-framework/*`) is
61
- * always handled by the SDK redirect plugin — callers may add more patterns
62
- * to be left as globals.
63
- */
64
- extraExternals?: string[];
65
- /**
66
- * Global name for the IIFE output object. Defaults to `__testBundle`.
67
- * The runtime entry uses this to call `__testBundle.runTestModule(__userFactory)`.
68
- */
69
- globalName?: string;
70
- }
71
- /**
72
- * The result of bundling a test file.
73
- * `code` is a self-contained IIFE string ready for `Runtime.evaluate`.
74
- */
75
- interface BundleResult {
76
- code: string;
77
- warnings: string[];
78
- }
79
- /**
80
- * esbuild plugin that intercepts SDK imports and redirects them to the
81
- * `window.__sdk` proxy that `src/in-app/auto.ts` installs at runtime.
82
- *
83
- * Strategy: for every import of `@apps-in-toss/web-framework` (or sub-paths),
84
- * esbuild resolves it to a virtual module that re-exports all named exports
85
- * via `window.__sdk[name]`. This avoids bundling the real SDK (which may not
86
- * be available in the test environment) while still making named imports work.
87
- *
88
- * If `window.__sdk` is absent (non-dog-food build), every access throws a
89
- * descriptive error rather than returning `undefined` silently.
90
- *
91
- * Bridge-stub interception (devtools#740, DT-2): the virtual module runs the
92
- * resolved `window.__sdk` object through `wrapSdkWithStub` before exporting
93
- * it. `wrapSdkWithStub` is a pass-through (returns the same object,
94
- * unwrapped) unless `isStubBlockingEnabled()` reads `true` off
95
- * `globalThis.__AIT_STUB_BLOCKING__` — an opt-in flag injected the same way
96
- * `__AIT_CELL__` is (`cell.ts#injectGlobals`, wired from the CLI's
97
- * `--stub-blocking` flag). Default off => zero behavior change: every existing
98
- * (non-stub) test run resolves the exact same `window.__sdk` reference it did
99
- * before this plugin learned about stubbing.
100
- *
101
- * Per-method pacing (devtools#769): BEFORE the stub wrap, `window.__sdk` is
102
- * run through `wrapWithMethodPacing`, which enforces a minimum interval
103
- * between calls to the SAME named SDK function (`getPaceMethodMs()` reads the
104
- * `__AIT_PACE_METHOD_MS__` page global — see `method-pace.ts`). Composition
105
- * order is pacing INSIDE the stub (`wrapSdkWithStub(wrapWithMethodPacing(sdk,
106
- * gap), enabled)`): a stubbed name resolves instantly from
107
- * `bridge-stub.ts`'s fixtures without ever reaching the paced wrapper, and
108
- * only calls that fall through to the real bridge — the ones that can
109
- * actually trigger `APP_BRIDGE_THROTTLED` — pay the pacing cost. `gapMs <= 0`
110
- * (default, no `--pace-method` / non-2.x cell) is a no-op fast path — see
111
- * `method-pace.ts#wrapWithMethodPacing`'s doc for the full contract.
112
- */
113
- /**
114
- * Builds the virtual CommonJS-style module contents the `sdk-redirect`
115
- * esbuild plugin loads for every `@apps-in-toss/web-framework` import.
116
- *
117
- * Pulled out to a pure, exported function (rather than inlined at the
118
- * `build.onLoad` call site) so unit tests can assert the exact composition
119
- * order (pacing wraps the raw SDK; the stub wraps the paced result) as a
120
- * string-level contract, independent of esbuild — esbuild cannot run inside
121
- * this repo's jsdom vitest environment (see `bundleTestFile`'s module doc's
122
- * lazy-import note), so a real bundling round-trip is out of unit-test reach
123
- * here; `wrapSdkWithStub`/`wrapWithMethodPacing`'s own composed-call behavior
124
- * is covered directly (see `bundle.test.ts`).
125
- *
126
- * Generates a virtual CommonJS-style module so that esbuild does NOT perform
127
- * strict named-export matching. When `format:'iife'` bundles a CJS module, it
128
- * wraps it with its own `__toCommonJS` helper and satisfies named imports via
129
- * property access on the `module.exports` object — which is our Proxy. This
130
- * means `import { getPlatformOS } from '...'` becomes
131
- * `__proxy.getPlatformOS` at runtime, which correctly reads from
132
- * `window.__sdk`.
133
- *
134
- * The bridge-stub and method-pace imports are STATIC imports of the real
135
- * `bridge-stub.ts`/`method-pace.ts` modules (not inlined JS) so esbuild
136
- * bundles each once and the fixture registry / pacing registry have a single
137
- * source of truth shared with their own unit tests.
138
- *
139
- * Exported for unit testing.
140
- */
141
- declare function buildSdkRedirectModuleContents(): string;
142
- /**
143
- * Bundles `absPath` into a single IIFE string suitable for `Runtime.evaluate`.
144
- *
145
- * The IIFE installs `window.__testBundle` (or the custom `globalName`) with:
146
- * - `runTestModule` — the runtime entry (from `runtime.ts`).
147
- * - `__userFactory` — an async function wrapping the user's test registration
148
- * code so it runs AFTER `runTestModule` installs the globals.
149
- *
150
- * Callers (rpc.ts) invoke:
151
- * `globalThis.__testBundle.runTestModule(globalThis.__testBundle.__userFactory)`
152
- *
153
- * @param absPath - Absolute path to the user test file.
154
- * @param opts - Optional bundling overrides.
155
- */
156
- declare function bundleTestFile(absPath: string, opts?: BundleOptions): Promise<BundleResult>;
157
- //#endregion
158
- export { bundleTestFile as i, BundleResult as n, buildSdkRedirectModuleContents as r, BundleOptions as t };
159
- //# sourceMappingURL=bundle-C796JIwG.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bundle-C796JIwG.d.ts","names":[],"sources":["../src/test-runner/bundle.ts"],"mappings":";;AAqEA;;;;;AAmBA;;;;;AA+FA;;;;;AA4UA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA9biB,aAAA;;;;;;;EAOf,cAAA;;;;;EAKA,UAAA;AAAA;;;;;UAOe,YAAA;EACf,IAAA;EACA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6Fc,8BAAA,CAAA;;;;;;;;;;;;;;;iBA4UM,cAAA,CAAe,OAAA,UAAiB,IAAA,GAAO,aAAA,GAAgB,OAAA,CAAQ,YAAA"}
@@ -1,58 +0,0 @@
1
- //#region src/test-runner/capture.d.ts
2
- /**
3
- * `__AIT_CAPTURE__` console-line parser (devtools#696).
4
- *
5
- * env3 test runs inject sdk-example's `aitCapture.ts`, which — when running in a
6
- * WebView (no filesystem) — emits one `console.log` line per category in the
7
- * stable form:
8
- *
9
- * __AIT_CAPTURE__ <category> <json>
10
- *
11
- * The relay-worker harvests `Runtime.consoleAPICalled` events as plain text
12
- * lines (see `relay-worker.ts`) and hands them here. This module's only job is
13
- * to recognise the allowlisted prefix, split off the category, and keep the
14
- * remaining JSON string OPAQUE — devtools does NOT own or interpret the
15
- * `__AIT_CAPTURE__` record shape (that lives in sdk-example). We carry
16
- * `{ category, json }` through untouched so the 2.x↔3.0 line comparison stays a
17
- * downstream concern.
18
- *
19
- * Why a strict allowlist prefix (SECRET-HANDLING): the raw console stream may
20
- * also contain wss/scheme/relay noise lines. Only lines that EXACTLY start with
21
- * `'__AIT_CAPTURE__ '` pass; everything else is discarded, so a stray relay URL
22
- * can never be serialised into a capture artifact.
23
- *
24
- * react-free, dependency-free — safe to import from any test-runner entry
25
- * without dragging in the chii/cloudflared Node graph.
26
- */
27
- /**
28
- * One parsed capture line. `json` is the raw JSON string exactly as the page
29
- * emitted it (an array of sdk-example capture records). devtools treats it as
30
- * opaque — it is validated as parseable JSON but never inspected.
31
- */
32
- interface AitCaptureLine {
33
- /** The capture category (first whitespace-delimited token after the prefix). */
34
- category: string;
35
- /** The remaining JSON payload, verbatim. Opaque to devtools. */
36
- json: string;
37
- }
38
- /**
39
- * Parses raw console line texts into {@link AitCaptureLine}s.
40
- *
41
- * Filtering rules (each independently drops a line — never throws):
42
- * - the line text must `startsWith(CAPTURE_PREFIX)` exactly (allowlist);
43
- * - there must be a non-empty category token (up to the next space);
44
- * - the remaining payload must be valid JSON (`JSON.parse` succeeds).
45
- *
46
- * Lines that fail any rule (wss/scheme noise, truncated, broken JSON) are
47
- * silently discarded — capture harvesting is best-effort and must never fail a
48
- * run or leak a malformed/secret-bearing line.
49
- *
50
- * @param raw - Console line objects (only `.text` is read).
51
- * @returns The captured lines, in input order.
52
- */
53
- declare function parseCaptureLines(raw: ReadonlyArray<{
54
- text: string;
55
- }>): AitCaptureLine[];
56
- //#endregion
57
- export { parseCaptureLines as n, AitCaptureLine as t };
58
- //# sourceMappingURL=capture-DsP525OZ.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"capture-DsP525OZ.d.ts","names":[],"sources":["../src/test-runner/capture.ts"],"mappings":";;AA+BA;;;;;AAyBA;;;;;;;;;;;;;;;;;;;;;;;;UAzBiB,cAAA;;EAEf,QAAA;;EAEA,IAAA;AAAA;;;;;;;;;;;;;;;;iBAqBc,iBAAA,CAAkB,GAAA,EAAK,aAAA;EAAgB,IAAA;AAAA,KAAkB,cAAA"}
@@ -1,287 +0,0 @@
1
- //#region src/mcp/cdp-connection.d.ts
2
- /**
3
- * Injectable CDP connection abstraction for the debug-mode MCP server.
4
- *
5
- * The Phase 1 tool layer (`list_console_messages`, `list_network_requests`,
6
- * `list_pages`) reads from CDP events captured off a Chii relay connection.
7
- * To keep that tool layer CI-verifiable without a phone roundtrip, the actual
8
- * relay websocket sits behind this interface. Production wires
9
- * `ChiiCdpConnection` (see `chii-connection.ts`); tests inject a fake that
10
- * emits canned `Runtime.consoleAPICalled` / `Network.*` events.
11
- *
12
- * Phase 2 adds CDP *commands* (request→response): `DOM.getDocument`,
13
- * `DOMSnapshot.captureSnapshot`, `Page.captureScreenshot`. Unlike Phase 1's
14
- * event streams these need a `send(method, params)` round-trip, so the
15
- * connection grows a typed `send`. The fake returns canned command results.
16
- *
17
- * Phase 2 extension: `Runtime.evaluate` (read-only probe) added for the
18
- * `measure_safe_area` tool — executes a JS snippet on the attached page and
19
- * returns the result as a `RemoteObject`. The fake returns canned results for
20
- * unit tests without a phone roundtrip.
21
- *
22
- * Only the slice of the Chrome DevTools Protocol the tools need is typed here.
23
- */
24
- /** A target (page) the Chii relay currently sees attached. */
25
- interface CdpTarget {
26
- /** Chii's internal target id (session UUID). */
27
- id: string;
28
- /** Page title reported by the in-app target. */
29
- title: string;
30
- /** Page URL reported by the in-app target. */
31
- url: string;
32
- }
33
- /** `Runtime.RemoteObject` subset we surface for console args. */
34
- interface CdpRemoteObject {
35
- type: string;
36
- subtype?: string;
37
- value?: unknown;
38
- description?: string;
39
- className?: string;
40
- }
41
- /** Payload of a `Runtime.consoleAPICalled` event. */
42
- interface ConsoleApiCalledEvent {
43
- /** log | warning | error | info | debug | … */
44
- type: string;
45
- args: CdpRemoteObject[];
46
- /** Milliseconds since epoch (CDP `Runtime.Timestamp`). */
47
- timestamp: number;
48
- executionContextId?: number;
49
- stackTrace?: {
50
- callFrames: Array<{
51
- functionName: string;
52
- url: string;
53
- lineNumber: number;
54
- columnNumber: number;
55
- }>;
56
- };
57
- }
58
- /** Payload of a `Network.requestWillBeSent` event (subset). */
59
- interface NetworkRequestWillBeSentEvent {
60
- requestId: string;
61
- request: {
62
- url: string;
63
- method: string;
64
- headers?: Record<string, string>;
65
- };
66
- /** CDP `Network.MonotonicTime` (seconds). */
67
- timestamp: number;
68
- /** Wall-clock seconds since epoch, when available. */
69
- wallTime?: number;
70
- type?: string;
71
- }
72
- /** Payload of a `Network.responseReceived` event (subset). */
73
- interface NetworkResponseReceivedEvent {
74
- requestId: string;
75
- response: {
76
- url: string;
77
- status: number;
78
- statusText: string;
79
- mimeType?: string;
80
- };
81
- timestamp: number;
82
- type?: string;
83
- }
84
- /**
85
- * A single call frame in a `Runtime.exceptionThrown` stack trace.
86
- * Subset of the CDP `Runtime.CallFrame` shape.
87
- */
88
- interface CdpCallFrame {
89
- functionName: string;
90
- scriptId?: string;
91
- url: string;
92
- lineNumber: number;
93
- columnNumber: number;
94
- }
95
- /** Payload of a `Runtime.exceptionThrown` event. */
96
- interface RuntimeExceptionThrownEvent {
97
- /** Milliseconds since epoch (CDP `Runtime.Timestamp`). */
98
- timestamp: number;
99
- exceptionDetails: {
100
- exceptionId: number;
101
- text: string;
102
- lineNumber: number;
103
- columnNumber: number;
104
- scriptId?: string;
105
- url?: string;
106
- stackTrace?: {
107
- callFrames: CdpCallFrame[];
108
- }; /** The thrown value as a CDP `RemoteObject`. */
109
- exception?: CdpRemoteObject;
110
- };
111
- }
112
- /** Map of the CDP event names Phase 1 consumes to their payload shapes. */
113
- interface CdpEventMap {
114
- 'Runtime.consoleAPICalled': ConsoleApiCalledEvent;
115
- 'Network.requestWillBeSent': NetworkRequestWillBeSentEvent;
116
- 'Network.responseReceived': NetworkResponseReceivedEvent;
117
- 'Runtime.exceptionThrown': RuntimeExceptionThrownEvent;
118
- }
119
- type CdpEventName = keyof CdpEventMap;
120
- /** A `DOM.Node` subset (recursive) returned by `DOM.getDocument`. */
121
- interface CdpDomNode {
122
- nodeId: number;
123
- /** CDP node type (1 = element, 3 = text, 9 = document, …). */
124
- nodeType: number;
125
- nodeName: string;
126
- /** Tag/local name for elements. */
127
- localName?: string;
128
- nodeValue?: string;
129
- /** Flattened attribute list: `[name, value, name, value, …]`. */
130
- attributes?: string[];
131
- childNodeCount?: number;
132
- children?: CdpDomNode[];
133
- documentURL?: string;
134
- baseURL?: string;
135
- }
136
- /** Result of `DOM.getDocument`. */
137
- interface DomGetDocumentResult {
138
- root: CdpDomNode;
139
- }
140
- /** Result of `DOMSnapshot.captureSnapshot` (subset we surface). */
141
- interface DomSnapshotResult {
142
- documents: unknown[];
143
- strings: string[];
144
- }
145
- /** Result of `Page.captureScreenshot`. */
146
- interface PageCaptureScreenshotResult {
147
- /** Base64-encoded image bytes (PNG by default). */
148
- data: string;
149
- }
150
- /**
151
- * Params for `Runtime.evaluate`.
152
- * Covers the subset used by the `measure_safe_area` read-only probe.
153
- */
154
- interface RuntimeEvaluateParams {
155
- /** JavaScript expression to evaluate in the page context. */
156
- expression: string;
157
- /** Return the result as a plain JSON value (vs. a handle). Default false. */
158
- returnByValue?: boolean;
159
- /** Await a returned Promise before resolving. Default false. */
160
- awaitPromise?: boolean;
161
- }
162
- /** Result of `Runtime.evaluate`. */
163
- interface RuntimeEvaluateResult {
164
- /** The evaluation result. */
165
- result: CdpRemoteObject;
166
- /** Present when evaluation threw an uncaught exception. */
167
- exceptionDetails?: {
168
- text: string;
169
- exception?: CdpRemoteObject;
170
- };
171
- }
172
- /**
173
- * Map of CDP command method → params/result shape. Keeps `send` typed so a
174
- * `DOM.getDocument` call resolves to a `DomGetDocumentResult`, etc.
175
- */
176
- interface CdpCommandMap {
177
- 'DOM.getDocument': {
178
- params: {
179
- depth?: number;
180
- pierce?: boolean;
181
- };
182
- result: DomGetDocumentResult;
183
- };
184
- 'DOMSnapshot.captureSnapshot': {
185
- params: {
186
- computedStyles?: string[];
187
- };
188
- result: DomSnapshotResult;
189
- };
190
- 'Page.captureScreenshot': {
191
- params: {
192
- format?: 'png' | 'jpeg' | 'webp';
193
- quality?: number;
194
- };
195
- result: PageCaptureScreenshotResult;
196
- };
197
- 'Runtime.evaluate': {
198
- params: RuntimeEvaluateParams;
199
- result: RuntimeEvaluateResult;
200
- };
201
- }
202
- type CdpCommandName = keyof CdpCommandMap;
203
- /**
204
- * The connection the tool layer reads from. The production implementation
205
- * wraps the Chii relay's CDP websocket; tests inject a fake.
206
- *
207
- * Implementations are expected to maintain an internal ring buffer of recent
208
- * events (so a tool call returns recent history rather than only live events).
209
- */
210
- interface CdpConnection {
211
- /**
212
- * Authoritative kind of this connection's transport (issue #348).
213
- *
214
- * - `'relay'` — backed by the Chii relay + cloudflared tunnel (a real-device
215
- * WebView, env 3/4). `ChiiCdpConnection`.
216
- * - `'local'` — backed by a direct CDP websocket to a local Chromium (env 1).
217
- * `LocalCdpConnection`.
218
- *
219
- * This replaces the old `getEnvironment()` URL-pattern sniffing: the
220
- * `mock` vs `relay` split is now a free, authoritative property of the
221
- * connection itself, known before any target attaches. The `relay-dev` vs
222
- * `relay-live` distinction is orthogonal (operator-supplied `liveIntent`,
223
- * see `environment.ts`) because dog-food and production relays are
224
- * byte-identical on the wire.
225
- */
226
- readonly kind: 'relay' | 'local';
227
- /**
228
- * Enable the CDP domains Phase 1 needs (`Runtime.enable`, `Network.enable`).
229
- * Idempotent. Resolves once the relay has acknowledged (or immediately for a
230
- * fake connection).
231
- */
232
- enableDomains(): Promise<void>;
233
- /** Targets (pages) the relay currently sees attached. */
234
- listTargets(): CdpTarget[];
235
- /** Recent buffered events for a domain, oldest-first. */
236
- getBufferedEvents<E extends CdpEventName>(event: E): ReadonlyArray<CdpEventMap[E]>;
237
- /** Subscribe to live events. Returns an unsubscribe function. */
238
- on<E extends CdpEventName>(event: E, listener: (payload: CdpEventMap[E]) => void): () => void;
239
- /**
240
- * Issue a CDP command (request → response). Phase 2's DOM/snapshot/screenshot
241
- * tools use this; resolves with the typed result or rejects on a CDP error.
242
- * Implementations must have called {@link enableDomains} first.
243
- *
244
- * @param opts.timeoutMs - Per-call override for the connection's own command
245
- * watchdog (devtools#747). Optional — implementations without a per-command
246
- * watchdog (e.g. `LocalCdpConnection`) may ignore it. Callers that already
247
- * race `send` against their own longer timeout (e.g. the test-runner's
248
- * file-evaluate budget) MUST pass a `timeoutMs` at least as large as that
249
- * caller-side timeout, or the connection's shorter default watchdog fires
250
- * first and undercuts the caller's race.
251
- */
252
- send<M extends CdpCommandName>(method: M, params?: CdpCommandMap[M]['params'], opts?: {
253
- timeoutMs?: number;
254
- }): Promise<CdpCommandMap[M]['result']>;
255
- /**
256
- * Close the underlying transport and reject any in-flight commands.
257
- * Optional so that minimal test fakes that don't need teardown remain
258
- * compatible without change. Both `ChiiCdpConnection` and
259
- * `LocalCdpConnection` already implement this.
260
- */
261
- close?(): void;
262
- /**
263
- * Refresh the attached-target list from the relay and return the result.
264
- * Emits an internal `'target:attached'` event when a new target appears so
265
- * that {@link waitForFirstTarget} can race against the polling round.
266
- *
267
- * Optional — only `ChiiCdpConnection` (relay mode) supports this; local
268
- * connections and test fakes may omit it. Callers should guard with
269
- * `connection.refreshTargets?.()`.
270
- */
271
- refreshTargets?(): Promise<CdpTarget[]>;
272
- /**
273
- * Waits until at least one target satisfying `filterFn` is attached, then
274
- * resolves with the full target list at that moment.
275
- *
276
- * Optional — only `ChiiCdpConnection` provides the event-driven
277
- * implementation. When absent, callers fall back to a generic polling loop.
278
- *
279
- * @param filterFn - Predicate the resolved targets must satisfy.
280
- * @param timeoutMs - Reject after this many ms (default 90 000).
281
- * @param pollIntervalMs - Fallback poll interval (default 500 ms).
282
- */
283
- waitForFirstTarget?(filterFn: (targets: CdpTarget[]) => boolean, timeoutMs?: number, pollIntervalMs?: number): Promise<CdpTarget[]>;
284
- }
285
- //#endregion
286
- export { CdpConnection as t };
287
- //# sourceMappingURL=cdp-connection-rP1WdnH5.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cdp-connection-rP1WdnH5.d.ts","names":[],"sources":["../src/mcp/cdp-connection.ts"],"mappings":"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"}
@@ -1,68 +0,0 @@
1
- import { buildIndicatorExpression } from "./attach-orchestrator-D65KxFy_.js";
2
- //#region src/test-runner/cell.ts
3
- /**
4
- * Injects each key of `globals` into `globalThis` in the page via a single
5
- * `Runtime.evaluate` call. Must be called BEFORE the first `bundleTestFile`
6
- * inject — the cell is session-global and applies to all subsequent files.
7
- *
8
- * Throws if the CDP evaluate returns an exception.
9
- *
10
- * @param conn - The live CDP connection (relay-attached page).
11
- * @param globals - Plain-JSON-serialisable key→value map to assign onto `globalThis`.
12
- */
13
- async function injectGlobals(conn, globals) {
14
- const expr = `(() => { Object.assign(globalThis, ${JSON.stringify(globals)}); return true; })()`;
15
- const result = await conn.send("Runtime.evaluate", {
16
- expression: expr,
17
- returnByValue: true
18
- });
19
- if (result.exceptionDetails) {
20
- const msg = result.exceptionDetails.exception?.description ?? result.exceptionDetails.text ?? "unknown error";
21
- throw new Error(`injectGlobals: Runtime.evaluate threw: ${msg}`);
22
- }
23
- }
24
- /**
25
- * Injects (or updates) the "Debugger Connected"/"Debugger Disconnected"
26
- * on-phone indicator via `Runtime.evaluate` (#730).
27
- *
28
- * Uses the same CDP mechanism as {@link injectGlobals} — a single
29
- * `Runtime.evaluate` round-trip with the expression built by
30
- * {@link buildIndicatorExpression}. The indicator is a LIVE badge rendered at
31
- * the bottom-left of the page (position:fixed, safe-area-aware): the badge's
32
- * controller is idempotent, so calling this again (e.g. right before
33
- * `close()` with `{ state: 'disconnected' }`) UPDATES the existing badge in
34
- * place instead of injecting a duplicate.
35
- *
36
- * **Isolation**: unlike {@link injectGlobals}, this function NEVER throws to
37
- * its caller. Injection failure (e.g. page detached during inject, CSS not
38
- * supported) is swallowed and logged as `console.debug` — the badge is
39
- * informational UI and must never block attach success or test execution.
40
- * This is the same fire-and-forget spirit as the in-page console mount in
41
- * `src/in-app/attach.ts`.
42
- *
43
- * Call this ONLY on the manual debug paths (start_attach MCP, devtools-test
44
- * CLI). Do NOT call on the `run_tests` auto-attach path — the badge
45
- * would contaminate screenshots, measure_safe_area probes, and DOM snapshots
46
- * taken during automated measurement runs.
47
- *
48
- * SECRET-HANDLING: the injected expression contains no secrets, relay URLs,
49
- * wss addresses, or TOTP codes — it is pure DOM UI text + enum state built by
50
- * {@link buildIndicatorExpression}.
51
- *
52
- * @param conn - The live CDP connection (relay-attached page).
53
- * @param opts - Optional overrides forwarded to {@link buildIndicatorExpression}.
54
- */
55
- async function injectDebugIndicator(conn, opts) {
56
- try {
57
- await conn.send("Runtime.evaluate", {
58
- expression: buildIndicatorExpression(opts),
59
- returnByValue: true
60
- });
61
- } catch (err) {
62
- console.debug("[@ait-co/devtools] debug indicator inject skipped:", err);
63
- }
64
- }
65
- //#endregion
66
- export { injectDebugIndicator, injectGlobals };
67
-
68
- //# sourceMappingURL=cell-BaLvusOl.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cell-BaLvusOl.js","names":[],"sources":["../src/test-runner/cell.ts"],"sourcesContent":["/**\n * Cell injection utility for the `devtools-test` CLI (issue #684 §4.1).\n *\n * Injects arbitrary globals into the page via `Runtime.evaluate` BEFORE the\n * first test bundle is injected. The injected values are session-global — one\n * call covers all files in the run.\n *\n * The primary use-case is injecting `__AIT_CELL__` (sdkLine/platform) so\n * sdk-example's `aitCapture.ts` picks up the correct test-axis values instead\n * of falling back to `'2.x'`/`'mock'`.\n *\n * devtools does NOT know the shape of `__AIT_CELL__` — it only provides the\n * general injection mechanism. The caller (CLI or MCP auto-attach path) is\n * responsible for constructing the cell object.\n *\n * SECRET-HANDLING: cell values (sdkLine/platform) are not secrets and may be\n * logged at the caller's discretion. This module does NOT log them itself.\n *\n * Node-only. react-free. CdpConnection only.\n */\n\nimport { THROTTLED_ERROR_CODE, THROTTLED_MESSAGE_SUBSTRING } from './throttle.js';\n\n/**\n * `__AIT_PERMS__` key → SDK function name whose `.getPermission()` is probed\n * (devtools#739). This is the exact contract sdk-example#265 consumes — do\n * not rename keys without a coordinated sdk-example update.\n *\n * Each SDK function is reached via `window.__sdk` — the SAME page-global\n * bridge `src/in-app/auto.ts` installs for `call_sdk`/`__sdkCall` (see\n * `src/test-runner/bundle.ts`'s `sdkRedirectPlugin`, which redirects bundled\n * `@apps-in-toss/web-framework` imports to this same object at runtime). The\n * test-runner bundle owns no independent SDK import — `window.__sdk` is a\n * page global regardless of whether a bundle has been injected yet, so this\n * preflight runs standalone via `injectGlobals`'s `Runtime.evaluate`\n * mechanism BEFORE the first bundle, rather than being prepended into\n * `rpc.ts#buildRunTestsExpression`. (Design choice documented in PR #739 —\n * bundle-prepend was the fallback plan if the SDK were only reachable from\n * inside bundle scope, which reality ruled out.)\n */\nconst PERMISSION_PROBE_MAP: Record<string, string> = {\n clipboardRead: 'getClipboardText',\n clipboardWrite: 'setClipboardText',\n album: 'fetchAlbumPhotos',\n camera: 'openCamera',\n contacts: 'fetchContacts',\n location: 'getCurrentLocation',\n};\n\n/**\n * Inter-probe spacing (ms) applied BEFORE every probe after the first\n * (devtools#767). The native per-method bridge rate limit observed\n * 2026-07-10 rejects a SECOND call to the same method within a short window\n * with `APP_BRIDGE_THROTTLED` — the permission preflight's un-paced burst\n * (6 probes fired back-to-back) was the FIRST trigger of that limiter in the\n * wild (only the first probe passed; the remaining 5 came back throttled →\n * `unavailable`, cascading into skipped `__AIT_PERMS__`-branching tests).\n * Sequential-with-spacing is cheap insurance even though each probe targets a\n * DIFFERENT method — the limiter's exact scope (per-method vs. a shared\n * bridge-wide window) was not reverse-engineered (explicitly out of scope,\n * devtools#767) so spacing every probe is the conservative choice.\n */\nconst PROBE_INTER_CALL_DELAY_MS = 250;\n\n/**\n * Backoff delays (ms) between retry attempts when a probe is throttled. Its\n * `.length` IS the max retry count (devtools#767: \"최대 2회 재시도\") — the\n * generated page-side expression below derives `attempt < backoff.length`\n * from this same array (via `backoffArray`), so there is a single source for\n * both the delay ladder and the retry count; no separate max-retries\n * constant is kept in this module (unlike `runtime.ts`'s `TEST_MAX_RETRIES`,\n * which IS consumed directly by a Node-side loop condition).\n */\nconst PROBE_RETRY_BACKOFF_MS = [500, 1000] as const;\n\n/**\n * Non-fatal bound for the permission preflight `Runtime.evaluate` round-trip\n * (devtools#767: raised from the pre-pacing 10s to cover the new sequential +\n * backoff time budget).\n *\n * Worst-case budget with 6 probes, each requiring the full retry ladder:\n * - inter-probe spacing: only BEFORE probes 2‑6 (none before the first) =\n * 5 × {@link PROBE_INTER_CALL_DELAY_MS} = 1 250ms\n * - per-probe backoff (both retries taken): 6 × (500 + 1000) = 9 000ms\n * - probe round-trips themselves (headroom, not just the sleeps): ~4 500ms\n * total ≈ 14 750ms, rounded up to a clean 20 000ms for headroom.\n */\nexport const PERMISSION_PREFLIGHT_TIMEOUT_MS = 20_000;\n\n/**\n * Builds the `Runtime.evaluate` expression for the permission-state preflight\n * (devtools#739). Evaluated ONCE per relay session, before the first test\n * bundle is injected (see `relay-worker.ts#runTestFilesOverRelay`).\n *\n * For each entry in {@link PERMISSION_PROBE_MAP}, probes\n * `window.__sdk.<fn>.getPermission()` — a NON-blocking query (never\n * `openPermissionDialog`/`requestPermission`, which open native UI) — and\n * assigns the resolved `'allowed'|'denied'|'notDetermined'` status to\n * `globalThis.__AIT_PERMS__[<key>]`. A probe that is absent, throws, or\n * rejects resolves to `'unavailable'` — this expression never throws to its\n * caller, and a single slow/broken permission must not fail the others (each\n * probe is awaited independently, not short-circuited).\n *\n * devtools#767: probes run SEQUENTIALLY (not a parallel burst) with a\n * {@link PROBE_INTER_CALL_DELAY_MS} gap before each probe after the first, and\n * a probe that comes back `APP_BRIDGE_THROTTLED` (native per-method bridge\n * rate limit) is retried up to {@link PROBE_RETRY_BACKOFF_MS}`.length` times\n * with the same {@link PROBE_RETRY_BACKOFF_MS} ladder before falling back to\n * `'unavailable'`.\n * The THROTTLED detection mirrors `throttle.ts#isThrottledError` inline (this\n * expression is raw JS text evaluated via CDP, not an esbuild-bundled module,\n * so it cannot statically `import` that helper) — kept in sync by checking\n * BOTH `e.code === 'APP_BRIDGE_THROTTLED'` and a message substring match, the\n * same two signals `isThrottledError` checks.\n *\n * devtools#767 acceptance criteria 2 (\"3.x run duration은 유의미하게 늘지 않음,\n * pacing은 opt-in 또는 throttle-adaptive\") requires this NOT be an unconditional\n * cost — `pace` (default `true`, matching the pre-existing sequential+spacing\n * behavior for 2.x/unknown cells) lets a 3.x caller skip BOTH the inter-probe\n * `sleep(250)` AND the retry backoff ladder, since `APP_BRIDGE_THROTTLED` is a\n * 2.x-bridge-only limiter (see `--pace`'s own doc in `cli.ts`: \"3.x cells are\n * unaffected by that limiter\"). When `pace` is `false`, probes still run\n * sequentially (never a parallel burst) but back-to-back with no added delay,\n * and a THROTTLED result resolves to `'unavailable'` immediately (no retry) —\n * this matches the 3.x runtime, which never emits `APP_BRIDGE_THROTTLED`.\n *\n * Tests (sdk-example#265) read `globalThis.__AIT_PERMS__` to branch\n * deterministically per permission state instead of blanket outcome-branching.\n *\n * Returns a JSON-serialised string (the same double-serialisation pattern\n * `rpc.ts#buildRunTestsExpression` uses) rather than relying on CDP\n * `returnByValue` structural fidelity for a plain object across the Chii\n * relay — the Node side re-parses via `JSON.parse`.\n *\n * Pure function — no I/O, no CDP call. Callers pass the returned string to\n * `Runtime.evaluate`.\n *\n * @param pace - Defaults to `true` (today's sequential+spacing+backoff\n * behavior). Pass `false` for a 3.x cell to skip the inter-probe delay and\n * the THROTTLED retry ladder entirely.\n */\nexport function buildPermissionPreflightExpression(pace = true): string {\n const probeKeys = Object.keys(PERMISSION_PROBE_MAP);\n const probeCalls = probeKeys\n .map((key, i) => {\n const fnName = PERMISSION_PROBE_MAP[key];\n // Every probe after the first waits PROBE_INTER_CALL_DELAY_MS first —\n // sequential execution with spacing, never a parallel burst. Skipped\n // entirely when `pace` is false (3.x cell — no native limiter to dodge).\n const spacing = i === 0 || !pace ? '' : ` await sleep(${PROBE_INTER_CALL_DELAY_MS});\\n`;\n return (\n `${spacing}` +\n ` result[${JSON.stringify(key)}] = await probeWithRetry(${JSON.stringify(fnName)});`\n );\n })\n .join('\\n');\n\n // 3.x cells never emit APP_BRIDGE_THROTTLED (it's a 2.x-bridge-only native\n // limiter) — an empty backoff ladder makes `probeWithRetry` resolve any\n // throw (throttled or not) to 'unavailable' on the FIRST attempt, with zero\n // retry sleeps, satisfying devtools#767 acceptance criteria 2.\n const backoffArray = pace ? `[${PROBE_RETRY_BACKOFF_MS.join(',')}]` : '[]';\n\n return (\n `(async () => {` +\n ` const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));` +\n ` const isThrottled = (e) => {` +\n ` if (!e) return false;` +\n ` if (e.code === ${JSON.stringify(THROTTLED_ERROR_CODE)}) return true;` +\n ` const msg = typeof e.message === 'string' ? e.message : '';` +\n ` return msg.indexOf(${JSON.stringify(THROTTLED_MESSAGE_SUBSTRING)}) !== -1;` +\n ` };` +\n ` const probe = async (fnName) => {` +\n ` const fn = globalThis.__sdk && globalThis.__sdk[fnName];` +\n ` if (!fn || typeof fn.getPermission !== 'function') return { ok: true, value: 'unavailable' };` +\n ` const status = await fn.getPermission();` +\n ` if (status === 'allowed' || status === 'denied' || status === 'notDetermined') return { ok: true, value: status };` +\n ` return { ok: true, value: 'unavailable' };` +\n ` };` +\n // probeWithRetry: up to PROBE_RETRY_BACKOFF_MS.length retries on THROTTLED,\n // backing off per PROBE_RETRY_BACKOFF_MS. Any OTHER throw (or a\n // non-throttled outcome) resolves to 'unavailable' immediately — only\n // THROTTLED gets a retry.\n ` const backoff = ${backoffArray};` +\n ` const probeWithRetry = async (fnName) => {` +\n ` for (let attempt = 0; attempt <= backoff.length; attempt++) {` +\n ` try {` +\n ` const r = await probe(fnName);` +\n ` return r.value;` +\n ` } catch (e) {` +\n ` if (isThrottled(e) && attempt < backoff.length) {` +\n ` await sleep(backoff[attempt]);` +\n ` continue;` +\n ` }` +\n ` return 'unavailable';` +\n ` }` +\n ` }` +\n ` return 'unavailable';` +\n ` };` +\n ` const result = {};` +\n `${probeCalls}\\n` +\n ` globalThis.__AIT_PERMS__ = result;` +\n ` return JSON.stringify(result);` +\n `})()`\n );\n}\n\n/**\n * Runs the permission-state preflight (devtools#739) via `Runtime.evaluate`\n * and returns the collected `__AIT_PERMS__` map, or `undefined` when the\n * preflight itself failed or timed out.\n *\n * NON-FATAL by design: any failure (CDP exception, timeout, page-side throw)\n * is caught here, logged as ONE stderr line, and swallowed — the whole test\n * run must proceed even when the preflight cannot complete (e.g. `window.__sdk`\n * not yet installed, or a page navigation mid-attach). Callers that want the\n * result for report provenance (`RelayRunReport.preflight`) get `undefined`\n * in that case, which downstream code treats the same as \"not run\".\n *\n * SECRET-HANDLING: no relay/wss/secret values are read or logged; only\n * permission-state strings cross this boundary.\n *\n * @param conn - The live CDP connection (relay-attached page).\n * @param timeoutMs - Round-trip bound. Defaults to {@link PERMISSION_PREFLIGHT_TIMEOUT_MS}.\n * @param pace - Forwarded to {@link buildPermissionPreflightExpression}.\n * Defaults to `true` (today's sequential+spacing+backoff behavior, correct\n * for 2.x/unknown cells). Callers that know the cell is 3.x should pass\n * `false` — devtools#767 acceptance criteria 2 requires 3.x run duration not\n * grow from this preflight, and 3.x never hits the 2.x-only\n * `APP_BRIDGE_THROTTLED` limiter this pacing exists to dodge.\n */\nexport async function runPermissionPreflight(\n conn: CdpConnection,\n timeoutMs = PERMISSION_PREFLIGHT_TIMEOUT_MS,\n pace = true,\n): Promise<Record<string, string> | undefined> {\n const TIMEOUT_SENTINEL = Symbol('permission-preflight-timeout');\n const timeoutPromise = new Promise<typeof TIMEOUT_SENTINEL>((resolve) =>\n setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs),\n );\n\n try {\n const evalPromise = conn.send('Runtime.evaluate', {\n expression: buildPermissionPreflightExpression(pace),\n returnByValue: true,\n awaitPromise: true,\n });\n\n const raceResult = await Promise.race([\n evalPromise.then((v) => ({ tag: 'eval' as const, v })),\n timeoutPromise.then(() => ({ tag: 'timeout' as const })),\n ]);\n\n if (raceResult.tag === 'timeout') {\n process.stderr.write(\n `test-runner: permission preflight timed out after ${timeoutMs}ms — proceeding with __AIT_PERMS__ unset\\n`,\n );\n return undefined;\n }\n\n if (raceResult.v.exceptionDetails) {\n process.stderr.write(\n 'test-runner: permission preflight threw — proceeding with __AIT_PERMS__ unset\\n',\n );\n return undefined;\n }\n\n const rawValue = raceResult.v.result.value;\n if (typeof rawValue !== 'string') return undefined;\n const parsed: unknown = JSON.parse(rawValue);\n if (typeof parsed !== 'object' || parsed === null) return undefined;\n return parsed as Record<string, string>;\n } catch (e) {\n process.stderr.write(\n `test-runner: permission preflight failed (${\n e instanceof Error ? e.message : String(e)\n }) — proceeding with __AIT_PERMS__ unset\\n`,\n );\n return undefined;\n }\n}\n\nimport { buildIndicatorExpression } from '../mcp/attach-orchestrator.js';\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\n\n/**\n * Injects each key of `globals` into `globalThis` in the page via a single\n * `Runtime.evaluate` call. Must be called BEFORE the first `bundleTestFile`\n * inject — the cell is session-global and applies to all subsequent files.\n *\n * Throws if the CDP evaluate returns an exception.\n *\n * @param conn - The live CDP connection (relay-attached page).\n * @param globals - Plain-JSON-serialisable key→value map to assign onto `globalThis`.\n */\nexport async function injectGlobals(\n conn: CdpConnection,\n globals: Record<string, unknown>,\n): Promise<void> {\n // JSON.stringify is safe here: globals values are plain data (sdkLine/platform\n // strings or simple objects). If a value is not JSON-serialisable this throws\n // at call time, which surfaces the error early and clearly.\n const expr = `(() => { Object.assign(globalThis, ${JSON.stringify(globals)}); return true; })()`;\n const result = await conn.send('Runtime.evaluate', { expression: expr, returnByValue: true });\n if (result.exceptionDetails) {\n const msg =\n result.exceptionDetails.exception?.description ??\n result.exceptionDetails.text ??\n 'unknown error';\n throw new Error(`injectGlobals: Runtime.evaluate threw: ${msg}`);\n }\n}\n\n/**\n * Injects (or updates) the \"Debugger Connected\"/\"Debugger Disconnected\"\n * on-phone indicator via `Runtime.evaluate` (#730).\n *\n * Uses the same CDP mechanism as {@link injectGlobals} — a single\n * `Runtime.evaluate` round-trip with the expression built by\n * {@link buildIndicatorExpression}. The indicator is a LIVE badge rendered at\n * the bottom-left of the page (position:fixed, safe-area-aware): the badge's\n * controller is idempotent, so calling this again (e.g. right before\n * `close()` with `{ state: 'disconnected' }`) UPDATES the existing badge in\n * place instead of injecting a duplicate.\n *\n * **Isolation**: unlike {@link injectGlobals}, this function NEVER throws to\n * its caller. Injection failure (e.g. page detached during inject, CSS not\n * supported) is swallowed and logged as `console.debug` — the badge is\n * informational UI and must never block attach success or test execution.\n * This is the same fire-and-forget spirit as the in-page console mount in\n * `src/in-app/attach.ts`.\n *\n * Call this ONLY on the manual debug paths (start_attach MCP, devtools-test\n * CLI). Do NOT call on the `run_tests` auto-attach path — the badge\n * would contaminate screenshots, measure_safe_area probes, and DOM snapshots\n * taken during automated measurement runs.\n *\n * SECRET-HANDLING: the injected expression contains no secrets, relay URLs,\n * wss addresses, or TOTP codes — it is pure DOM UI text + enum state built by\n * {@link buildIndicatorExpression}.\n *\n * @param conn - The live CDP connection (relay-attached page).\n * @param opts - Optional overrides forwarded to {@link buildIndicatorExpression}.\n */\nexport async function injectDebugIndicator(\n conn: CdpConnection,\n opts?: { label?: string; disconnectedLabel?: string; state?: 'attached' | 'disconnected' },\n): Promise<void> {\n try {\n await conn.send('Runtime.evaluate', {\n expression: buildIndicatorExpression(opts),\n returnByValue: true,\n });\n } catch (err) {\n // Badge injection is informational UI — swallow and log; never propagate.\n console.debug('[@ait-co/devtools] debug indicator inject skipped:', err);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAuSA,eAAsB,cACpB,MACA,SACe;CAIf,MAAM,OAAO,sCAAsC,KAAK,UAAU,QAAQ,CAAC;CAC3E,MAAM,SAAS,MAAM,KAAK,KAAK,oBAAoB;EAAE,YAAY;EAAM,eAAe;EAAM,CAAC;AAC7F,KAAI,OAAO,kBAAkB;EAC3B,MAAM,MACJ,OAAO,iBAAiB,WAAW,eACnC,OAAO,iBAAiB,QACxB;AACF,QAAM,IAAI,MAAM,0CAA0C,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCpE,eAAsB,qBACpB,MACA,MACe;AACf,KAAI;AACF,QAAM,KAAK,KAAK,oBAAoB;GAClC,YAAY,yBAAyB,KAAK;GAC1C,eAAe;GAChB,CAAC;UACK,KAAK;AAEZ,UAAQ,MAAM,sDAAsD,IAAI"}