@ait-co/devtools 0.1.133 → 0.1.135

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 (70) hide show
  1. package/dist/{cdp-connection-D7AYQck2.d.ts → cdp-connection-BYE9meXe.d.ts} +12 -2
  2. package/dist/{cdp-connection-D7AYQck2.d.ts.map → cdp-connection-BYE9meXe.d.ts.map} +1 -1
  3. package/dist/{debug-server-CS1BS2BX.js → debug-server-B2aCwwtV.js} +24 -9
  4. package/dist/debug-server-B2aCwwtV.js.map +1 -0
  5. package/dist/{debug-server-DnNCoNiR.js → debug-server-CBqMfcUi.js} +2 -2
  6. package/dist/{debug-server-DnNCoNiR.js.map → debug-server-CBqMfcUi.js.map} +1 -1
  7. package/dist/{debug-server-DmzuK2c6.js → debug-server-DR84Z243.js} +9 -4
  8. package/dist/debug-server-DR84Z243.js.map +1 -0
  9. package/dist/mcp/cli.js +105 -21
  10. package/dist/mcp/cli.js.map +1 -1
  11. package/dist/mcp/server.js +1 -1
  12. package/dist/panel/index.js +1 -1
  13. package/dist/{pool-x28Wv1ty.d.ts → pool-C6TgrcyW.d.ts} +3 -3
  14. package/dist/{pool-x28Wv1ty.d.ts.map → pool-C6TgrcyW.d.ts.map} +1 -1
  15. package/dist/{qr-http-server-iH_Hh_si.cjs → qr-http-server-B1en4tTL.cjs} +60 -7
  16. package/dist/{qr-http-server-iH_Hh_si.cjs.map → qr-http-server-B1en4tTL.cjs.map} +1 -1
  17. package/dist/{qr-http-server-C_DTp9WU.js → qr-http-server-CLt72Dwe.js} +60 -8
  18. package/dist/{qr-http-server-DeRrKp_R.js.map → qr-http-server-CLt72Dwe.js.map} +1 -1
  19. package/dist/{qr-http-server-FVn61xAq.js → qr-http-server-DlNWJEaH.js} +60 -7
  20. package/dist/{qr-http-server-C_DTp9WU.js.map → qr-http-server-DlNWJEaH.js.map} +1 -1
  21. package/dist/{qr-http-server-DX_9UA-p.cjs → qr-http-server-hnuUw9TK.cjs} +60 -7
  22. package/dist/{qr-http-server-DX_9UA-p.cjs.map → qr-http-server-hnuUw9TK.cjs.map} +1 -1
  23. package/dist/{qr-http-server-V0xuU5TJ.js → qr-http-server-iBqsAKor.js} +60 -7
  24. package/dist/{qr-http-server-V0xuU5TJ.js.map → qr-http-server-iBqsAKor.js.map} +1 -1
  25. package/dist/{qr-http-server-DeRrKp_R.js → qr-http-server-yQ1EWTwf.js} +61 -7
  26. package/dist/{qr-http-server-FVn61xAq.js.map → qr-http-server-yQ1EWTwf.js.map} +1 -1
  27. package/dist/{relay-factory-BQfmK7RP.js → relay-factory-CjqAJ3Y8.js} +4 -4
  28. package/dist/relay-factory-CjqAJ3Y8.js.map +1 -0
  29. package/dist/{relay-worker-DtX_eszH.d.ts → relay-worker-Dw3aIzIK.d.ts} +3 -3
  30. package/dist/{relay-worker-DtX_eszH.d.ts.map → relay-worker-Dw3aIzIK.d.ts.map} +1 -1
  31. package/dist/{relay-worker-MZq4fLv8.js → relay-worker-UK0nBfDX.js} +18 -8
  32. package/dist/relay-worker-UK0nBfDX.js.map +1 -0
  33. package/dist/{runtime-9xhN9pr8.d.ts → runtime-DfHHZms2.d.ts} +34 -5
  34. package/dist/runtime-DfHHZms2.d.ts.map +1 -0
  35. package/dist/test-runner/bin.js +68 -15
  36. package/dist/test-runner/bin.js.map +1 -1
  37. package/dist/test-runner/config.d.ts +9 -1
  38. package/dist/test-runner/config.d.ts.map +1 -1
  39. package/dist/test-runner/config.js +1 -1
  40. package/dist/test-runner/pool.d.ts +1 -1
  41. package/dist/test-runner/pool.js +1 -1
  42. package/dist/test-runner/relay-factory.d.ts +19 -1
  43. package/dist/test-runner/relay-factory.d.ts.map +1 -1
  44. package/dist/test-runner/relay-factory.js +3 -3
  45. package/dist/test-runner/relay-factory.js.map +1 -1
  46. package/dist/test-runner/relay-worker.d.ts +1 -1
  47. package/dist/test-runner/relay-worker.js +1 -1
  48. package/dist/test-runner/report.d.ts +2 -2
  49. package/dist/test-runner/rpc.d.ts +8 -5
  50. package/dist/test-runner/rpc.d.ts.map +1 -1
  51. package/dist/test-runner/rpc.js +15 -4
  52. package/dist/test-runner/rpc.js.map +1 -1
  53. package/dist/test-runner/runtime.d.ts +2 -2
  54. package/dist/test-runner/runtime.js +30 -4
  55. package/dist/test-runner/runtime.js.map +1 -1
  56. package/dist/test-runner/task-graph.d.ts +1 -1
  57. package/dist/{tunnel-DP453L4e.cjs → tunnel-Cr_oTkaj.cjs} +2 -2
  58. package/dist/{tunnel-DP453L4e.cjs.map → tunnel-Cr_oTkaj.cjs.map} +1 -1
  59. package/dist/{tunnel-Djf-zmjJ.js → tunnel-DUCogcQi.js} +2 -2
  60. package/dist/{tunnel-Djf-zmjJ.js.map → tunnel-DUCogcQi.js.map} +1 -1
  61. package/dist/unplugin/index.cjs +1 -1
  62. package/dist/unplugin/index.js +1 -1
  63. package/dist/unplugin/tunnel.cjs +1 -1
  64. package/dist/unplugin/tunnel.js +1 -1
  65. package/package.json +1 -1
  66. package/dist/debug-server-CS1BS2BX.js.map +0 -1
  67. package/dist/debug-server-DmzuK2c6.js.map +0 -1
  68. package/dist/relay-factory-BQfmK7RP.js.map +0 -1
  69. package/dist/relay-worker-MZq4fLv8.js.map +0 -1
  70. package/dist/runtime-9xhN9pr8.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.133";
