@ait-co/devtools 0.1.116 → 0.1.117

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.
@@ -1723,9 +1723,57 @@ async function renderAndMaybeWait(deps, prep, waitForAttach, callTimeoutMs, conn
1723
1723
  ...totpResult() ? { totp: totpResult() } : {}
1724
1724
  }, null, 2)}\n\n${qr}`);
1725
1725
  }
1726
+ /**
1727
+ * Builds a self-contained IIFE DOM expression that renders a dismissible
1728
+ * "Debugger Connected" badge on the bottom-left of the phone screen.
1729
+ *
1730
+ * **Pure function** — returns a JS expression string; does NOT inject it.
1731
+ * Injection is performed by {@link injectDebugIndicator} in `cell.ts`.
1732
+ *
1733
+ * The expression, when evaluated on the page, does the following:
1734
+ * 1. Early-returns if `#__ait_debug_indicator` already exists (idempotent —
1735
+ * prevents duplicate badges on re-injection after page reload).
1736
+ * 2. Appends a fixed-position `<div id="__ait_debug_indicator">` at the
1737
+ * bottom-left, accounting for safe-area insets.
1738
+ * 3. Attaches a `{ once: true }` `pointerdown` listener that removes the
1739
+ * badge on first touch — one-tap dismiss.
1740
+ *
1741
+ * The expression intentionally contains NO relay URLs, wss addresses, TOTP
1742
+ * codes, or any other secrets. It is pure DOM UI text only.
1743
+ *
1744
+ * SECRET-HANDLING: this expression contains no secrets, relay URLs, wss
1745
+ * addresses, or TOTP codes whatsoever — DOM label text only.
1746
+ *
1747
+ * @param opts.label - Badge text (default: `'Debugger Connected'`).
1748
+ * @returns A JS expression string suitable for `Runtime.evaluate`.
1749
+ */
1750
+ function buildIndicatorExpression(opts) {
1751
+ const label = opts?.label ?? "Debugger Connected";
1752
+ return `(() => {if (document.getElementById('__ait_debug_indicator')) return;const el = document.createElement('div');el.id = '__ait_debug_indicator';el.style.cssText = ['position:fixed','left:max(12px,calc(env(safe-area-inset-left,0px) + 8px))','bottom:max(12px,calc(env(safe-area-inset-bottom,0px) + 8px))','z-index:2147483647','background:#e5484d','color:#fff','font:bold 11px/1 system-ui,sans-serif','padding:5px 9px','border-radius:6px','pointer-events:auto','user-select:none',].join(';');el.textContent = ${JSON.stringify(label)};el.addEventListener('pointerdown', () => el.remove(), { once: true });document.body.appendChild(el);})()`;
1753
+ }
1726
1754
  //#endregion
1727
1755
  //#region src/test-runner/cell.ts
