@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.
@@ -7,12 +7,12 @@ import { fileURLToPath } from "node:url";
7
7
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
8
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
9
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
10
- import { parseArgs } from "node:util";
11
10
  import { homedir, platform } from "node:os";
12
11
  import * as path from "node:path";
13
12
  import { isAbsolute, join, resolve } from "node:path";
14
13
  import { randomBytes } from "node:crypto";
15
14
  import { Tunnel, bin, install } from "cloudflared";
15
+ import { parseArgs } from "node:util";
16
16
  import * as fs from "node:fs/promises";
17
17
  import { glob } from "node:fs/promises";
18
18
  import { EventEmitter } from "node:events";
@@ -221,29 +221,6 @@ function startMaxAgeWatchdog(onExpired, opts = {}) {
221
221
  } };
222
222
  }
223
223
  //#endregion
224
- //#region src/test-runner/cell.ts
225
- /**
226
- * Injects each key of `globals` into `globalThis` in the page via a single
227
- * `Runtime.evaluate` call. Must be called BEFORE the first `bundleTestFile`
228
- * inject — the cell is session-global and applies to all subsequent files.
229
- *
230
- * Throws if the CDP evaluate returns an exception.
231
- *
232
- * @param conn - The live CDP connection (relay-attached page).
233
- * @param globals - Plain-JSON-serialisable key→value map to assign onto `globalThis`.
234
- */
235
- async function injectGlobals(conn, globals) {
236
- const expr = `(() => { Object.assign(globalThis, ${JSON.stringify(globals)}); return true; })()`;
237
- const result = await conn.send("Runtime.evaluate", {
238
- expression: expr,
239
- returnByValue: true
240
- });
241
- if (result.exceptionDetails) {
242
- const msg = result.exceptionDetails.exception?.description ?? result.exceptionDetails.text ?? "unknown error";
243
- throw new Error(`injectGlobals: Runtime.evaluate threw: ${msg}`);
244
- }
245
- }
246
- //#endregion
247
224
  //#region src/mcp/deeplink.ts
248
225
  /**
249
226
  * URL of the AITC Sandbox launcher PWA.
@@ -2057,7 +2034,7 @@ async function readMcpSdkVersion() {
2057
2034
  * some test environments that skip the build step).
2058
2035
  */
2059
2036
  function readDevtoolsVersion() {
2060
- return "0.1.116";
2037
+ return "0.1.117";
2061
2038
  }