2027
+ return "0.1.135";
2028
2028
  }
2029
2029
  /**
2030
2030
  * Derives the next recommended action from a completed diagnostics snapshot.
@@ -3513,9 +3513,13 @@ var ChiiCdpConnection = class {
3513
3513
  /**
3514
3514
  * Issue a CDP command and resolve with its result (Phase 2). Rejects on a CDP
3515
3515
  * error frame or when no websocket is open (no page attached yet).
3516
+ *
3517
+ * @param opts.timeoutMs - Per-call override for this connection's command
3518
+ * watchdog (devtools#747) — see the `CdpConnection.send` docblock for the
3519
+ * contract callers racing their own longer timeout must follow.
3516
3520
  */
3517
- send(method, params) {
3518
- return this.sendCommand(method, params ?? {});
3521
+ send(method, params, opts) {
3522
+ return this.sendCommand(method, params ?? {}, opts);
3519
3523
  }
3520
3524
  /**
3521
3525
  * Issue an arbitrary request→response command over the relay and resolve with
@@ -3526,16 +3530,22 @@ var ChiiCdpConnection = class {
3526
3530
  * auto-reconnect). Caller should re-run `list_pages` or `enableDomains` to
3527
3531
  * reattach.
3528
3532
  *
3529
- * Times out after `commandTimeoutMs` (default 30s, env
3530
- * `AIT_CDP_COMMAND_TIMEOUT_MS`). On timeout the pending entry is cleaned up
3531
- * and the promise rejects with a descriptive Korean error.
3533
+ * Times out after `opts.timeoutMs` when given, else `commandTimeoutMs`
3534
+ * (default 30s, env `AIT_CDP_COMMAND_TIMEOUT_MS`) see devtools#747: the
3535
+ * default 30s watchdog used to undercut the test-runner's own longer
3536
+ * file-evaluate race no matter what `--timeout` the caller asked for. On
3537
+ * timeout the pending entry is cleaned up and the promise rejects with a
3538
+ * descriptive Korean error. `Number.isFinite` guards against a non-finite
3539
+ * override (e.g. `Infinity`, mirroring `waitForFirstTarget`'s convention)
3540
+ * so an intentional "no watchdog" override doesn't get clamped by
3541
+ * `setTimeout`.
3532
3542
  */
3533
- sendCommand(method, params = {}) {
3543
+ sendCommand(method, params = {}, opts) {
3534
3544
  if (this.connectionState === "disconnected") return Promise.reject(/* @__PURE__ */ new Error(`relay에 연결되어 있지 않습니다 (${method}). list_pages로 attach 상태를 확인하고 enableDomains()로 재연결하세요.`));
3535
3545
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return Promise.reject(/* @__PURE__ */ new Error("No mini-app page attached to the Chii relay yet. Call enableDomains() first."));
3536
3546
  const id = this.nextCommandId++;
3537
3547
  const ws = this.ws;
3538
- const timeoutMs = this.commandTimeoutMs;
3548
+ const timeoutMs = opts?.timeoutMs !== void 0 && Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0 ? opts.timeoutMs : this.commandTimeoutMs;
3539
3549
  return new Promise((resolve, reject) => {
3540
3550
  const handle = setTimeout(() => {
3541
3551
  this.pending.delete(id);
@@ -4120,6 +4130,14 @@ function parseCaptureLines(raw) {
4120
4130
  /** Maximum milliseconds to wait for a single evaluate round-trip. */
4121
4131
  const DEFAULT_TIMEOUT_MS = 6e4;
4122
4132
  /**
4133
+ * Extra headroom (ms) added on top of the rpc-level `timeoutMs` when telling
4134
+ * the underlying `CdpConnection` its per-command watchdog budget (devtools#747).
4135
+ * The rpc-level race above is the authoritative file timeout — this margin
4136
+ * only ensures the connection's own (shorter-by-default) watchdog never fires
4137
+ * first and masks the rpc-level timeout error with a connection-level one.
4138
+ */
4139
+ const CONNECTION_TIMEOUT_MARGIN_MS = 5e3;
4140
+ /**
4123
4141
  * Wraps bundle code in a self-executing IIFE that:
4124
4142
  * 1. Evaluates the bundle (registering describe/it/test).
4125
4143
  * 2. Calls `__testBundle.runTestModule(...)` — the entry the runtime exports.
@@ -4166,12 +4184,15 @@ function parseRunTestsResult(rawValue) {
4166
4184
  * Injects `bundleCode` into the attached page and awaits test execution.
4167
4185
  *
4168
4186
  * Uses `Runtime.evaluate` with `awaitPromise: true` to wait for the
4169
- * async IIFE to settle. The 30-second CDP command timeout covers even
4170
- * long-running test suites; split into smaller files if you hit it.
4187
+ * async IIFE to settle. `timeoutMs` (default 60s) is the authoritative file
4188
+ * timeout this function races it against the evaluate call AND (devtools#747)
4189
+ * threads it down to the underlying `CdpConnection`'s own per-command watchdog
4190
+ * (plus a small margin) so that watchdog can never undercut this race. Split
4191
+ * into smaller files if you hit the timeout.
4171
4192
  *
4172
4193
  * @param connection - Active CDP connection (relay or local).
4173
4194
  * @param bundleCode - IIFE bundle string from `bundleTestFile`.
4174
- * @param timeoutMs - Override the default 30 s timeout.
4195
+ * @param timeoutMs - Override the default 60 s timeout.
4175
4196
  *
4176
4197
  * SECRET-HANDLING: `bundleCode` and the raw CDP result value are never logged.
4177
4198
  */
@@ -4183,7 +4204,7 @@ async function injectAndRunBundle(connection, bundleCode, timeoutMs = DEFAULT_TI
4183
4204
  expression,
4184
4205
  returnByValue: true,
4185
4206
  awaitPromise: true
4186
- });
4207
+ }, { timeoutMs: timeoutMs + CONNECTION_TIMEOUT_MARGIN_MS });
4187
4208
  const raceResult = await Promise.race([evalPromise.then((v) => ({
4188
4209
  tag: "eval",
4189
4210
  v
@@ -4441,6 +4462,11 @@ OPTIONS
4441
4462
  (report: <sdkLine>.<platform>.json; captures:
4442
4463
  <dir>/.ait-capture/<category>.<sdkLine>.<platform>.json).
4443
4464
  Omitted = nothing saved. Enables console capture.
4465
+ --dashboard-port <port> Base port for the QR dashboard HTTP server. On
4466
+ EADDRINUSE it increments (+1, up to 20 tries) before
4467
+ falling back to an ephemeral port. Omit to use
4468
+ AIT_DEBUG_HTTP_PORT env or the built-in default
4469
+ (8317) — pass 0 to force a random ephemeral port.
4444
4470
  --no-qr-stdout Suppress the QR/attach block on stdout (auto-on for
4445
4471
  non-interactive stdout / CI / AIT_NO_QR_STDOUT)
4446
4472
  --headless Disable browser auto-open (text QR only)
@@ -5244,8 +5270,13 @@ var LocalCdpConnection = class {
5244
5270
  /**
5245
5271
  * Issue a CDP command and resolve with its typed result. Rejects on a CDP
5246
5272
  * error frame or when no websocket is open.
5273
+ *
5274
+ * `opts.timeoutMs` is accepted for `CdpConnection` interface parity but
5275
+ * ignored — this connection has no per-command watchdog of its own
5276
+ * (devtools#747 only affects `ChiiCdpConnection`, which layers a
5277
+ * relay-command watchdog on top of the caller's own race).
5247
5278
  */
5248
- send(method, params) {
5279
+ send(method, params, _opts) {
5249
5280
  return this.sendCommand(method, params ?? {});
5250
5281
  }
5251
5282
  /**
@@ -6786,13 +6817,70 @@ function buildAttachHtml(qrDataUrl, safeLabel, safeAttachUrl, locale, path = "/a
6786
6817
  return filled.replace("</body>", `${sseScript}\n</body>`);
6787
6818
  }
6788
6819
  /**
6789
- * 로컬 HTTP 서버를 127.0.0.1 random port(또는 `AIT_DEBUG_HTTP_PORT` env)로 시작한다.
6820
+ * base 포트부터 EADDRINUSE 시 +1 증가하며 bind를 시도한다. EADDRINUSE가
6821
+ * 아닌 에러는 즉시 reject한다(스캔 대상 아님). `range`번 모두 점유 상태면
6822
+ * ephemeral(포트 0)로 폴백하고 한국어 안내를 stderr에 1회 출력한다.
6823
+ *
6824
+ * 매 시도마다 이전에 등록한 `error` 리스너를 제거한다 — 성공 시 listener가
6825
+ * 누적돼 다음 실패에서 중복 reject/EventEmitter 경고가 나는 것을 방지한다.
6826
+ *
6827
+ * `basePort === 0`이면 스캔 없이 즉시 ephemeral bind (명시적 opt-out, 기존
6828
+ * 순수 랜덤 포트 동작 유지).
6829
+ */
6830
+ async function bindWithIncrement(server, basePort, range = 20) {
6831
+ if (basePort === 0) return new Promise((resolve, reject) => {
6832
+ const onError = (err) => reject(err);
6833
+ server.once("error", onError);
6834
+ server.listen(0, "127.0.0.1", () => {
6835
+ server.removeListener("error", onError);
6836
+ resolve();
6837
+ });
6838
+ });
6839
+ for (let attempt = 0; attempt < range; attempt++) {
6840
+ const candidatePort = basePort + attempt;
6841
+ try {
6842
+ await new Promise((resolve, reject) => {
6843
+ const onError = (err) => {
6844
+ server.removeListener("error", onError);
6845
+ reject(err);
6846
+ };
6847
+ server.once("error", onError);
6848
+ server.listen(candidatePort, "127.0.0.1", () => {
6849
+ server.removeListener("error", onError);
6850
+ resolve();
6851
+ });
6852
+ });
6853
+ return;
6854
+ } catch (err) {
6855
+ if (err.code !== "EADDRINUSE") throw err;
6856
+ }
6857
+ }
6858
+ process.stderr.write(`devtools: 대시보드 포트 ${basePort}~${basePort + range - 1}이 모두 사용 중이라 임의 포트로 대체합니다.\n`);
6859
+ return new Promise((resolve, reject) => {
6860
+ const onError = (err) => reject(err);
6861
+ server.once("error", onError);
6862
+ server.listen(0, "127.0.0.1", () => {
6863
+ server.removeListener("error", onError);
6864
+ resolve();
6865
+ });
6866
+ });
6867
+ }
6868
+ /**
6869
+ * 로컬 HTTP 서버를 127.0.0.1에 고정 base 포트({@link DEFAULT_DASHBOARD_PORT},
6870
+ * `AIT_DEBUG_HTTP_PORT` env, 또는 `options.dashboardPort`)에서 시작한다.
6871
+ * base 포트가 점유(EADDRINUSE) 상태면 +1씩 증가하며 재시도하고(최대
6872
+ * {@link PORT_SCAN_RANGE}회), 전부 점유면 ephemeral 포트로 폴백한다 —
6873
+ * rerun 시 대시보드 URL이 안정적으로 유지되어 브라우저 탭/북마크가
6874
+ * run마다 무효화되지 않는다 (devtools#752). base 포트를 명시적으로 `0`으로
6875
+ * 주면(env 또는 옵션) 기존 순수 ephemeral 동작을 유지한다.
6876
+ *
6790
6877
  * MCP debug server 생애주기에 묶어 사용 — `runDebugServer` shutdown 시 `close()`로 정리.
6791
6878
  *
6792
6879
  * @param getDashboardState - dashboard 상태를 반환하는 클로저. 주입 시 `GET /` dashboard와
6793
6880
  * `GET /events` SSE 스트림이 활성화된다. 미주입 시 두 라우트는 204/서비스 없음으로 응답.
6794
6881
  * @param options - 서버 옵션. `sseRefreshIntervalMs`로 idle 탭 TOTP 만료 방지 주기를 조정.
6795
6882
  * `getDirectInspectorUrl`로 /inspector 라우트에서 직접 조립 URL을 제공해 redirect 루프를 방지.
6883
+ * `dashboardPort`로 bind base 포트를 override.
6796
6884
  */
6797
6885
  async function startQrHttpServer(getDashboardState, options) {
6798
6886
  const { default: QRCode } = await import("qrcode");
@@ -6972,11 +7060,7 @@ async function startQrHttpServer(getDashboardState, options) {
6972
7060
  res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
6973
7061
  res.end("Not Found");
6974
7062
  });
6975
- const listenPort = Number(process.env.AIT_DEBUG_HTTP_PORT ?? 0);
6976
- await new Promise((resolve, reject) => {
6977
- server.listen(listenPort, "127.0.0.1", () => resolve());
6978
- server.once("error", reject);
6979
- });
7063
+ await bindWithIncrement(server, options?.dashboardPort ?? (process.env.AIT_DEBUG_HTTP_PORT !== void 0 ? Number(process.env.AIT_DEBUG_HTTP_PORT) : 8317), options?.portScanRange);
6980
7064
  const address = server.address();
6981
7065
  if (!address || typeof address === "string") throw new Error("qr-http-server: server.address()가 예상하지 못한 형태입니다.");
6982
7066
  const port = address.port;
@@ -7119,7 +7203,7 @@ function createDebugServer(deps) {
7119
7203
  };
7120
7204
  const server = new Server({
7121
7205
  name: "ait-debug",
7122
- version: "0.1.133"
7206
+ version: "0.1.135"
7123
7207
  }, { capabilities: { tools: { listChanged: true } } });
7124
7208
  server.setRequestHandler(ListToolsRequestSchema, () => {
7125
7209
  const conn = router.active;
@@ -9103,7 +9187,7 @@ function createDevServer(deps = {}) {
9103
9187
  const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
9104
9188
  const server = new Server({
9105
9189
  name: "ait-devtools",
9106
- version: "0.1.133"
9190
+ version: "0.1.135"
9107
9191
  }, { capabilities: { tools: {} } });
9108
9192
  server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
9109
9193
  server.setRequestHandler(CallToolRequestSchema, async (request) => {