1728
1756
  /**
1757
+ * Cell injection utility for the `devtools-test` CLI (issue #684 §4.1).
1758
+ *
1759
+ * Injects arbitrary globals into the page via `Runtime.evaluate` BEFORE the
1760
+ * first test bundle is injected. The injected values are session-global — one
1761
+ * call covers all files in the run.
1762
+ *
1763
+ * The primary use-case is injecting `__AIT_CELL__` (sdkLine/platform) so
1764
+ * sdk-example's `aitCapture.ts` picks up the correct test-axis values instead
1765
+ * of falling back to `'2.x'`/`'mock'`.
1766
+ *
1767
+ * devtools does NOT know the shape of `__AIT_CELL__` — it only provides the
1768
+ * general injection mechanism. The caller (CLI or MCP auto-attach path) is
1769
+ * responsible for constructing the cell object.
1770
+ *
1771
+ * SECRET-HANDLING: cell values (sdkLine/platform) are not secrets and may be
1772
+ * logged at the caller's discretion. This module does NOT log them itself.
1773
+ *
1774
+ * Node-only. react-free. CdpConnection only.
1775
+ */
1776
+ /**
1729
1777
  * Injects each key of `globals` into `globalThis` in the page via a single
1730
1778
  * `Runtime.evaluate` call. Must be called BEFORE the first `bundleTestFile`
1731
1779
  * inject — the cell is session-global and applies to all subsequent files.
@@ -1746,6 +1794,43 @@ async function injectGlobals(conn, globals) {
1746
1794
  throw new Error(`injectGlobals: Runtime.evaluate threw: ${msg}`);
1747
1795
  }
1748
1796
  }
1797
+ /**
1798
+ * Injects the "Debugger Connected" on-phone indicator via `Runtime.evaluate`.
1799
+ *
1800
+ * Uses the same CDP mechanism as {@link injectGlobals} — a single
1801
+ * `Runtime.evaluate` round-trip with the expression built by
1802
+ * {@link buildIndicatorExpression}. The indicator is a dismissible red badge
1803
+ * rendered at the bottom-left of the page (position:fixed, safe-area-aware).
1804
+ *
1805
+ * **Isolation**: unlike {@link injectGlobals}, this function NEVER throws to
1806
+ * its caller. Injection failure (e.g. page detached during inject, CSS not
1807
+ * supported) is swallowed and logged as `console.debug` — the badge is
1808
+ * informational UI and must never block attach success or test execution.
1809
+ * This is the same fire-and-forget spirit as the eruda mount in
1810
+ * `src/in-app/attach.ts`.
1811
+ *
1812
+ * Call this ONLY on the manual debug paths (start_attach MCP, devtools-test
1813
+ * CLI). Do NOT call on the `run_tests` auto-attach path — the red badge
1814
+ * would contaminate screenshots, measure_safe_area probes, and DOM snapshots
1815
+ * taken during automated measurement runs.
1816
+ *
1817
+ * SECRET-HANDLING: the injected expression contains no secrets, relay URLs,
1818
+ * wss addresses, or TOTP codes — it is pure DOM UI text built by
1819
+ * {@link buildIndicatorExpression}.
1820
+ *
1821
+ * @param conn - The live CDP connection (relay-attached page).
1822
+ * @param opts - Optional overrides forwarded to {@link buildIndicatorExpression}.
1823
+ */
1824
+ async function injectDebugIndicator(conn, opts) {
1825
+ try {
1826
+ await conn.send("Runtime.evaluate", {
1827
+ expression: buildIndicatorExpression(opts),
1828
+ returnByValue: true
1829
+ });
1830
+ } catch (err) {
1831
+ console.debug("[@ait-co/devtools] debug indicator inject skipped:", err);
1832
+ }
1833
+ }
1749
1834
  //#endregion
1750
1835
  //#region src/test-runner/discover.ts
1751
1836
  /**
@@ -2404,7 +2489,7 @@ async function main(argv = process.argv.slice(2)) {
2404
2489
  process.stderr.write(`devtools-test: found ${files.length} test file(s)\n`);
2405
2490
  const { loadRelaySecretReadOnly } = await import("./relay-secret-store-CmqchhR5.js");
2406
2491
  await loadRelaySecretReadOnly({ projectRoot });
2407
- const { bootRelayFamily, buildRelayVerifyAuth } = await import("./debug-server-DcAKrbnq.js");
2492
+ const { bootRelayFamily, buildRelayVerifyAuth } = await import("./debug-server-BvrESnaV.js");
2408
2493
  let family;
2409
2494
  try {
2410
2495
  family = await bootRelayFamily({ verifyAuth: buildRelayVerifyAuth() });
@@ -2440,6 +2525,7 @@ async function main(argv = process.argv.slice(2)) {
2440
2525
  return;
2441
2526
  }
2442
2527
  for (const chunk of waitResult.content) if (chunk.type === "text") process.stdout.write(`${chunk.text}\n`);
2528
+ await injectDebugIndicator(family.connection);
2443
2529
  if (hasCell) {
2444
2530
  const cell = {};
2445
2531
  if (cellSdkLine !== void 0) cell.sdkLine = cellSdkLine;
@@ -2463,4 +2549,4 @@ if (import.meta.url === new URL(process.argv[1], "file://").href) main().catch((
2463
2549
  //#endregion
2464
2550
  export { START_ATTACH_SEGMENT_MS as a, generateAttachToken as c, startQuickTunnel as d, startTunnelHealthProbe as f, START_ATTACH_REMINT_THRESHOLD_MS as i, makeTunnelStatus as l, logInfo as m, runWithConnection as n, extractDeploymentId as o, logError as p, RELAY_SANDBOX_STALE_PAGE_MS as r, isSandboxPageFresh as s, main as t, printAttachBanner as u };
2465
2551
 
2466
- //# sourceMappingURL=cli-BLBo0lkP.js.map
2552
+ //# sourceMappingURL=cli-CvUNQKqw.js.map