2062
2039
  /**
2063
2040
  * Derives the next recommended action from a completed diagnostics snapshot.
@@ -2903,6 +2880,114 @@ async function renderAndMaybeWait(deps, prep, waitForAttach, callTimeoutMs, conn
2903
2880
  ...totpResult() ? { totp: totpResult() } : {}
2904
2881
  }, null, 2)}\n\n${qr}`);
2905
2882
  }
2883
+ /**
2884
+ * Builds a self-contained IIFE DOM expression that renders a dismissible
2885
+ * "Debugger Connected" badge on the bottom-left of the phone screen.
2886
+ *
2887
+ * **Pure function** — returns a JS expression string; does NOT inject it.
2888
+ * Injection is performed by {@link injectDebugIndicator} in `cell.ts`.
2889
+ *
2890
+ * The expression, when evaluated on the page, does the following:
2891
+ * 1. Early-returns if `#__ait_debug_indicator` already exists (idempotent —
2892
+ * prevents duplicate badges on re-injection after page reload).
2893
+ * 2. Appends a fixed-position `<div id="__ait_debug_indicator">` at the
2894
+ * bottom-left, accounting for safe-area insets.
2895
+ * 3. Attaches a `{ once: true }` `pointerdown` listener that removes the
2896
+ * badge on first touch — one-tap dismiss.
2897
+ *
2898
+ * The expression intentionally contains NO relay URLs, wss addresses, TOTP
2899
+ * codes, or any other secrets. It is pure DOM UI text only.
2900
+ *
2901
+ * SECRET-HANDLING: this expression contains no secrets, relay URLs, wss
2902
+ * addresses, or TOTP codes whatsoever — DOM label text only.
2903
+ *
2904
+ * @param opts.label - Badge text (default: `'Debugger Connected'`).
2905
+ * @returns A JS expression string suitable for `Runtime.evaluate`.
2906
+ */
2907
+ function buildIndicatorExpression(opts) {
2908
+ const label = opts?.label ?? "Debugger Connected";
2909
+ 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);})()`;
2910
+ }
2911
+ //#endregion
2912
+ //#region src/test-runner/cell.ts
2913
+ /**
2914
+ * Cell injection utility for the `devtools-test` CLI (issue #684 §4.1).
2915
+ *
2916
+ * Injects arbitrary globals into the page via `Runtime.evaluate` BEFORE the
2917
+ * first test bundle is injected. The injected values are session-global — one
2918
+ * call covers all files in the run.
2919
+ *
2920
+ * The primary use-case is injecting `__AIT_CELL__` (sdkLine/platform) so
2921
+ * sdk-example's `aitCapture.ts` picks up the correct test-axis values instead
2922
+ * of falling back to `'2.x'`/`'mock'`.
2923
+ *
2924
+ * devtools does NOT know the shape of `__AIT_CELL__` — it only provides the
2925
+ * general injection mechanism. The caller (CLI or MCP auto-attach path) is
2926
+ * responsible for constructing the cell object.
2927
+ *
2928
+ * SECRET-HANDLING: cell values (sdkLine/platform) are not secrets and may be
2929
+ * logged at the caller's discretion. This module does NOT log them itself.
2930
+ *
2931
+ * Node-only. react-free. CdpConnection only.
2932
+ */
2933
+ /**
2934
+ * Injects each key of `globals` into `globalThis` in the page via a single
2935
+ * `Runtime.evaluate` call. Must be called BEFORE the first `bundleTestFile`
2936
+ * inject — the cell is session-global and applies to all subsequent files.
2937
+ *
2938
+ * Throws if the CDP evaluate returns an exception.
2939
+ *
2940
+ * @param conn - The live CDP connection (relay-attached page).
2941
+ * @param globals - Plain-JSON-serialisable key→value map to assign onto `globalThis`.
2942
+ */
2943
+ async function injectGlobals(conn, globals) {
2944
+ const expr = `(() => { Object.assign(globalThis, ${JSON.stringify(globals)}); return true; })()`;
2945
+ const result = await conn.send("Runtime.evaluate", {
2946
+ expression: expr,
2947
+ returnByValue: true
2948
+ });
2949
+ if (result.exceptionDetails) {
2950
+ const msg = result.exceptionDetails.exception?.description ?? result.exceptionDetails.text ?? "unknown error";
2951
+ throw new Error(`injectGlobals: Runtime.evaluate threw: ${msg}`);
2952
+ }
2953
+ }
2954
+ /**
2955
+ * Injects the "Debugger Connected" on-phone indicator via `Runtime.evaluate`.
2956
+ *
2957
+ * Uses the same CDP mechanism as {@link injectGlobals} — a single
2958
+ * `Runtime.evaluate` round-trip with the expression built by
2959
+ * {@link buildIndicatorExpression}. The indicator is a dismissible red badge
2960
+ * rendered at the bottom-left of the page (position:fixed, safe-area-aware).
2961
+ *
2962
+ * **Isolation**: unlike {@link injectGlobals}, this function NEVER throws to
2963
+ * its caller. Injection failure (e.g. page detached during inject, CSS not
2964
+ * supported) is swallowed and logged as `console.debug` — the badge is
2965
+ * informational UI and must never block attach success or test execution.
2966
+ * This is the same fire-and-forget spirit as the eruda mount in
2967
+ * `src/in-app/attach.ts`.
2968
+ *
2969
+ * Call this ONLY on the manual debug paths (start_attach MCP, devtools-test
2970
+ * CLI). Do NOT call on the `run_tests` auto-attach path — the red badge
2971
+ * would contaminate screenshots, measure_safe_area probes, and DOM snapshots
2972
+ * taken during automated measurement runs.
2973
+ *
2974
+ * SECRET-HANDLING: the injected expression contains no secrets, relay URLs,
2975
+ * wss addresses, or TOTP codes — it is pure DOM UI text built by
2976
+ * {@link buildIndicatorExpression}.
2977
+ *
2978
+ * @param conn - The live CDP connection (relay-attached page).
2979
+ * @param opts - Optional overrides forwarded to {@link buildIndicatorExpression}.
2980
+ */
2981
+ async function injectDebugIndicator(conn, opts) {
2982
+ try {
2983
+ await conn.send("Runtime.evaluate", {
2984
+ expression: buildIndicatorExpression(opts),
2985
+ returnByValue: true
2986
+ });
2987
+ } catch (err) {
2988
+ console.debug("[@ait-co/devtools] debug indicator inject skipped:", err);
2989
+ }
2990
+ }
2906
2991
  //#endregion
2907
2992
  //#region src/test-runner/discover.ts
2908
2993
  /**
@@ -3597,6 +3682,7 @@ async function main(argv = process.argv.slice(2)) {
3597
3682
  return;
3598
3683
  }
3599
3684
  for (const chunk of waitResult.content) if (chunk.type === "text") process.stdout.write(`${chunk.text}\n`);
3685
+ await injectDebugIndicator(family.connection);
3600
3686
  if (hasCell) {
3601
3687
  const cell = {};
3602
3688
  if (cellSdkLine !== void 0) cell.sdkLine = cellSdkLine;
@@ -6688,7 +6774,7 @@ function createDebugServer(deps) {
6688
6774
  };
6689
6775
  const server = new Server({
6690
6776
  name: "ait-debug",
6691
- version: "0.1.116"
6777
+ version: "0.1.117"
6692
6778
  }, { capabilities: { tools: { listChanged: true } } });
6693
6779
  server.setRequestHandler(ListToolsRequestSchema, () => {
6694
6780
  const conn = router.active;
@@ -6750,7 +6836,9 @@ function createDebugServer(deps) {
6750
6836
  try {
6751
6837
  const prep = await prepareAttach(attachDeps, attachEnv, args, attachConn);
6752
6838
  if (!prep.ok) return prep.error;
6753
- return await renderAndMaybeWait(attachDeps, prep, waitForAttach, callTimeoutMs, attachConn);
6839
+ const attachResult = await renderAndMaybeWait(attachDeps, prep, waitForAttach, callTimeoutMs, attachConn);
6840
+ if (!attachResult.isError) await injectDebugIndicator(attachConn);
6841
+ return attachResult;
6754
6842
  } catch (err) {
6755
6843
  return errorResult(err, name);
6756
6844
  }
@@ -8168,4 +8256,4 @@ async function runMobileDebugServer(options = {}) {
8168
8256
  //#endregion
8169
8257
  export { wrapEnvelope as a, getSdkCallHistory as c, tierRejectionError as d, runMobileDebugServer as i, isAitToolName as l, runDebugServer as n, getMockState as o, runLocalDebugServer as r, getOperationalEnvironment as s, debug_server_exports as t, mcpError as u };
8170
8258
 
8171
- //# sourceMappingURL=debug-server-DlXJARIC.js.map
8259
+ //# sourceMappingURL=debug-server-jrI9U_f4.js.map