@ait-co/devtools 0.1.129 → 0.1.132
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/dist/{attach-orchestrator-DvrgUIx7.js → attach-orchestrator-BiaYiNOr.js} +31 -13
- package/dist/{attach-orchestrator-DvrgUIx7.js.map → attach-orchestrator-BiaYiNOr.js.map} +1 -1
- package/dist/{attach-orchestrator-RhOdO3DS.js → attach-orchestrator-Cjdhir2U.js} +31 -13
- package/dist/{attach-orchestrator-RhOdO3DS.js.map → attach-orchestrator-Cjdhir2U.js.map} +1 -1
- package/dist/{attach-orchestrator-Bdt5Zdo9.js → attach-orchestrator-ca34r46y.js} +31 -13
- package/dist/{attach-orchestrator-Bdt5Zdo9.js.map → attach-orchestrator-ca34r46y.js.map} +1 -1
- package/dist/{cell-Ba9lCI3B.js → cell-Bi8MAPA8.js} +11 -7
- package/dist/cell-Bi8MAPA8.js.map +1 -0
- package/dist/{cell-DA_lcpDI.js → cell-Cw4fVOl2.js} +11 -7
- package/dist/cell-Cw4fVOl2.js.map +1 -0
- package/dist/{cell-DLRv4iG6.js → cell-rr6gL9AT.js} +11 -7
- package/dist/cell-rr6gL9AT.js.map +1 -0
- package/dist/{debug-server-e1qPe0ZB.js → debug-server-BBUzxZSf.js} +4 -4
- package/dist/{debug-server-e1qPe0ZB.js.map → debug-server-BBUzxZSf.js.map} +1 -1
- package/dist/{debug-server--Y0QZVJS.js → debug-server-Ch5p0ryv.js} +33 -11
- package/dist/debug-server-Ch5p0ryv.js.map +1 -0
- package/dist/{debug-server-Bu3pCG9c.js → debug-server-DoWAtTNj.js} +27 -9
- package/dist/debug-server-DoWAtTNj.js.map +1 -0
- package/dist/in-app/auto.js +15 -0
- package/dist/in-app/auto.js.map +1 -1
- package/dist/in-app/index.d.ts +27 -0
- package/dist/in-app/index.d.ts.map +1 -1
- package/dist/in-app/index.js +15 -0
- package/dist/in-app/index.js.map +1 -1
- package/dist/mcp/cli.js +211 -38
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/panel/index.js +11 -1
- package/dist/panel/index.js.map +1 -1
- package/dist/{pool-C0pc7T2p.d.ts → pool-BtLh7U1y.d.ts} +24 -2
- package/dist/{pool-C0pc7T2p.d.ts.map → pool-BtLh7U1y.d.ts.map} +1 -1
- package/dist/{qr-http-server-DM2R25jP.cjs → qr-http-server-DX_9UA-p.cjs} +77 -6
- package/dist/qr-http-server-DX_9UA-p.cjs.map +1 -0
- package/dist/{qr-http-server-HANhOFwI.js → qr-http-server-DeRrKp_R.js} +77 -6
- package/dist/qr-http-server-DeRrKp_R.js.map +1 -0
- package/dist/{qr-http-server-CrGohOwC.js → qr-http-server-FVn61xAq.js} +77 -6
- package/dist/qr-http-server-FVn61xAq.js.map +1 -0
- package/dist/{qr-http-server-s1iW_5VQ.js → qr-http-server-KB147M-S.js} +77 -6
- package/dist/qr-http-server-KB147M-S.js.map +1 -0
- package/dist/{qr-http-server-BH0UFeUn.js → qr-http-server-V0xuU5TJ.js} +77 -6
- package/dist/qr-http-server-V0xuU5TJ.js.map +1 -0
- package/dist/{qr-http-server-Bt_RAxFn.cjs → qr-http-server-iH_Hh_si.cjs} +77 -6
- package/dist/qr-http-server-iH_Hh_si.cjs.map +1 -0
- package/dist/{relay-factory-Ck3vBonr.js → relay-factory-cNgPfrWg.js} +39 -13
- package/dist/relay-factory-cNgPfrWg.js.map +1 -0
- package/dist/{relay-worker-o0M2ndyJ.d.ts → relay-worker-BMSnlyls.d.ts} +39 -2
- package/dist/relay-worker-BMSnlyls.d.ts.map +1 -0
- package/dist/{relay-worker-Bt0QYKQH.js → relay-worker-l34xNuci.js} +28 -7
- package/dist/relay-worker-l34xNuci.js.map +1 -0
- package/dist/test-runner/bin.js +202 -36
- package/dist/test-runner/bin.js.map +1 -1
- package/dist/test-runner/config.d.ts +15 -9
- package/dist/test-runner/config.d.ts.map +1 -1
- package/dist/test-runner/config.js +1 -1
- package/dist/test-runner/pool.d.ts +1 -1
- package/dist/test-runner/pool.js +1 -1
- package/dist/test-runner/pool.js.map +1 -1
- package/dist/test-runner/relay-factory.d.ts +36 -8
- package/dist/test-runner/relay-factory.d.ts.map +1 -1
- package/dist/test-runner/relay-factory.js +38 -12
- package/dist/test-runner/relay-factory.js.map +1 -1
- package/dist/test-runner/relay-worker.d.ts +2 -2
- package/dist/test-runner/relay-worker.js +2 -2
- package/dist/test-runner/report.d.ts +26 -4
- package/dist/test-runner/report.d.ts.map +1 -1
- package/dist/test-runner/report.js +41 -7
- package/dist/test-runner/report.js.map +1 -1
- package/dist/{tunnel-DyEV6WwL.cjs → tunnel-DP453L4e.cjs} +4 -3
- package/dist/{tunnel-DyEV6WwL.cjs.map → tunnel-DP453L4e.cjs.map} +1 -1
- package/dist/{tunnel-BFwOSwT4.js → tunnel-Djf-zmjJ.js} +4 -3
- package/dist/{tunnel-BFwOSwT4.js.map → tunnel-Djf-zmjJ.js.map} +1 -1
- package/dist/unplugin/index.cjs +1 -1
- package/dist/unplugin/index.js +1 -1
- package/dist/unplugin/tunnel.cjs +3 -2
- package/dist/unplugin/tunnel.cjs.map +1 -1
- package/dist/unplugin/tunnel.d.cts.map +1 -1
- package/dist/unplugin/tunnel.d.ts.map +1 -1
- package/dist/unplugin/tunnel.js +3 -2
- package/dist/unplugin/tunnel.js.map +1 -1
- package/package.json +1 -1
- package/dist/cell-Ba9lCI3B.js.map +0 -1
- package/dist/cell-DA_lcpDI.js.map +0 -1
- package/dist/cell-DLRv4iG6.js.map +0 -1
- package/dist/debug-server--Y0QZVJS.js.map +0 -1
- package/dist/debug-server-Bu3pCG9c.js.map +0 -1
- package/dist/qr-http-server-BH0UFeUn.js.map +0 -1
- package/dist/qr-http-server-Bt_RAxFn.cjs.map +0 -1
- package/dist/qr-http-server-CrGohOwC.js.map +0 -1
- package/dist/qr-http-server-DM2R25jP.cjs.map +0 -1
- package/dist/qr-http-server-HANhOFwI.js.map +0 -1
- package/dist/qr-http-server-s1iW_5VQ.js.map +0 -1
- package/dist/relay-factory-Ck3vBonr.js.map +0 -1
- package/dist/relay-worker-Bt0QYKQH.js.map +0 -1
- package/dist/relay-worker-o0M2ndyJ.d.ts.map +0 -1
package/dist/mcp/cli.js
CHANGED
|
@@ -2024,7 +2024,7 @@ async function readMcpSdkVersion() {
|
|
|
2024
2024
|
* some test environments that skip the build step).
|
|
2025
2025
|
*/
|
|
2026
2026
|
function readDevtoolsVersion() {
|
|
2027
|
-
return "0.1.
|
|
2027
|
+
return "0.1.132";
|
|
2028
2028
|
}
|
|
2029
2029
|
/**
|
|
2030
2030
|
* Derives the next recommended action from a completed diagnostics snapshot.
|
|
@@ -2864,32 +2864,50 @@ async function renderAndMaybeWait(deps, prep, waitForAttach, callTimeoutMs, conn
|
|
|
2864
2864
|
}, null, 2)}\n\n${qr}`);
|
|
2865
2865
|
}
|
|
2866
2866
|
/**
|
|
2867
|
-
* Builds a self-contained IIFE DOM expression that renders a
|
|
2868
|
-
* "Debugger Connected" badge on the bottom-left of
|
|
2867
|
+
* Builds a self-contained IIFE DOM expression that renders a LIVE
|
|
2868
|
+
* "Debugger Connected" / "Debugger Disconnected" badge on the bottom-left of
|
|
2869
|
+
* the phone screen (#730).
|
|
2869
2870
|
*
|
|
2870
2871
|
* **Pure function** — returns a JS expression string; does NOT inject it.
|
|
2871
2872
|
* Injection is performed by {@link injectDebugIndicator} in `cell.ts`.
|
|
2872
2873
|
*
|
|
2873
2874
|
* The expression, when evaluated on the page, does the following:
|
|
2874
|
-
* 1.
|
|
2875
|
-
*
|
|
2876
|
-
*
|
|
2877
|
-
*
|
|
2878
|
-
*
|
|
2879
|
-
*
|
|
2875
|
+
* 1. Idempotent controller — a single `window.__ait_indicator` controller
|
|
2876
|
+
* object is created once (keyed on its presence, not on the DOM node).
|
|
2877
|
+
* Re-injection (e.g. explicit disconnect notice from `close()`) UPDATES
|
|
2878
|
+
* the existing badge's state/label in place — it never duplicates the
|
|
2879
|
+
* `<div>` or stacks a second observer.
|
|
2880
|
+
* 2. Renders a fixed-position `<div id="__ait_debug_indicator">` at the
|
|
2881
|
+
* bottom-left, accounting for safe-area insets. Background/text flip
|
|
2882
|
+
* between the attached (red) and disconnected (grey) visuals.
|
|
2883
|
+
* 3. A `pointerdown` listener dismisses (hides) the badge on tap — dismiss
|
|
2884
|
+
* is NON-terminal: a later state transition un-dismisses it, so a
|
|
2885
|
+
* genuine disconnect after a dismissed tap is still visible.
|
|
2886
|
+
* 4. Observes relay-socket lifecycle WITHOUT opening any new connection:
|
|
2887
|
+
* - Preferred path: if the in-app module (`src/in-app/attach.ts`) has
|
|
2888
|
+
* already installed its relay-WS observer (`window.__ait_relay_ws_observed`),
|
|
2889
|
+
* subscribe to the `ait:relay-ws-state` CustomEvent it broadcasts.
|
|
2890
|
+
* - Fallback path: wrap `window.WebSocket` in a `Proxy` and match dials
|
|
2891
|
+
* by PATHNAME SHAPE only (`/target/`) — never by host/wss value — so a
|
|
2892
|
+
* bare CDP-injected badge (no in-app bundle) still reacts to the
|
|
2893
|
+
* chii target socket's own open/close lifecycle.
|
|
2880
2894
|
*
|
|
2881
2895
|
* The expression intentionally contains NO relay URLs, wss addresses, TOTP
|
|
2882
|
-
* codes, or any other secrets. It is pure DOM UI text only.
|
|
2896
|
+
* codes, or any other secrets. It is pure DOM UI text + enum state only.
|
|
2883
2897
|
*
|
|
2884
2898
|
* SECRET-HANDLING: this expression contains no secrets, relay URLs, wss
|
|
2885
|
-
* addresses, or TOTP codes whatsoever — DOM label text
|
|
2899
|
+
* addresses, or TOTP codes whatsoever — DOM label text + a structural
|
|
2900
|
+
* pathname match (`/target/`) only.
|
|
2886
2901
|
*
|
|
2887
|
-
* @param opts.label -
|
|
2902
|
+
* @param opts.label - Attached-state badge text (default: `'Debugger Connected'`).
|
|
2903
|
+
* @param opts.disconnectedLabel - Disconnected-state badge text (default: `'Debugger Disconnected'`).
|
|
2904
|
+
* @param opts.state - Initial/forced state for THIS injection call (default: `'attached'`).
|
|
2888
2905
|
* @returns A JS expression string suitable for `Runtime.evaluate`.
|
|
2889
2906
|
*/
|
|
2890
2907
|
function buildIndicatorExpression(opts) {
|
|
2891
2908
|
const label = opts?.label ?? "Debugger Connected";
|
|
2892
|
-
|
|
2909
|
+
const disconnectedLabel = opts?.disconnectedLabel ?? "Debugger Disconnected";
|
|
2910
|
+
return `(() => {var W = window;function render(c) {if (c.dismissed) { c.el.style.display = 'none'; return; }c.el.style.display = 'block';var up = c.state !== 'disconnected';c.el.style.background = up ? '#e5484d' : '#8a8f98';c.el.textContent = up ? ${JSON.stringify(label)} : ${JSON.stringify(disconnectedLabel)};}function setState(c, next) { c.state = next; c.dismissed = false; render(c); }var c = W.__ait_indicator;if (!c) {var 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','color:#fff','font:bold 11px/1 system-ui,sans-serif','padding:5px 9px','border-radius:6px','pointer-events:auto','user-select:none',].join(';');document.body.appendChild(el);c = { el: el, state: 'attached', dismissed: false };el.addEventListener('pointerdown', function () { c.dismissed = true; render(c); }, { passive: true });W.__ait_indicator = c;if (W.__ait_relay_ws_observed) {W.addEventListener('ait:relay-ws-state', function (e) {setState(c, e.detail && e.detail.state === 'open' ? 'attached' : 'disconnected');});} else {try {var Native = W.WebSocket;W.WebSocket = new Proxy(Native, {construct: function (t, a) {var ws = Reflect.construct(t, a);try {var u = new URL(String(a[0]), location.href);if (/\\/target\\//.test(u.pathname)) {ws.addEventListener('open', function () { setState(c, 'attached'); });ws.addEventListener('close', function () { setState(c, 'disconnected'); });ws.addEventListener('error', function () { setState(c, 'disconnected'); });}} catch (_) {}return ws;},});} catch (_) {}}}setState(c, ${JSON.stringify(opts?.state ?? "attached")});})()`;
|
|
2893
2911
|
}
|
|
2894
2912
|
//#endregion
|
|
2895
2913
|
//#region src/test-runner/cell.ts
|
|
@@ -2935,12 +2953,16 @@ async function injectGlobals(conn, globals) {
|
|
|
2935
2953
|
}
|
|
2936
2954
|
}
|
|
2937
2955
|
/**
|
|
2938
|
-
* Injects the "Debugger Connected"
|
|
2956
|
+
* Injects (or updates) the "Debugger Connected"/"Debugger Disconnected"
|
|
2957
|
+
* on-phone indicator via `Runtime.evaluate` (#730).
|
|
2939
2958
|
*
|
|
2940
2959
|
* Uses the same CDP mechanism as {@link injectGlobals} — a single
|
|
2941
2960
|
* `Runtime.evaluate` round-trip with the expression built by
|
|
2942
|
-
* {@link buildIndicatorExpression}. The indicator is a
|
|
2943
|
-
*
|
|
2961
|
+
* {@link buildIndicatorExpression}. The indicator is a LIVE badge rendered at
|
|
2962
|
+
* the bottom-left of the page (position:fixed, safe-area-aware): the badge's
|
|
2963
|
+
* controller is idempotent, so calling this again (e.g. right before
|
|
2964
|
+
* `close()` with `{ state: 'disconnected' }`) UPDATES the existing badge in
|
|
2965
|
+
* place instead of injecting a duplicate.
|
|
2944
2966
|
*
|
|
2945
2967
|
* **Isolation**: unlike {@link injectGlobals}, this function NEVER throws to
|
|
2946
2968
|
* its caller. Injection failure (e.g. page detached during inject, CSS not
|
|
@@ -2950,12 +2972,12 @@ async function injectGlobals(conn, globals) {
|
|
|
2950
2972
|
* `src/in-app/attach.ts`.
|
|
2951
2973
|
*
|
|
2952
2974
|
* Call this ONLY on the manual debug paths (start_attach MCP, devtools-test
|
|
2953
|
-
* CLI). Do NOT call on the `run_tests` auto-attach path — the
|
|
2975
|
+
* CLI). Do NOT call on the `run_tests` auto-attach path — the badge
|
|
2954
2976
|
* would contaminate screenshots, measure_safe_area probes, and DOM snapshots
|
|
2955
2977
|
* taken during automated measurement runs.
|
|
2956
2978
|
*
|
|
2957
2979
|
* SECRET-HANDLING: the injected expression contains no secrets, relay URLs,
|
|
2958
|
-
* wss addresses, or TOTP codes — it is pure DOM UI text built by
|
|
2980
|
+
* wss addresses, or TOTP codes — it is pure DOM UI text + enum state built by
|
|
2959
2981
|
* {@link buildIndicatorExpression}.
|
|
2960
2982
|
*
|
|
2961
2983
|
* @param conn - The live CDP connection (relay-attached page).
|
|
@@ -2985,6 +3007,23 @@ async function injectDebugIndicator(conn, opts) {
|
|
|
2985
3007
|
* safe to import from the MCP daemon graph.
|
|
2986
3008
|
*/
|
|
2987
3009
|
/**
|
|
3010
|
+
* Filename suffix that opts a test file into manual-variant scheduling
|
|
3011
|
+
* (devtools#741). A file named `<name>.manual.ait.test.ts` is EXCLUDED from
|
|
3012
|
+
* `discoverTestFiles`'s default output (so existing unattended runs are
|
|
3013
|
+
* unaffected — the zero-diff-when-off constraint) and is only surfaced when
|
|
3014
|
+
* the caller explicitly asks for manual files via {@link partitionManualTests}
|
|
3015
|
+
* (wired from the CLI's `--manual-blocking` flag).
|
|
3016
|
+
*
|
|
3017
|
+
* This is the entire tagging contract for v1 — no separate manifest/config,
|
|
3018
|
+
* just a filename convention. Documented here + in the CLI `--help` text
|
|
3019
|
+
* (cli.ts USAGE) and the test-runner README.
|
|
3020
|
+
*/
|
|
3021
|
+
const MANUAL_TEST_SUFFIX = ".manual.ait.test.ts";
|
|
3022
|
+
/** True when `file`'s basename ends with {@link MANUAL_TEST_SUFFIX}. */
|
|
3023
|
+
function isManualTestFile(file) {
|
|
3024
|
+
return basename(file).endsWith(MANUAL_TEST_SUFFIX);
|
|
3025
|
+
}
|
|
3026
|
+
/**
|
|
2988
3027
|
* Expands `patterns` (globs or plain paths) into a sorted, de-duplicated list of
|
|
2989
3028
|
* ABSOLUTE test file paths, resolved relative to `cwd`.
|
|
2990
3029
|
*
|
|
@@ -2993,14 +3032,26 @@ async function injectDebugIndicator(conn, opts) {
|
|
|
2993
3032
|
* resolved against `cwd`. `bundleTestFile` requires an absolute path, so the
|
|
2994
3033
|
* absolute output feeds it directly.
|
|
2995
3034
|
*
|
|
3035
|
+
* By default, files matching {@link MANUAL_TEST_SUFFIX} are EXCLUDED from the
|
|
3036
|
+
* result (devtools#741) — blocking-UI tests opt in via that filename
|
|
3037
|
+
* convention and must never appear in an unattended run unless the caller
|
|
3038
|
+
* explicitly asks for them via `includeManual: true`. This keeps the
|
|
3039
|
+
* default (flag-off) discovery path byte-for-byte identical to before this
|
|
3040
|
+
* option existed.
|
|
3041
|
+
*
|
|
2996
3042
|
* @param patterns Glob patterns or file paths (e.g. `['src/**\/*.ait.test.ts']`).
|
|
2997
3043
|
* @param cwd Base directory for relative patterns/results.
|
|
3044
|
+
* @param opts `{ includeManual }` — when true, manual-tagged files are kept
|
|
3045
|
+
* in the (still-sorted) output instead of being filtered out.
|
|
3046
|
+
* Use {@link partitionManualTests} to separate + reorder them.
|
|
2998
3047
|
* @returns Sorted, de-duplicated absolute file paths. Empty when nothing matches.
|
|
2999
3048
|
*/
|
|
3000
|
-
async function discoverTestFiles(patterns, cwd) {
|
|
3049
|
+
async function discoverTestFiles(patterns, cwd, opts) {
|
|
3001
3050
|
const out = /* @__PURE__ */ new Set();
|
|
3002
3051
|
for await (const match of glob(patterns, { cwd })) out.add(isAbsolute(match) ? match : resolve(cwd, match));
|
|
3003
|
-
|
|
3052
|
+
const sorted = [...out].sort();
|
|
3053
|
+
if (opts?.includeManual) return sorted;
|
|
3054
|
+
return sorted.filter((f) => !isManualTestFile(f));
|
|
3004
3055
|
}
|
|
3005
3056
|
//#endregion
|
|
3006
3057
|
//#region src/shared/relay-auth-close.ts
|
|
@@ -3235,7 +3286,11 @@ var ChiiCdpConnection = class {
|
|
|
3235
3286
|
* EventEmitter is missed (defensive belt-and-suspenders).
|
|
3236
3287
|
*
|
|
3237
3288
|
* @param filterFn - Predicate that the returned targets must satisfy.
|
|
3238
|
-
* @param timeoutMs - Reject after this many ms (default 90 000).
|
|
3289
|
+
* @param timeoutMs - Reject after this many ms (default 90 000). Pass a
|
|
3290
|
+
* non-finite value (`Infinity`) to disable the rejection timer entirely —
|
|
3291
|
+
* used by the test-runner's unbounded QR-attach wait (devtools#735). Node
|
|
3292
|
+
* clamps `setTimeout(fn, Infinity)` to ~1ms, so a non-finite value MUST
|
|
3293
|
+
* skip arming the timer rather than pass it through.
|
|
3239
3294
|
* @param pollIntervalMs - Fallback poll interval (default 500ms).
|
|
3240
3295
|
*/
|
|
3241
3296
|
waitForFirstTarget(filterFn, timeoutMs = 9e4, pollIntervalMs = 500) {
|
|
@@ -3247,7 +3302,7 @@ var ChiiCdpConnection = class {
|
|
|
3247
3302
|
const settle = (targets) => {
|
|
3248
3303
|
if (settled) return;
|
|
3249
3304
|
settled = true;
|
|
3250
|
-
clearTimeout(timeoutHandle);
|
|
3305
|
+
if (timeoutHandle !== null) clearTimeout(timeoutHandle);
|
|
3251
3306
|
if (pollHandle !== null) {
|
|
3252
3307
|
clearInterval(pollHandle);
|
|
3253
3308
|
pollHandle = null;
|
|
@@ -3258,7 +3313,7 @@ var ChiiCdpConnection = class {
|
|
|
3258
3313
|
const onAttach = (targets) => {
|
|
3259
3314
|
if (filterFn(targets)) settle(targets);
|
|
3260
3315
|
};
|
|
3261
|
-
const timeoutHandle = setTimeout(() => {
|
|
3316
|
+
const timeoutHandle = Number.isFinite(timeoutMs) ? setTimeout(() => {
|
|
3262
3317
|
if (settled) return;
|
|
3263
3318
|
settled = true;
|
|
3264
3319
|
if (pollHandle !== null) {
|
|
@@ -3267,7 +3322,7 @@ var ChiiCdpConnection = class {
|
|
|
3267
3322
|
}
|
|
3268
3323
|
this.emitter.off("target:attached", onAttach);
|
|
3269
3324
|
reject(/* @__PURE__ */ new Error(`waitForFirstTarget: 타임아웃 (${timeoutMs}ms) — 폰이 relay에 attach되지 않았습니다.`));
|
|
3270
|
-
}, timeoutMs);
|
|
3325
|
+
}, timeoutMs) : null;
|
|
3271
3326
|
this.emitter.on("target:attached", onAttach);
|
|
3272
3327
|
pollHandle = setInterval(() => {
|
|
3273
3328
|
this.refreshTargets().then((targets) => {
|
|
@@ -4043,6 +4098,13 @@ async function injectAndRunBundle(connection, bundleCode, timeoutMs = DEFAULT_TI
|
|
|
4043
4098
|
//#endregion
|
|
4044
4099
|
//#region src/test-runner/relay-worker.ts
|
|
4045
4100
|
/**
|
|
4101
|
+
* Per-file evaluate timeout (ms) for manual-variant files (devtools#741) — a
|
|
4102
|
+
* human is expected to be tapping through a native sheet, so the timeout must
|
|
4103
|
+
* be far longer than the unattended default (60s, rpc.ts DEFAULT_TIMEOUT_MS).
|
|
4104
|
+
* Fixed constant (not configurable in v1) — documented here + CLI `--help`.
|
|
4105
|
+
*/
|
|
4106
|
+
const MANUAL_FILE_TIMEOUT_MS = 5 * 6e4;
|
|
4107
|
+
/**
|
|
4046
4108
|
* Sentinel string embedded in the error message by `injectAndRunBundle` when
|
|
4047
4109
|
* the per-file evaluate race hits the timeout. Used by the retry guard so only
|
|
4048
4110
|
* genuine timeouts get a second attempt — not bundle errors or parse failures.
|
|
@@ -4113,12 +4175,21 @@ async function runTestFilesOverRelay(connection, files, opts) {
|
|
|
4113
4175
|
process.stderr.write(`relay-worker: reconnect failed (${e instanceof Error ? e.message : String(e)}) — continuing, remaining files may fail\n`);
|
|
4114
4176
|
}
|
|
4115
4177
|
};
|
|
4178
|
+
const manualFiles = opts?.manualFiles;
|
|
4179
|
+
const manualTotal = manualFiles?.size ?? 0;
|
|
4180
|
+
let manualIndex = 0;
|
|
4116
4181
|
try {
|
|
4117
4182
|
for (const file of files) {
|
|
4118
4183
|
if (pendingReconnectCheck) {
|
|
4119
4184
|
await attemptReconnect("next-file");
|
|
4120
4185
|
pendingReconnectCheck = false;
|
|
4121
4186
|
}
|
|
4187
|
+
const isManual = manualFiles?.has(file) === true;
|
|
4188
|
+
if (isManual) {
|
|
4189
|
+
manualIndex += 1;
|
|
4190
|
+
opts?.onManualFile?.(file, manualIndex, manualTotal);
|
|
4191
|
+
}
|
|
4192
|
+
const fileTimeoutMs = isManual ? MANUAL_FILE_TIMEOUT_MS : opts?.timeoutMs;
|
|
4122
4193
|
let fileEntry;
|
|
4123
4194
|
try {
|
|
4124
4195
|
const { code } = await bundleTestFile(file, opts?.bundleOptions);
|
|
@@ -4144,7 +4215,7 @@ async function runTestFilesOverRelay(connection, files, opts) {
|
|
|
4144
4215
|
const attempt = async () => {
|
|
4145
4216
|
let rpcResult;
|
|
4146
4217
|
try {
|
|
4147
|
-
rpcResult = await injectAndRunBundle(connection, code,
|
|
4218
|
+
rpcResult = await injectAndRunBundle(connection, code, fileTimeoutMs);
|
|
4148
4219
|
} catch (e) {
|
|
4149
4220
|
return {
|
|
4150
4221
|
file,
|
|
@@ -4180,6 +4251,7 @@ async function runTestFilesOverRelay(connection, files, opts) {
|
|
|
4180
4251
|
};
|
|
4181
4252
|
}
|
|
4182
4253
|
if ("error" in fileEntry.result && isRelayDisconnectMessage(fileEntry.result.error)) pendingReconnectCheck = true;
|
|
4254
|
+
if (isManual) fileEntry.mode = "manual";
|
|
4183
4255
|
fileResults.push(fileEntry);
|
|
4184
4256
|
}
|
|
4185
4257
|
} finally {
|
|
@@ -4252,9 +4324,9 @@ OPTIONS
|
|
|
4252
4324
|
the CLI waits for a human to scan the QR code — use
|
|
4253
4325
|
--attach-timeout for that.
|
|
4254
4326
|
--attach-timeout <ms> How long to wait for a human to scan the QR code with
|
|
4255
|
-
their phone (default
|
|
4256
|
-
|
|
4257
|
-
|
|
4327
|
+
their phone. Omit (default) to wait indefinitely — the
|
|
4328
|
+
runner stays up until you stop it (Ctrl-C/SIGTERM).
|
|
4329
|
+
Pass a value to bound the wait for CI/headless runs.
|
|
4258
4330
|
--cell-sdk-line <line> SDK line to inject as __AIT_CELL__.sdkLine (2.x|3.x)
|
|
4259
4331
|
--cell-platform <plat> Platform to inject as __AIT_CELL__.platform
|
|
4260
4332
|
(mock|ios|android, default: AIT_CELL_PLATFORM env)
|
|
@@ -4267,6 +4339,24 @@ OPTIONS
|
|
|
4267
4339
|
--headless Disable browser auto-open (text QR only)
|
|
4268
4340
|
--project-root <dir> Project root for .ait_relay secret lookup
|
|
4269
4341
|
(default: current working directory)
|
|
4342
|
+
--manual-blocking Run manual-tagged test files (*.manual.ait.test.ts)
|
|
4343
|
+
LAST, after all regular files, with a human present.
|
|
4344
|
+
Before each manual file, the QR dashboard is pushed
|
|
4345
|
+
a step-by-step Korean prompt naming the file + its
|
|
4346
|
+
progress (k/n), and the same line is printed to
|
|
4347
|
+
stdout. Manual files get a 5-minute per-file evaluate
|
|
4348
|
+
timeout (vs. --timeout for everything else) since a
|
|
4349
|
+
human is expected to tap through a native sheet
|
|
4350
|
+
(photo picker, permission dialog, fullscreen ad).
|
|
4351
|
+
Without this flag (default off), *.manual.ait.test.ts
|
|
4352
|
+
files are EXCLUDED from the glob expansion entirely —
|
|
4353
|
+
existing unattended runs are byte-for-byte unaffected.
|
|
4354
|
+
With --report-dir, a run that included manual files
|
|
4355
|
+
ALSO writes <sdkLine>.<platform>.manual.json
|
|
4356
|
+
alongside (never replacing) the standard report, and
|
|
4357
|
+
each manual file's report entry is stamped
|
|
4358
|
+
mode: 'manual' — never diff a manual run against an
|
|
4359
|
+
unattended baseline as if they were equivalent.
|
|
4270
4360
|
--help, -h Show this help message
|
|
4271
4361
|
|
|
4272
4362
|
DESCRIPTION
|
|
@@ -5397,6 +5487,11 @@ const en = {
|
|
|
5397
5487
|
"dashboard.watchdog.title": "Server has shut down",
|
|
5398
5488
|
"dashboard.watchdog.body": "The MCP server has stopped. This session is no longer active. You may close this tab.",
|
|
5399
5489
|
"dashboard.watchdog.close": "Close tab",
|
|
5490
|
+
"dashboard.conn.lost": "Connection lost — reconnecting…",
|
|
5491
|
+
"dashboard.session.completeTitle": "Test run complete",
|
|
5492
|
+
"dashboard.session.completeBody": "The runner exited cleanly. See your terminal for results.",
|
|
5493
|
+
"dashboard.session.shutdownTitle": "Debug server stopped",
|
|
5494
|
+
"dashboard.session.shutdownBody": "The MCP server has shut down; this session is no longer live. You can close this tab.",
|
|
5400
5495
|
"attach.title": "AIT Debug Session — QR Scan",
|
|
5401
5496
|
"attach.deployment": "deployment: {label}",
|
|
5402
5497
|
"attach.steps.section": "How to scan",
|
|
@@ -5635,6 +5730,11 @@ const tables = {
|
|
|
5635
5730
|
"dashboard.watchdog.title": "서버가 종료되었습니다",
|
|
5636
5731
|
"dashboard.watchdog.body": "MCP server가 종료되어 이 세션이 더 이상 유효하지 않습니다. 이 탭을 닫아도 됩니다.",
|
|
5637
5732
|
"dashboard.watchdog.close": "탭 닫기",
|
|
5733
|
+
"dashboard.conn.lost": "연결 끊김 — 재연결 시도 중…",
|
|
5734
|
+
"dashboard.session.completeTitle": "테스트 실행 완료",
|
|
5735
|
+
"dashboard.session.completeBody": "러너가 정상 종료되었습니다. 결과는 터미널에서 확인하세요.",
|
|
5736
|
+
"dashboard.session.shutdownTitle": "디버그 서버가 종료되었습니다",
|
|
5737
|
+
"dashboard.session.shutdownBody": "MCP server가 종료되어 이 세션이 더 이상 유효하지 않습니다. 이 탭을 닫아도 됩니다.",
|
|
5638
5738
|
"attach.title": "AIT 디버그 세션 — QR 스캔",
|
|
5639
5739
|
"attach.deployment": "deployment: {label}",
|
|
5640
5740
|
"attach.steps.section": "스캔 절차",
|
|
@@ -6216,7 +6316,12 @@ function buildDashboardHtml(state, qrDataUrl, locale, path = "/", params = new U
|
|
|
6216
6316
|
watchdogTimeoutMs,
|
|
6217
6317
|
watchdogTitle: JSON.stringify(s("dashboard.watchdog.title")),
|
|
6218
6318
|
watchdogBody: JSON.stringify(s("dashboard.watchdog.body")),
|
|
6219
|
-
watchdogCloseLabel: JSON.stringify(s("dashboard.watchdog.close"))
|
|
6319
|
+
watchdogCloseLabel: JSON.stringify(s("dashboard.watchdog.close")),
|
|
6320
|
+
connectionLost: JSON.stringify(s("dashboard.conn.lost")),
|
|
6321
|
+
completeTitle: JSON.stringify(s("dashboard.session.completeTitle")),
|
|
6322
|
+
completeBody: JSON.stringify(s("dashboard.session.completeBody")),
|
|
6323
|
+
shutdownTitle: JSON.stringify(s("dashboard.session.shutdownTitle")),
|
|
6324
|
+
shutdownBody: JSON.stringify(s("dashboard.session.shutdownBody"))
|
|
6220
6325
|
};
|
|
6221
6326
|
const langSwitcher = buildLangSwitcher(path, params, locale, s);
|
|
6222
6327
|
const filled = dashboardChromeByLocale[locale].replaceAll("__LANG_SWITCHER__", langSwitcher).replaceAll("__NOW__", escapeHtml(now)).replaceAll("__TUNNEL_CLASS__", tunnelClass).replaceAll("__TUNNEL_STATUS__", escapeHtml(tunnelStatus)).replaceAll("__ATTACH_SECTION__", attachSection).replaceAll("__INSPECTOR_SECTION__", inspectorSection).replaceAll("__PAGES_SECTION__", pagesSection);
|
|
@@ -6273,6 +6378,14 @@ function buildSseScript(strings) {
|
|
|
6273
6378
|
var WATCHDOG_BODY = ${strings.watchdogBody};
|
|
6274
6379
|
var WATCHDOG_CLOSE_LABEL = ${strings.watchdogCloseLabel};
|
|
6275
6380
|
|
|
6381
|
+
// ── 실시간 상태 표면 상수 (#730) ───────────────────────────────────────
|
|
6382
|
+
var CONN_LOST = ${strings.connectionLost};
|
|
6383
|
+
var COMPLETE_TITLE = ${strings.completeTitle};
|
|
6384
|
+
var COMPLETE_BODY = ${strings.completeBody};
|
|
6385
|
+
var SHUTDOWN_TITLE = ${strings.shutdownTitle};
|
|
6386
|
+
var SHUTDOWN_BODY = ${strings.shutdownBody};
|
|
6387
|
+
var disconnectedShown = false;
|
|
6388
|
+
|
|
6276
6389
|
// ── 클립보드 복사 헬퍼 ────────────────────────────────────────────────
|
|
6277
6390
|
function copyText(text) {
|
|
6278
6391
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
@@ -6350,6 +6463,36 @@ function buildSseScript(strings) {
|
|
|
6350
6463
|
}
|
|
6351
6464
|
}
|
|
6352
6465
|
|
|
6466
|
+
// ── Terminal 상태 배너 (#730) ─────────────────────────────────────────
|
|
6467
|
+
// "완료"/"종료"는 watchdog(최대 210s 지연)을 기다리지 않고 close() 직전에
|
|
6468
|
+
// 서버가 직접 push하는 마지막 SSE 프레임으로 즉시 렌더한다. watchdogFired를
|
|
6469
|
+
// 함께 세워 뒤이은 onerror의 showConnLost가 이 배너를 덮어쓰지 않게 한다.
|
|
6470
|
+
function showTerminalBanner(title, body) {
|
|
6471
|
+
if (watchdogTimer) { clearInterval(watchdogTimer); watchdogTimer = null; }
|
|
6472
|
+
watchdogFired = true; // 이후 watchdog/onerror 발화를 억제
|
|
6473
|
+
if (document.body) {
|
|
6474
|
+
document.body.innerHTML =
|
|
6475
|
+
'<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;' +
|
|
6476
|
+
'height:100vh;font-family:sans-serif;text-align:center;padding:2rem;box-sizing:border-box;">' +
|
|
6477
|
+
'<p style="font-size:1.4rem;font-weight:bold;margin-bottom:1rem;">' + title + '</p>' +
|
|
6478
|
+
'<p style="color:#555;">' + body + '</p></div>';
|
|
6479
|
+
}
|
|
6480
|
+
}
|
|
6481
|
+
|
|
6482
|
+
// ── SSE onerror 즉시 신호 (#730) ──────────────────────────────────────
|
|
6483
|
+
// EventSource는 "재시도 중"과 "서버 종료"를 구분하지 못하므로, onerror에서
|
|
6484
|
+
// 즉시 구분되는 '연결 끊김' 상태를 tunnel-status 배지에 표시한다. 이미
|
|
6485
|
+
// terminal 배너가 뜬 뒤(watchdogFired)라면 덮어쓰지 않는다.
|
|
6486
|
+
function showConnLost() {
|
|
6487
|
+
if (disconnectedShown || watchdogFired) return;
|
|
6488
|
+
disconnectedShown = true;
|
|
6489
|
+
var el = document.getElementById('tunnel-status');
|
|
6490
|
+
if (el) { el.textContent = CONN_LOST; el.className = 'status status-down'; }
|
|
6491
|
+
}
|
|
6492
|
+
function clearConnLost() {
|
|
6493
|
+
disconnectedShown = false;
|
|
6494
|
+
}
|
|
6495
|
+
|
|
6353
6496
|
function fireWatchdog() {
|
|
6354
6497
|
if (watchdogFired) return;
|
|
6355
6498
|
watchdogFired = true;
|
|
@@ -6380,7 +6523,7 @@ function buildSseScript(strings) {
|
|
|
6380
6523
|
src.onopen = function () {
|
|
6381
6524
|
// 연결 복구 시 lastSeen 갱신 — 일시적 끊김이 watchdog을 발화시키지 않게.
|
|
6382
6525
|
// watchdog이 이미 발화했으면 갱신하지 않는다(폴백 UI를 그대로 유지).
|
|
6383
|
-
if (!watchdogFired) { lastSeen = Date.now(); }
|
|
6526
|
+
if (!watchdogFired) { lastSeen = Date.now(); clearConnLost(); }
|
|
6384
6527
|
};
|
|
6385
6528
|
src.onmessage = function (e) {
|
|
6386
6529
|
// SSE 메시지 수신 — lastSeen 갱신으로 watchdog 리셋.
|
|
@@ -6388,6 +6531,13 @@ function buildSseScript(strings) {
|
|
|
6388
6531
|
if (!watchdogFired) { lastSeen = Date.now(); }
|
|
6389
6532
|
try {
|
|
6390
6533
|
var s = JSON.parse(e.data);
|
|
6534
|
+
// 어떤 프레임이든 성공적으로 수신됐다는 건 서버가 살아있다는 뜻 —
|
|
6535
|
+
// onerror가 세운 '연결 끊김' 표시를 해제한다 (#730).
|
|
6536
|
+
clearConnLost();
|
|
6537
|
+
// phase gate (#730) — 'complete'/'shutdown'은 terminal 상태이므로
|
|
6538
|
+
// 나머지 필드 렌더보다 먼저 처리하고 즉시 반환한다.
|
|
6539
|
+
if (s.phase === 'complete') { showTerminalBanner(COMPLETE_TITLE, COMPLETE_BODY); return; }
|
|
6540
|
+
if (s.phase === 'shutdown') { showTerminalBanner(SHUTDOWN_TITLE, SHUTDOWN_BODY); return; }
|
|
6391
6541
|
// 터널 상태 갱신
|
|
6392
6542
|
var el = document.getElementById('tunnel-status');
|
|
6393
6543
|
if (el) {
|
|
@@ -6466,7 +6616,11 @@ function buildSseScript(strings) {
|
|
|
6466
6616
|
} catch (_) { /* 파싱 오류 무시 */ }
|
|
6467
6617
|
};
|
|
6468
6618
|
src.onerror = function () {
|
|
6469
|
-
//
|
|
6619
|
+
// EventSource는 "재시도 중"과 "서버 종료"를 구분하지 못하므로 즉시
|
|
6620
|
+
// 구분되는 "연결 끊김"을 표시한다(#730). 네이티브 auto-reconnect는 그대로
|
|
6621
|
+
// 진행되며 onopen/onmessage가 성공 즉시 이 상태를 해제한다. watchdog은
|
|
6622
|
+
// 여전히 2차 fallback으로 남는다(최종 폴백 UI 전환).
|
|
6623
|
+
showConnLost();
|
|
6470
6624
|
};
|
|
6471
6625
|
})();
|
|
6472
6626
|
<\/script>`;
|
|
@@ -6515,7 +6669,12 @@ function buildAttachHtml(qrDataUrl, safeLabel, safeAttachUrl, locale, path = "/a
|
|
|
6515
6669
|
watchdogTimeoutMs,
|
|
6516
6670
|
watchdogTitle: JSON.stringify(s("dashboard.watchdog.title")),
|
|
6517
6671
|
watchdogBody: JSON.stringify(s("dashboard.watchdog.body")),
|
|
6518
|
-
watchdogCloseLabel: JSON.stringify(s("dashboard.watchdog.close"))
|
|
6672
|
+
watchdogCloseLabel: JSON.stringify(s("dashboard.watchdog.close")),
|
|
6673
|
+
connectionLost: JSON.stringify(s("dashboard.conn.lost")),
|
|
6674
|
+
completeTitle: JSON.stringify(s("dashboard.session.completeTitle")),
|
|
6675
|
+
completeBody: JSON.stringify(s("dashboard.session.completeBody")),
|
|
6676
|
+
shutdownTitle: JSON.stringify(s("dashboard.session.shutdownTitle")),
|
|
6677
|
+
shutdownBody: JSON.stringify(s("dashboard.session.shutdownBody"))
|
|
6519
6678
|
});
|
|
6520
6679
|
return filled.replace("</body>", `${sseScript}\n</body>`);
|
|
6521
6680
|
}
|
|
@@ -6542,7 +6701,9 @@ async function startQrHttpServer(getDashboardState, options) {
|
|
|
6542
6701
|
},
|
|
6543
6702
|
pages: state.pages,
|
|
6544
6703
|
attachUrl: state.attachUrl,
|
|
6545
|
-
inspectorUrl: state.inspectorUrl ?? null
|
|
6704
|
+
inspectorUrl: state.inspectorUrl ?? null,
|
|
6705
|
+
phase: state.phase ?? "active",
|
|
6706
|
+
manualPrompt: state.manualPrompt ?? null
|
|
6546
6707
|
});
|
|
6547
6708
|
res.write(`data: ${payload}\n\n`);
|
|
6548
6709
|
}
|
|
@@ -6851,7 +7012,7 @@ function createDebugServer(deps) {
|
|
|
6851
7012
|
};
|
|
6852
7013
|
const server = new Server({
|
|
6853
7014
|
name: "ait-debug",
|
|
6854
|
-
version: "0.1.
|
|
7015
|
+
version: "0.1.132"
|
|
6855
7016
|
}, { capabilities: { tools: { listChanged: true } } });
|
|
6856
7017
|
server.setRequestHandler(ListToolsRequestSchema, () => {
|
|
6857
7018
|
const conn = router.active;
|
|
@@ -7813,6 +7974,7 @@ async function runDebugServer(options = {}) {
|
|
|
7813
7974
|
return router.active;
|
|
7814
7975
|
});
|
|
7815
7976
|
let lastAttachParts = null;
|
|
7977
|
+
let currentPhase = "active";
|
|
7816
7978
|
const getDashboardState = () => {
|
|
7817
7979
|
const targets = router.active.listTargets();
|
|
7818
7980
|
const inspectorUrl = qrServer?.inspectorStableUrl ?? null;
|
|
@@ -7827,7 +7989,8 @@ async function runDebugServer(options = {}) {
|
|
|
7827
7989
|
})),
|
|
7828
7990
|
attachUrl: lastAttachParts ? rebuildAttachUrl(lastAttachParts) : null,
|
|
7829
7991
|
inspectorUrl,
|
|
7830
|
-
mode: deriveEnvironment(router.active.kind, router.activeRelayOrigin)
|
|
7992
|
+
mode: deriveEnvironment(router.active.kind, router.activeRelayOrigin),
|
|
7993
|
+
phase: currentPhase
|
|
7831
7994
|
};
|
|
7832
7995
|
};
|
|
7833
7996
|
const getDirectInspectorUrl = () => {
|
|
@@ -7891,6 +8054,8 @@ async function runDebugServer(options = {}) {
|
|
|
7891
8054
|
const shutdown = () => {
|
|
7892
8055
|
if (closed) return;
|
|
7893
8056
|
closed = true;
|
|
8057
|
+
currentPhase = "shutdown";
|
|
8058
|
+
qrServer?.notifyStateChange();
|
|
7894
8059
|
parentWatcher?.stop();
|
|
7895
8060
|
maxAgeWatchdog?.stop();
|
|
7896
8061
|
if (totpRefreshHandle) clearInterval(totpRefreshHandle);
|
|
@@ -8028,6 +8193,7 @@ async function runLocalDebugServer(options = {}) {
|
|
|
8028
8193
|
return router.active;
|
|
8029
8194
|
});
|
|
8030
8195
|
let lastAttachParts = null;
|
|
8196
|
+
let currentPhase = "active";
|
|
8031
8197
|
const getDashboardState = () => {
|
|
8032
8198
|
const targets = router.active.listTargets();
|
|
8033
8199
|
const inspectorUrl = qrServer?.inspectorStableUrl ?? null;
|
|
@@ -8041,7 +8207,8 @@ async function runLocalDebugServer(options = {}) {
|
|
|
8041
8207
|
url: t.url
|
|
8042
8208
|
})),
|
|
8043
8209
|
attachUrl: lastAttachParts ? rebuildAttachUrl(lastAttachParts) : null,
|
|
8044
|
-
inspectorUrl
|
|
8210
|
+
inspectorUrl,
|
|
8211
|
+
phase: currentPhase
|
|
8045
8212
|
};
|
|
8046
8213
|
};
|
|
8047
8214
|
const getDirectInspectorUrl = () => {
|
|
@@ -8105,6 +8272,8 @@ async function runLocalDebugServer(options = {}) {
|
|
|
8105
8272
|
const shutdown = () => {
|
|
8106
8273
|
if (closed) return;
|
|
8107
8274
|
closed = true;
|
|
8275
|
+
currentPhase = "shutdown";
|
|
8276
|
+
qrServer?.notifyStateChange();
|
|
8108
8277
|
parentWatcher?.stop();
|
|
8109
8278
|
maxAgeWatchdog?.stop();
|
|
8110
8279
|
if (totpRefreshHandle) clearInterval(totpRefreshHandle);
|
|
@@ -8225,6 +8394,7 @@ async function runMobileDebugServer(options = {}) {
|
|
|
8225
8394
|
return router.active;
|
|
8226
8395
|
});
|
|
8227
8396
|
let lastAttachParts = null;
|
|
8397
|
+
let currentPhase = "active";
|
|
8228
8398
|
const getDashboardState = () => {
|
|
8229
8399
|
const targets = router.active.listTargets();
|
|
8230
8400
|
const inspectorUrl = qrServer?.inspectorStableUrl ?? null;
|
|
@@ -8238,7 +8408,8 @@ async function runMobileDebugServer(options = {}) {
|
|
|
8238
8408
|
url: t.url
|
|
8239
8409
|
})),
|
|
8240
8410
|
attachUrl: lastAttachParts ? rebuildAttachUrl(lastAttachParts) : null,
|
|
8241
|
-
inspectorUrl
|
|
8411
|
+
inspectorUrl,
|
|
8412
|
+
phase: currentPhase
|
|
8242
8413
|
};
|
|
8243
8414
|
};
|
|
8244
8415
|
const getDirectInspectorUrl = () => {
|
|
@@ -8302,6 +8473,8 @@ async function runMobileDebugServer(options = {}) {
|
|
|
8302
8473
|
const shutdown = () => {
|
|
8303
8474
|
if (closed) return;
|
|
8304
8475
|
closed = true;
|
|
8476
|
+
currentPhase = "shutdown";
|
|
8477
|
+
qrServer?.notifyStateChange();
|
|
8305
8478
|
parentWatcher?.stop();
|
|
8306
8479
|
maxAgeWatchdog?.stop();
|
|
8307
8480
|
if (totpRefreshHandle) clearInterval(totpRefreshHandle);
|
|
@@ -8823,7 +8996,7 @@ function createDevServer(deps = {}) {
|
|
|
8823
8996
|
const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
|
|
8824
8997
|
const server = new Server({
|
|
8825
8998
|
name: "ait-devtools",
|
|
8826
|
-
version: "0.1.
|
|
8999
|
+
version: "0.1.132"
|
|
8827
9000
|
}, { capabilities: { tools: {} } });
|
|
8828
9001
|
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
|
|
8829
9002
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|