@ait-co/devtools 0.1.108 → 0.1.110

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 (79) hide show
  1. package/README.en.md +13 -31
  2. package/README.md +13 -31
  3. package/dist/bundle-KFs4t-wc.d.ts +96 -0
  4. package/dist/bundle-KFs4t-wc.d.ts.map +1 -0
  5. package/dist/in-app/auto.d.ts.map +1 -1
  6. package/dist/in-app/auto.js +40 -3
  7. package/dist/in-app/auto.js.map +1 -1
  8. package/dist/in-app/index.d.ts.map +1 -1
  9. package/dist/in-app/index.js +39 -2
  10. package/dist/in-app/index.js.map +1 -1
  11. package/dist/mcp/cli.d.ts +4 -16
  12. package/dist/mcp/cli.d.ts.map +1 -1
  13. package/dist/mcp/cli.js +803 -712
  14. package/dist/mcp/cli.js.map +1 -1
  15. package/dist/mcp/server.d.ts.map +1 -1
  16. package/dist/mcp/server.js +47 -59
  17. package/dist/mcp/server.js.map +1 -1
  18. package/dist/mock/index.d.ts.map +1 -1
  19. package/dist/mock/index.js +21 -2
  20. package/dist/mock/index.js.map +1 -1
  21. package/dist/panel/index.js +47 -32
  22. package/dist/panel/index.js.map +1 -1
  23. package/dist/{pool-Dkp7I9Bf.d.ts → pool-Bf6rQci4.d.ts} +210 -48
  24. package/dist/pool-Bf6rQci4.d.ts.map +1 -0
  25. package/dist/{qr-http-server-D4EAA7Il.js → qr-http-server-BJJt3ush.js} +8 -17
  26. package/dist/qr-http-server-BJJt3ush.js.map +1 -0
  27. package/dist/{qr-http-server-A9vld8r7.cjs → qr-http-server-BVS-HZjU.cjs} +8 -17
  28. package/dist/qr-http-server-BVS-HZjU.cjs.map +1 -0
  29. package/dist/{qr-http-server-Dj3Z0NHi.cjs → qr-http-server-C1T4RNbq.cjs} +8 -17
  30. package/dist/qr-http-server-C1T4RNbq.cjs.map +1 -0
  31. package/dist/{qr-http-server-HzdCLU8s.js → qr-http-server-Cs93vEPH.js} +8 -17
  32. package/dist/qr-http-server-Cs93vEPH.js.map +1 -0
  33. package/dist/{relay-worker-BzFQ3fv9.d.ts → relay-worker-xxanNQGs.d.ts} +3 -3
  34. package/dist/relay-worker-xxanNQGs.d.ts.map +1 -0
  35. package/dist/{runtime-ORdrpizY.d.ts → runtime-Wi5d6Ywz.d.ts} +3 -3
  36. package/dist/{runtime-ORdrpizY.d.ts.map → runtime-Wi5d6Ywz.d.ts.map} +1 -1
  37. package/dist/test-runner/bundle.d.ts +1 -1
  38. package/dist/test-runner/bundle.js +148 -11
  39. package/dist/test-runner/bundle.js.map +1 -1
  40. package/dist/test-runner/cli.d.ts +59 -14
  41. package/dist/test-runner/cli.d.ts.map +1 -1
  42. package/dist/test-runner/cli.js +171 -32
  43. package/dist/test-runner/cli.js.map +1 -1
  44. package/dist/test-runner/config.d.ts +1 -1
  45. package/dist/test-runner/pool.d.ts +1 -1
  46. package/dist/test-runner/relay-worker.d.ts +1 -1
  47. package/dist/test-runner/relay-worker.js.map +1 -1
  48. package/dist/test-runner/rpc.d.ts +1 -1
  49. package/dist/test-runner/rpc.d.ts.map +1 -1
  50. package/dist/test-runner/rpc.js +1 -1
  51. package/dist/test-runner/rpc.js.map +1 -1
  52. package/dist/test-runner/task-graph.d.ts +1 -1
  53. package/dist/{tunnel-BjJROkcj.js → tunnel-Cpn3mA4u.js} +3 -3
  54. package/dist/tunnel-Cpn3mA4u.js.map +1 -0
  55. package/dist/{tunnel-d_G9AIFn.cjs → tunnel-Dj8Kf2QS.cjs} +3 -3
  56. package/dist/tunnel-Dj8Kf2QS.cjs.map +1 -0
  57. package/dist/unplugin/index.cjs +1 -1
  58. package/dist/unplugin/index.d.cts +196 -34
  59. package/dist/unplugin/index.d.cts.map +1 -1
  60. package/dist/unplugin/index.d.ts +196 -34
  61. package/dist/unplugin/index.d.ts.map +1 -1
  62. package/dist/unplugin/index.js +1 -1
  63. package/dist/unplugin/tunnel.cjs +2 -2
  64. package/dist/unplugin/tunnel.cjs.map +1 -1
  65. package/dist/unplugin/tunnel.d.cts +1 -1
  66. package/dist/unplugin/tunnel.d.ts +1 -1
  67. package/dist/unplugin/tunnel.js +2 -2
  68. package/dist/unplugin/tunnel.js.map +1 -1
  69. package/package.json +14 -14
  70. package/dist/bundle-BJm5jk56.d.ts +0 -49
  71. package/dist/bundle-BJm5jk56.d.ts.map +0 -1
  72. package/dist/pool-Dkp7I9Bf.d.ts.map +0 -1
  73. package/dist/qr-http-server-A9vld8r7.cjs.map +0 -1
  74. package/dist/qr-http-server-D4EAA7Il.js.map +0 -1
  75. package/dist/qr-http-server-Dj3Z0NHi.cjs.map +0 -1
  76. package/dist/qr-http-server-HzdCLU8s.js.map +0 -1
  77. package/dist/relay-worker-BzFQ3fv9.d.ts.map +0 -1
  78. package/dist/tunnel-BjJROkcj.js.map +0 -1
  79. package/dist/tunnel-d_G9AIFn.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","names":[],"sources":["../../src/mcp/ait-source.ts","../../src/mcp/server.ts"],"mappings":";;;;;;;AAsBA;;;;;AAGA;;;;;;;;;;;;;KAHY,kBAAA;AAqBZ;AAAA,UAlBiB,UAAA;;EAEf,MAAA;EAiBiB;EAfjB,IAAA;EAwBsB;EAtBtB,SAAA;EAsByB;EApBzB,MAAA;EAuBe;EArBf,MAAA;;EAEA,KAAA;EAuBU;EArBV,QAAA,EAAU,kBAAA;AAAA;;UAIK,iBAAA;EACf,KAAA,EAAO,UAAA;AAAA;;;;;;;KASG,YAAA,GAAe,MAAA;;UAGV,yBAAA;EAW2C;EAT1D,WAAA;EAYuB;EAVvB,UAAA;AAAA;;UAIe,YAAA;EACf,uBAAA,EAAyB,iBAAA;EACzB,kBAAA,EAAoB,YAAA;EACpB,+BAAA,EAAiC,yBAAA;AAAA;AAAA,KAGvB,aAAA,SAAsB,YAAA;;;;;UAMjB,SAAA;EACf,GAAA,WAAc,aAAA,EAAe,MAAA,EAAQ,CAAA,GAAI,OAAA,CAAQ,YAAA,CAAa,CAAA;AAAA;;;UCsR/C,mBAAA;EDvRS;ECyRxB,SAAA,GAAY,SAAA;AAAA;;iBA2IE,eAAA,CAAgB,IAAA,GAAM,mBAAA,GAA2B,MAAA;;iBAqH3C,YAAA,CAAA,GAAgB,OAAA"}
1
+ {"version":3,"file":"server.d.ts","names":[],"sources":["../../src/mcp/ait-source.ts","../../src/mcp/server.ts"],"mappings":";;;;;;;AAsBA;;;;;AAGA;;;;;;;;;;;;;KAHY,kBAAA;AAqBZ;AAAA,UAlBiB,UAAA;;EAEf,MAAA;EAiBiB;EAfjB,IAAA;EAwBsB;EAtBtB,SAAA;EAsByB;EApBzB,MAAA;EAuBe;EArBf,MAAA;;EAEA,KAAA;EAuBU;EArBV,QAAA,EAAU,kBAAA;AAAA;;UAIK,iBAAA;EACf,KAAA,EAAO,UAAA;AAAA;;;;;;;KASG,YAAA,GAAe,MAAA;;UAGV,yBAAA;EAW2C;EAT1D,WAAA;EAYuB;EAVvB,UAAA;AAAA;;UAIe,YAAA;EACf,uBAAA,EAAyB,iBAAA;EACzB,kBAAA,EAAoB,YAAA;EACpB,+BAAA,EAAiC,yBAAA;AAAA;AAAA,KAGvB,aAAA,SAAsB,YAAA;;;;;UAMjB,SAAA;EACf,GAAA,WAAc,aAAA,EAAe,MAAA,EAAQ,CAAA,GAAI,OAAA,CAAQ,YAAA,CAAa,CAAA;AAAA;;;UCyR/C,mBAAA;ED1RS;EC4RxB,SAAA,GAAY,SAAA;AAAA;;iBA2IE,eAAA,CAAgB,IAAA,GAAM,mBAAA,GAA2B,MAAA;;iBAqH3C,YAAA,CAAA,GAAgB,OAAA"}
@@ -47,9 +47,10 @@ function isCompatMode() {
47
47
  return process.env.AIT_MCP_COMPAT === "chrome-devtools";
48
48
  }
49
49
  /**
50
- * Maps `McpEnvironment` to `EnvelopeEnv`. After #307 these are the same
51
- * union (`mock | relay-dev | relay-live`), so this is identity — kept as a
52
- * named export for surface stability if envelope env diverges in the future.
50
+ * Maps `McpEnvironment` to `EnvelopeEnv`. These are now the same 3-value
51
+ * union (`mock | relay-dev | relay-mobile`; `relay-live` removed in #665),
52
+ * so this is identity — kept as a named export for surface stability if
53
+ * envelope env diverges in the future.
53
54
  */
54
55
  function toEnvelopeEnv(env) {
55
56
  return env;
@@ -108,7 +109,7 @@ function mcpError(message) {
108
109
  * (예: `derived:kind=relay,liveIntent=true`).
109
110
  */
110
111
  function tierRejectionError(toolName, requiredEnv, currentEnv, reason) {
111
- return mcpError(`${`${toolName}은 ${requiredEnv === "relay" ? "relay (실기기 연결)" : "mock (로컬 브라우저)"} 환경에서만 사용할 수 있습니다. 현재 환경: ${currentEnv === "relay" ? "relay" : "mock"} (${reason}). ${requiredEnv === "relay" ? "relay로 전환하려면 MCP_ENV=relay 설정 후 서버를 재시작하고 build_attach_url → QR 스캔으로 실기기를 attach하세요." : "mock으로 전환하려면 MCP_ENV=mock 설정 후 서버를 재시작하세요."}`}\n\n${`tool ${toolName} is available only in ${requiredEnv}. Current environment is ${currentEnv} (${reason}).`}`);
112
+ return mcpError(`${`${toolName}은 ${requiredEnv === "relay" ? "relay (실기기 연결)" : "mock (로컬 브라우저)"} 환경에서만 사용할 수 있습니다. 현재 환경: ${currentEnv === "relay" ? "relay" : "mock"} (${reason}). ${requiredEnv === "relay" ? "relay로 전환하려면 MCP_ENV=relay 설정 후 서버를 재시작하고 start_attach → QR 스캔으로 실기기를 attach하세요." : "mock으로 전환하려면 MCP_ENV=mock 설정 후 서버를 재시작하세요."}`}\n\n${`tool ${toolName} is available only in ${requiredEnv}. Current environment is ${currentEnv} (${reason}).`}`);
112
113
  }
113
114
  //#endregion
114
115
  //#region src/mcp/sdk-signatures.ts
@@ -287,22 +288,27 @@ new Set([
287
288
  availableIn: "both"
288
289
  },
289
290
  {
290
- name: "build_attach_url",
291
- description: "The tool result already shows the QR to the user directly (Claude Code renders MCP tool output to the user's screen; they press Ctrl+O to expand if it's collapsed). Do NOT re-print or re-render the QR in your reply — that just wastes output tokens. Simply tell the user to scan the QR shown in this tool's output with their phone camera. Builds a self-attaching deep-link for the active relay environment and returns a QR code. Scan the QR with the phone camera to open the mini-app and attach it to this debug session (QR is the single entry path — no USB cable or platform CLI needed). Call list_pages first to confirm the relay/tunnel is up. If the tunnel is not up, restart: `npx @ait-co/devtools devtools-mcp`.\n\nEnvironment-specific behaviour:\n • env 3 / relay-staging (start_debug mode=\"relay-staging\"): requires scheme_url — the intoss-private://…?_deploymentId=<uuid> URL from `ait deploy --scheme-only`. Splices debug=1 + relay URL into the scheme URL to produce a self-attach deep-link.\n • env 2 / relay-sandbox (start_debug mode=\"relay-sandbox\"): scheme_url is NOT used. Instead, reads AIT_TUNNEL_BASE_URL (the https://*.trycloudflare.com app tunnel from `tunnel:{cdp:true}`) and builds a launcher PWA deep-link (https://devtools.aitc.dev/launcher/?url=…&debug=1&relay=…). When projectRoot is given, the app name from <projectRoot>/package.json is automatically added as name= so the launcher partner bar shows it. Scan the QR with the phone to open the launcher, which frames the tunnel URL and attaches CDP.\n\nSet wait_for_attach=true to block until a page attaches (default 60 s, adjustable via wait_timeout_seconds). On timeout, call build_attach_url again to resume polling. The server automatically opens the QR dashboard in the OS default browser when running on a local GUI machine — headless/remote environments fall back to the text QR in the tool output.\n\nTOTP auth: when AIT_DEBUG_TOTP_SECRET is set on the MCP server, the returned attachUrl automatically includes the current one-time code (at=<code>). The code is valid for ~3 minutes (the relay gate accepts ±6 TOTP steps = 180–210 s of backwards acceptance). The response includes a `totp` field with `expiresAt` (ISO timestamp, ~3 min from issuance). If the phone scan happens after expiresAt, the relay will reject the code — just call build_attach_url again to get a fresh URL. Without AIT_DEBUG_TOTP_SECRET, the attachUrl has no expiry.\n\nselfdebug (env 2 / relay-sandbox only): pass selfdebug=true to add &selfdebug=1 to the launcher deep-link. The launcher PWA then registers its own document as the CDP target instead of the framed mini-app. SINGLE-ATTACH MODEL: attaching the launcher self-target evicts any currently-attached mini-app target — use this mode exclusively for diagnosing the launcher document itself (DOM, safe-area, console). Not applicable in env 3/4 (relay-staging/relay-live) — passing selfdebug=true there returns an error.",
291
+ name: "start_attach",
292
+ description: "The tool result already shows the QR to the user directly (Claude Code renders MCP tool output to the user's screen; they press Ctrl+O to expand if it's collapsed). Do NOT re-print or re-render the QR in your reply — that just wastes output tokens. Simply tell the user to scan the QR shown in this tool's output with their phone camera. Single entry point to attach a real device: switches the debug mode (if `mode` is given), builds the self-attaching deep-link QR for the active relay environment, and waits for the phone to attach — all in one call (replaces the old attach-URL + start_debug two-step). Scan the QR with the phone camera to open the mini-app and attach it to this debug session (QR is the single entry path — no USB cable or platform CLI needed).\n\nmode (optional): pass \"relay-sandbox\" (env 2) or \"relay-staging\" (env 3) to switch the active environment first. When omitted, the current relay environment is used as-is (no switch). Passing \"local-browser\" returns an error — start_attach is relay-only (env 2/3). When the session is already in the requested mode, the switch is skipped.\n\nEnvironment-specific behaviour:\n • env 3 / relay-staging: requires scheme_url — the intoss-private://…?_deploymentId=<uuid> URL from `ait deploy --scheme-only`. Splices debug=1 + relay URL into the scheme URL.\n • env 2 / relay-sandbox: scheme_url is NOT used. Instead, reads AIT_TUNNEL_BASE_URL (the https://*.trycloudflare.com app tunnel from `tunnel:{cdp:true}`) and builds a launcher PWA deep-link (https://devtools.aitc.dev/launcher/?url=…&debug=1&relay=…). When projectRoot is given, the app name from <projectRoot>/package.json is added as name= so the launcher partner bar shows it.\n\nWaits for a page to attach by default (up to wait_timeout_seconds, default 60 s). The server automatically opens the QR dashboard in the OS default browser when running on a local GUI machine — headless/remote environments fall back to the text QR in the tool output.\n\nTOTP auto re-mint: when AIT_DEBUG_TOTP_SECRET is set on the MCP server, the attachUrl carries a one-time code (at=<code>) valid for ~3 minutes (the relay gate accepts ±6 TOTP steps). While waiting, start_attach AUTOMATICALLY re-mints a fresh code before the current one expires and refreshes the dashboard QR in place (no browser re-open). You do NOT need to re-call start_attach every time the code would expire a single call covers the whole wait window. The response includes a `totp` field with `expiresAt` and a `reminted` count of how many fresh codes were issued during the wait. Without AIT_DEBUG_TOTP_SECRET, the attachUrl has no expiry.\n\nselfdebug (env 2 / relay-sandbox only): pass selfdebug=true to add &selfdebug=1 to the launcher deep-link. The launcher PWA then registers its own document as the CDP target instead of the framed mini-app. SINGLE-ATTACH MODEL: attaching the launcher self-target evicts any currently-attached mini-app target — use this mode exclusively for diagnosing the launcher document itself (DOM, safe-area, console). Not applicable in env 3 (relay-staging) — passing selfdebug=true there returns an error.",
292
293
  inputSchema: {
293
294
  type: "object",
294
295
  properties: {
296
+ mode: {
297
+ type: "string",
298
+ enum: [
299
+ "local-browser",
300
+ "relay-sandbox",
301
+ "relay-staging"
302
+ ],
303
+ description: "Optional debug mode to switch into before attaching. \"relay-sandbox\" = env 2 (launcher PWA), \"relay-staging\" = env 3 (intoss-private dog-food). \"local-browser\" returns an error (start_attach is relay-only). Omit to keep the current relay environment."
304
+ },
295
305
  scheme_url: {
296
306
  type: "string",
297
307
  description: "The intoss-private:// scheme URL from `ait deploy --scheme-only` (must carry _deploymentId). Required for env 3/relay-staging mode. Not used in env 2/relay-sandbox mode (use AIT_TUNNEL_BASE_URL instead). The authority (host) must be the app name (e.g. intoss-private://aitc-sdk-example?_deploymentId=…). Generic values like \"web\" or an empty host indicate a malformed URL."
298
308
  },
299
- wait_for_attach: {
300
- type: "boolean",
301
- description: "If true, block after returning the QR until a page attaches to the relay (polls listTargets ~1 s interval, default 60 s). On attach, the response includes the attached page list. On timeout, call build_attach_url again to resume polling."
302
- },
303
309
  wait_timeout_seconds: {
304
310
  type: "number",
305
- description: "Maximum seconds to wait when wait_for_attach=true (default 60, range 1–600). Values outside the range or invalid inputs (0, negative, NaN) fall back to the default silently. Only meaningful when wait_for_attach=true."
311
+ description: "Maximum seconds to wait for a page to attach (default 60, range 1–600). Values outside the range or invalid inputs (0, negative, NaN) fall back to the default silently. During the wait the TOTP code is auto re-minted as needed, so a single call covers the whole window."
306
312
  },
307
313
  projectRoot: {
308
314
  type: "string",
@@ -310,7 +316,7 @@ new Set([
310
316
  },
311
317
  selfdebug: {
312
318
  type: "boolean",
313
- description: "Env 2 / relay-sandbox only. When true, adds &selfdebug=1 to the launcher deep-link so the launcher PWA registers its own document as the CDP target (launcher diagnostics mode). SINGLE-ATTACH MODEL: self-target attach evicts any currently-attached mini-app target. Use only when you need to inspect the launcher itself (DOM, safe-area, console). Passing selfdebug=true in env 3/4 (relay-staging/relay-live) returns an error. Default: false (omitted — output is byte-identical to previous behaviour)."
319
+ description: "Env 2 / relay-sandbox only. When true, adds &selfdebug=1 to the launcher deep-link so the launcher PWA registers its own document as the CDP target (launcher diagnostics mode). SINGLE-ATTACH MODEL: self-target attach evicts any currently-attached mini-app target. Use only when you need to inspect the launcher itself (DOM, safe-area, console). Passing selfdebug=true in env 3 (relay-staging) returns an error. Default: false (omitted)."
314
320
  }
315
321
  },
316
322
  required: []
@@ -349,7 +355,7 @@ new Set([
349
355
  },
350
356
  {
351
357
  name: "measure_safe_area",
352
- description: "Runs a safe-area probe on the attached mini-app page via Runtime.evaluate and returns normalized safe-area insets, viewport geometry, device pixel ratio, and User-Agent. Read-only — does not modify page state. Tier C per RFC #277: the same Runtime.evaluate probe runs in both `mock` (devtools panel page with window.__ait state) and `relay` (real-device WebView with window.__sdk). The result includes a `source: \"mock\" | \"relay-dev\" | \"relay-live\" | \"relay-mobile\"` field so consumers can identify provenance without inspecting payload values. (`relay-mobile` = env 2 real-device PWA over an external relay; `relay-dev` = env 3 dog-food WebView; `relay-live` = env 4 production WebView.) Use in a relay session (phone attached) to get ground-truth values for upgrading a viewport preset from extrapolated/placeholder to measured. Requires a page to be attached — call list_pages first.",
358
+ description: "Runs a safe-area probe on the attached mini-app page via Runtime.evaluate and returns normalized safe-area insets, viewport geometry, device pixel ratio, and User-Agent. Read-only — does not modify page state. Tier C per RFC #277: the same Runtime.evaluate probe runs in both `mock` (devtools panel page with window.__ait state) and `relay` (real-device WebView with window.__sdk). The result includes a `source: \"mock\" | \"relay-dev\" | \"relay-mobile\"` field so consumers can identify provenance without inspecting payload values. (`relay-mobile` = env 2 real-device PWA over an external relay; `relay-dev` = env 3 dog-food WebView; relay-live/env 4 removed #665.) Use in a relay session (phone attached) to get ground-truth values for upgrading a viewport preset from extrapolated/placeholder to measured. Requires a page to be attached — call list_pages first.",
353
359
  inputSchema: {
354
360
  type: "object",
355
361
  properties: {},
@@ -359,19 +365,13 @@ new Set([
359
365
  },
360
366
  {
361
367
  name: "evaluate",
362
- description: "Evaluates an arbitrary JavaScript expression on the attached mini-app page via CDP Runtime.evaluate (returnByValue: true) and returns the result. NOT read-only — the expression can have side effects (DOM mutations, SDK calls, state changes). Requires the relay to be attached — call list_pages first. Throws if the evaluation throws an exception on the page.\n\nSECURITY: expression and result are not redacted — never include secrets or auth tokens in the expression.\n\nLIVE guard: when running against a live/production relay (relay-live env, MCP_ENV=relay-live), this tool requires `confirm: true` to acknowledge that the expression may affect real users. Without it the call is rejected with a structured error. mock and relay-dev sessions are unaffected.",
368
+ description: "Evaluates an arbitrary JavaScript expression on the attached mini-app page via CDP Runtime.evaluate (returnByValue: true) and returns the result. NOT read-only — the expression can have side effects (DOM mutations, SDK calls, state changes). Requires the relay to be attached — call list_pages first. Throws if the evaluation throws an exception on the page.\n\nSECURITY: expression and result are not redacted — never include secrets or auth tokens in the expression.\n\nPositive-allowlist kill-switch (#665): this tool is blocked when the attached page is on a non-debug host (apps.tossmini.com / env 4). Only localhost, *.trycloudflare.com, and *.private-apps.tossmini.com are allowed. relay-live (env 4) and the LIVE confirm guard are removed.",
363
369
  inputSchema: {
364
370
  type: "object",
365
- properties: {
366
- expression: {
367
- type: "string",
368
- description: "JavaScript expression to evaluate in the page context."
369
- },
370
- confirm: {
371
- type: "boolean",
372
- description: "Required when MCP_ENV=relay-live. Set to `true` to explicitly acknowledge that this expression may have side effects on real/live users. Omitting this in a relay-live session results in a structured rejection error. Has no effect in mock or relay-dev sessions."
373
- }
374
- },
371
+ properties: { expression: {
372
+ type: "string",
373
+ description: "JavaScript expression to evaluate in the page context."
374
+ } },
375
375
  required: ["expression"]
376
376
  },
377
377
  availableIn: "both"
@@ -391,7 +391,7 @@ new Set([
391
391
  },
392
392
  {
393
393
  name: "call_sdk",
394
- description: "Calls a dog-food SDK method via the window.__sdkCall bridge (exported by @apps-in-toss/web-framework only in __DEBUG_BUILD__ bundles). NOT read-only — SDK calls have side effects (navigation, payments, permissions, etc.). On env 3/4 (real device relay) this hits the real SDK; on env 1 (local mock) and env 2 (PWA relay — real WebKit, mock SDK) it hits the mock SDK. Requires the relay to be attached — call list_pages first. Returns {ok: true, value} on success or {ok: false, error} on failure. If a Runtime.exceptionThrown event was observed within [callStart-50ms, callEnd+200ms], the result also includes `recentException` for crash triage. Returns a clear error if window.__sdkCall is not available — on relay (env 3/4) that means a non-dog-food bundle (redeploy via `ait build && aitcc app deploy`); on local (--target=local, env 1) it means the dev bridge is not installed (start the dev server with `pnpm dev`).\n\nSECURITY: method name, args, and result value are not redacted — never include secrets.\n\nLIVE guard: when running against a live/production relay (relay-live env, MCP_ENV=relay-live), this tool requires `confirm: true` to acknowledge that the SDK call may affect real users. Without it the call is rejected with a structured error. mock and relay-dev sessions are unaffected.\n\nIMPORTANT — 인자 시그니처 (잘못된 인자로 호출하면 토스 앱 crash 위험):\n setDeviceOrientation: call_sdk(\"setDeviceOrientation\", [{ type: \"landscape\" }]) // NOT \"landscape\"\n setIosSwipeGestureEnabled: call_sdk(\"setIosSwipeGestureEnabled\", [{ isEnabled: false }])\n setSecureScreen: call_sdk(\"setSecureScreen\", [{ enabled: true }])\n setScreenAwakeMode: call_sdk(\"setScreenAwakeMode\", [{ enabled: true }])\n getOperationalEnvironment: call_sdk(\"getOperationalEnvironment\", [])\n getPlatformOS: call_sdk(\"getPlatformOS\", [])\n getDeviceId: call_sdk(\"getDeviceId\", [])\n getLocale: call_sdk(\"getLocale\", [])\n getNetworkStatus: call_sdk(\"getNetworkStatus\", [])\n getSchemeUri: call_sdk(\"getSchemeUri\", [])\n requestReview: call_sdk(\"requestReview\", [])\n closeView: call_sdk(\"closeView\", [])",
394
+ description: "Calls a dog-food SDK method via the window.__sdkCall bridge (exported by @apps-in-toss/web-framework only in __DEBUG_BUILD__ bundles). NOT read-only — SDK calls have side effects (navigation, payments, permissions, etc.). On env 3/4 (real device relay) this hits the real SDK; on env 1 (local mock) and env 2 (PWA relay — real WebKit, mock SDK) it hits the mock SDK. Requires the relay to be attached — call list_pages first. Returns {ok: true, value} on success or {ok: false, error} on failure. If a Runtime.exceptionThrown event was observed within [callStart-50ms, callEnd+200ms], the result also includes `recentException` for crash triage. Returns a clear error if window.__sdkCall is not available — on relay (env 3/4) that means a non-dog-food bundle (redeploy via `ait build && aitcc app deploy`); on local (--target=local, env 1) it means the dev bridge is not installed (start the dev server with `pnpm dev`).\n\nSECURITY: method name, args, and result value are not redacted — never include secrets.\n\nPositive-allowlist kill-switch (#665): blocked when the attached page is on a non-debug host (apps.tossmini.com / env 4). relay-live and the LIVE guard removed.\n\nIMPORTANT — 인자 시그니처 (잘못된 인자로 호출하면 토스 앱 crash 위험):\n setDeviceOrientation: call_sdk(\"setDeviceOrientation\", [{ type: \"landscape\" }]) // NOT \"landscape\"\n setIosSwipeGestureEnabled: call_sdk(\"setIosSwipeGestureEnabled\", [{ isEnabled: false }])\n setSecureScreen: call_sdk(\"setSecureScreen\", [{ enabled: true }])\n setScreenAwakeMode: call_sdk(\"setScreenAwakeMode\", [{ enabled: true }])\n getOperationalEnvironment: call_sdk(\"getOperationalEnvironment\", [])\n getPlatformOS: call_sdk(\"getPlatformOS\", [])\n getDeviceId: call_sdk(\"getDeviceId\", [])\n getLocale: call_sdk(\"getLocale\", [])\n getNetworkStatus: call_sdk(\"getNetworkStatus\", [])\n getSchemeUri: call_sdk(\"getSchemeUri\", [])\n requestReview: call_sdk(\"requestReview\", [])\n closeView: call_sdk(\"closeView\", [])",
395
395
  inputSchema: {
396
396
  type: "object",
397
397
  properties: {
@@ -403,10 +403,6 @@ new Set([
403
403
  type: "array",
404
404
  description: "Arguments to pass to the SDK method (optional, default []).",
405
405
  items: {}
406
- },
407
- confirm: {
408
- type: "boolean",
409
- description: "Required when MCP_ENV=relay-live. Set to `true` to explicitly acknowledge that this SDK call may have side effects on real/live users. Omitting this in a relay-live session results in a structured rejection error. Has no effect in mock or relay-dev sessions."
410
406
  }
411
407
  },
412
408
  required: ["name"]
@@ -445,7 +441,7 @@ new Set([
445
441
  },
446
442
  {
447
443
  name: "start_debug",
448
- description: "Switches the active debug environment in-place (issue #348) — no Claude Code restart and no MCP re-handshake. One daemon holds both a local (env 1, mock SDK in a Chromium) and a relay (env 3/4, real-device Toss WebView over the Chii relay + cloudflared tunnel) connection at once; this tool flips which one every other tool reads from, lazily booting the requested family's infra on first use and keeping the inactive one warm so an existing attach survives the switch. After switching it emits notifications/tools/list_changed — call tools/list again to see the updated tool surface for the new environment.\n\nmodes:\n local-browser — env 1: desktop Chromium with the mock SDK and a local CDP attach. Side-effect tools (call_sdk/evaluate) run unguarded against the mock; nothing touches a real device or real users. No prerequisites — the default, always-available environment for state/contract and visual-layout work.\n relay-sandbox — env 2: a real-device PWA (real WebKit engine, mock SDK) over an external Chii relay. CDP covers real-device WebKit DOM, console, exceptions, and safe-area observation; call_sdk still hits the mock (SDK fidelity needs relay-staging). liveIntent off — dev-intent, LIVE guard inactive, side-effect tools run unguarded against the mock. Only the dual-connection daemon can enter relay-sandbox in-place; a single-connection session rejects it with \"동적 전환할 수 없습니다 … relay-sandbox 모드로 재시작하세요\" — follow that hint and restart the MCP server in relay-sandbox mode rather than retrying. Prerequisites: both AIT_RELAY_BASE_URL (the relay base the unplugin emits when started with tunnel:{cdp:true}, used for the CDP attach) and AIT_TUNNEL_BASE_URL (the dev-server tunnel host, required by build_attach_url to render the launcher QR) must be set before the MCP server starts — the unplugin does not auto-forward either; set them explicitly. Both carry relay/tunnel hosts (secret-class) — keep them out of logs.\n relay-staging — env 3: a real-device Toss WebView dog-food build with the REAL SDK over the intoss-private relay. The first environment where call_sdk exercises the genuine native bridge. Side-effect tools run unguarded (dog-food, not released to real users). Prerequisite: a dog-food candidate bundle built with `RELEASE_CHANNEL=dogfood ait build`, then uploaded with `ait deploy` (add `--scheme-only` to print the resulting intoss-private://…?_deploymentId=… deep-link); open that deep-link/QR on the device to cold-load the bundle with the relay injected. Unlike env 2, env 3 is NOT a dev-server tunnel — it is a deployed bundle reached via the intoss-private scheme, so `pnpm dev` plays no part here.\n relay-live — env 4: the REVIEW-PASSED, released production runtime with the REAL SDK over the intoss relay — real end users are on the other side. Read-only debugging is the intent: the LIVE guard is armed, so call_sdk/evaluate require confirm:true per call, and ENTERING relay-live ALSO requires confirm:true on this call. Use it only to observe a shipped regression; verify fixes in relay-staging first.\n\nSwitching back to local-browser automatically disarms the LIVE guard.\n\nFor a relay mode (relay-sandbox/relay-staging/relay-live), also pass projectRoot — the absolute mini-app project root — so the daemon can read the relay auth secret from <projectRoot>/.ait_relay (read-only; the daemon never mints it). Omit it for local-browser.",
444
+ description: "Switches the active debug environment in-place (issue #348) — no Claude Code restart and no MCP re-handshake. One daemon holds both a local (env 1, mock SDK in a Chromium) and a relay (env 2/3, real-device over the Chii relay + cloudflared tunnel) connection at once; this tool flips which one every other tool reads from, lazily booting the requested family's infra on first use and keeping the inactive one warm so an existing attach survives the switch. After switching it emits notifications/tools/list_changed — call tools/list again to see the updated tool surface for the new environment.\n\nPositive-allowlist kill-switch (#665): relay sessions on apps.tossmini.com (env 4, released production) are silently blocked at both the in-app gate and this MCP layer — relay-live and the LIVE guard have been removed. Only localhost/loopback (env 1), *.trycloudflare.com (env 2), and *.private-apps.tossmini.com (env 3) are allowed.\n\nmodes:\n local-browser — env 1: desktop Chromium with the mock SDK and a local CDP attach. Side-effect tools (call_sdk/evaluate) run unguarded against the mock; nothing touches a real device or real users. No prerequisites — the default, always-available environment for state/contract and visual-layout work.\n relay-sandbox — env 2: a real-device PWA (real WebKit engine, mock SDK) over an external Chii relay. CDP covers real-device WebKit DOM, console, exceptions, and safe-area observation; call_sdk still hits the mock (SDK fidelity needs relay-staging). Side-effect tools run unguarded against the mock. Only the dual-connection daemon can enter relay-sandbox in-place; a single-connection session rejects it with \"동적 전환할 수 없습니다 … relay-sandbox 모드로 재시작하세요\" — follow that hint and restart the MCP server in relay-sandbox mode rather than retrying. Prerequisites: both AIT_RELAY_BASE_URL (the relay base the unplugin emits when started with tunnel:{cdp:true}, used for the CDP attach) and AIT_TUNNEL_BASE_URL (the dev-server tunnel host, required by start_attach to render the launcher QR) must be set before the MCP server starts — the unplugin does not auto-forward either; set them explicitly. Both carry relay/tunnel hosts (secret-class) — keep them out of logs.\n relay-staging — env 3: a real-device Toss WebView dog-food build with the REAL SDK over the intoss-private relay. The first environment where call_sdk exercises the genuine native bridge. Side-effect tools run unguarded (dog-food, not released to real users). Prerequisite: a dog-food candidate bundle built with `RELEASE_CHANNEL=dogfood ait build`, then uploaded with `ait deploy` (add `--scheme-only` to print the resulting intoss-private://…?_deploymentId=… deep-link); open that deep-link/QR on the device to cold-load the bundle with the relay injected. Unlike env 2, env 3 is NOT a dev-server tunnel — it is a deployed bundle reached via the intoss-private scheme, so `pnpm dev` plays no part here.\n\nFor a relay mode (relay-sandbox/relay-staging), also pass projectRoot — the absolute mini-app project root — so the daemon can read the relay auth secret from <projectRoot>/.ait_relay (read-only; the daemon never mints it). Omit it for local-browser.",
449
445
  inputSchema: {
450
446
  type: "object",
451
447
  properties: {
@@ -454,18 +450,13 @@ new Set([
454
450
  enum: [
455
451
  "local-browser",
456
452
  "relay-sandbox",
457
- "relay-staging",
458
- "relay-live"
453
+ "relay-staging"
459
454
  ],
460
- description: "Target environment to switch to. mode=relay-live additionally requires confirm: true (and arms the read-only LIVE guard)."
461
- },
462
- confirm: {
463
- type: "boolean",
464
- description: "Required when mode=relay-live — set true to acknowledge entering LIVE (env 4) debugging that can affect real users. Ignored for the other modes."
455
+ description: "Target environment to switch to. relay-live (env 4) has been removed (#665) use relay-staging (env 3) for dog-food debugging."
465
456
  },
466
457
  projectRoot: {
467
458
  type: "string",
468
- description: "Absolute path to the mini-app project root (the directory containing its package.json and .ait_relay). The daemon reads the relay auth secret from <projectRoot>/.ait_relay (read-only) when switching to a relay environment (relay-staging/relay-live/relay-sandbox). Pass this because the daemon's own cwd is fixed at launch and may not be the project being debugged. Omit for mode=local-browser (no secret needed)."
459
+ description: "Absolute path to the mini-app project root (the directory containing its package.json and .ait_relay). The daemon reads the relay auth secret from <projectRoot>/.ait_relay (read-only) when switching to a relay environment (relay-staging/relay-sandbox). Pass this because the daemon's own cwd is fixed at launch and may not be the project being debugged. Omit for mode=local-browser (no secret needed)."
469
460
  }
470
461
  },
471
462
  required: ["mode"]
@@ -474,7 +465,7 @@ new Set([
474
465
  },
475
466
  {
476
467
  name: "get_debug_status",
477
- description: "Reports the current debug session state — which environment/mode is active, whether a page is attached, and a full diagnostic snapshot — in one call. Use this any time to answer \"what mode am I in right now?\" or \"why is this not working?\" without chaining tools. Fields: mcpVersion (MCP SDK version), devtoolsVersion (@ait-co/devtools package version), tunnel (up/wssUrl/pid/startedAt), pages (list_pages result + lastSeenAt stats), lastAttachAt, lastDetachAt, recentErrors (last N server-side errors, PII/secret redacted), authRejects ({count, lastAt} — relay TOTP 401 rejections, secret-free; count > 0 with empty pages means the phone reached the relay but its code was rejected), environment (kind: mock|relay-dev|relay-live|relay-mobile, env: mock|relay backward-compat, reason, liveGuardActive: true when relay-live LIVE guard is active; start_debug mode→kind mapping: relay-sandbox→relay-mobile, relay-staging→relay-dev, relay-live→relay-live, local-browser→mock), serverLockHolder (pid + startedAt from the lock file, or null), nextRecommendedAction ({tool, reason} or null — the single next tool to call; in local-target mode tunnel.up=false is normal so \"restart\" is never recommended). All fields are nullable — missing data is null, not an error. debug-mode only — dev-mode (--mode=dev) does not support relay diagnostics. Tier C (both mock and relay).",
468
+ description: "Reports the current debug session state — which environment/mode is active, whether a page is attached, and a full diagnostic snapshot — in one call. Use this any time to answer \"what mode am I in right now?\" or \"why is this not working?\" without chaining tools. Fields: mcpVersion (MCP SDK version), devtoolsVersion (@ait-co/devtools package version), tunnel (up/wssUrl/pid/startedAt), pages (list_pages result + lastSeenAt stats), lastAttachAt, lastDetachAt, recentErrors (last N server-side errors, PII/secret redacted), authRejects ({count, lastAt} — relay TOTP 401 rejections, secret-free; count > 0 with empty pages means the phone reached the relay but its code was rejected), environment (kind: mock|relay-dev|relay-mobile, env: mock|relay backward-compat, reason, liveGuardActive: always false relay-live and LIVE guard removed (#665); start_debug mode→kind mapping: relay-sandbox→relay-mobile, relay-staging→relay-dev, local-browser→mock), serverLockHolder (pid + startedAt from the lock file, or null), nextRecommendedAction ({tool, reason} or null — the single next tool to call; in local-target mode tunnel.up=false is normal so \"restart\" is never recommended). All fields are nullable — missing data is null, not an error. debug-mode only — dev-mode (--mode=dev) does not support relay diagnostics. Tier C (both mock and relay).",
478
469
  inputSchema: {
479
470
  type: "object",
480
471
  properties: { recent_errors_limit: {
@@ -487,7 +478,7 @@ new Set([
487
478
  },
488
479
  {
489
480
  name: "run_tests",
490
- description: "Runs mini-app test files on the attached page over CDP (Runtime.evaluate). Each matched file is bundled with esbuild (SDK imports redirected to the live mock/SDK), injected into the attached WebView, and executed; returns per-file results plus flattened totals (passed/failed/skipped/total). Requires an attached page — call list_pages first to confirm one is attached. Files run SEQUENTIALLY (single-attach model: the relay/local target serves one page), and one run_tests call runs at a time (a concurrent call is rejected). Test verification (assert/snapshot) is delegated to the in-page Vitest runtime; this tool is the transport + report. The per-file results array is the progress record — on partial failure you see exactly which files passed/failed/timed-out. In a relay-live session this is a state-mutating injection and is blocked unless confirm=true (ignored in mock/local/relay-dev/relay-mobile). debug-mode only — dev-mode (--mode=dev) has no CDP. Tier C (both mock/local and relay). Use the test-runner CLI (devtools-test) for the same run outside MCP.",
481
+ description: "Runs mini-app test files on the attached page over CDP (Runtime.evaluate). Each matched file is bundled with esbuild (SDK imports redirected to the live mock/SDK), injected into the attached WebView, and executed; returns per-file results plus flattened totals (passed/failed/skipped/total). Requires an attached page — call list_pages first to confirm one is attached. Files run SEQUENTIALLY (single-attach model: the relay/local target serves one page), and one run_tests call runs at a time (a concurrent call is rejected). Test verification (assert/snapshot) is delegated to the in-page Vitest runtime; this tool is the transport + report. The per-file results array is the progress record — on partial failure you see exactly which files passed/failed/timed-out. Positive-allowlist kill-switch (#665): blocked when the attached page is on a non-debug host. debug-mode only — dev-mode (--mode=dev) has no CDP. Tier C (both mock/local and relay). The devtools-test CLI shares this run core and file discovery, but its standalone relay attach is not wired yet — run via this tool for now.",
491
482
  inputSchema: {
492
483
  type: "object",
493
484
  properties: {
@@ -503,10 +494,6 @@ new Set([
503
494
  timeout_ms: {
504
495
  type: "number",
505
496
  description: "Per-file evaluate timeout in ms (default 30000, range 1000–600000). Out-of-range/invalid values fall back to the default."
506
- },
507
- confirm: {
508
- type: "boolean",
509
- description: "Required (true) to run in a relay-live session — test injection mutates page state. Ignored in mock/local/relay-dev/relay-mobile sessions."
510
497
  }
511
498
  },
512
499
  required: ["files"]
@@ -770,25 +757,30 @@ const DEV_TOOL_DEFINITIONS = [
770
757
  availableIn: "both"
771
758
  },
772
759
  {
773
- name: "build_attach_url",
774
- description: "Turns an `ait deploy --scheme-only` URL into a self-attaching deep link for a real device. NOT available in dev-mode — requires a live cloudflared relay (Tier B, relay-only). To use this tool: restart the MCP server with `--mode=debug` (or omit --mode) and set MCP_ENV=relay, then call build_attach_url to generate the QR for phone scanning. See: https://docs.aitc.dev/guides/debug-relay",
760
+ name: "start_attach",
761
+ description: "Switches into a relay mode (if given), builds a self-attaching deep-link QR for a real device, and waits for the phone to attach — all in one call. NOT available in dev-mode — requires a live cloudflared relay (Tier B, relay-only). To use this tool: restart the MCP server with `--mode=debug` (or omit --mode) and set MCP_ENV=relay, then call start_attach to generate the QR for phone scanning. See: https://docs.aitc.dev/guides/debug-relay",
775
762
  inputSchema: {
776
763
  type: "object",
777
764
  properties: {
778
- scheme_url: {
765
+ mode: {
779
766
  type: "string",
780
- description: "The intoss-private:// URL from `ait deploy --scheme-only`."
767
+ enum: [
768
+ "local-browser",
769
+ "relay-sandbox",
770
+ "relay-staging"
771
+ ],
772
+ description: "Optional relay mode to switch into before attaching."
781
773
  },
782
- wait_for_attach: {
783
- type: "boolean",
784
- description: "If true, block until a page attaches (default 60 s)."
774
+ scheme_url: {
775
+ type: "string",
776
+ description: "The intoss-private:// URL from `ait deploy --scheme-only` (env 3/relay-staging)."
785
777
  },
786
778
  wait_timeout_seconds: {
787
779
  type: "number",
788
- description: "Maximum seconds to wait when wait_for_attach=true (default 60, range 1–600). Invalid inputs fall back to default."
780
+ description: "Maximum seconds to wait for a page to attach (default 60, range 1–600). Invalid inputs fall back to default."
789
781
  }
790
782
  },
791
- required: ["scheme_url"]
783
+ required: []
792
784
  },
793
785
  availableIn: "relay"
794
786
  },
@@ -886,10 +878,6 @@ const DEV_TOOL_DEFINITIONS = [
886
878
  timeout_ms: {
887
879
  type: "number",
888
880
  description: "Per-file evaluate timeout in ms."
889
- },
890
- confirm: {
891
- type: "boolean",
892
- description: "Required in relay-live sessions."
893
881
  }
894
882
  },
895
883
  required: ["files"]
@@ -915,7 +903,7 @@ const CDP_ONLY_TOOL_NAMES = new Set([
915
903
  * Listed in dev-mode tool surface (issue #323) so agents get a hand-off hint
916
904
  * toward `--mode=debug` instead of "Unknown tool".
917
905
  */
918
- const TIER_B_TOOL_NAMES = new Set(["build_attach_url"]);
906
+ const TIER_B_TOOL_NAMES = new Set(["start_attach"]);
919
907
  /**
920
908
  * Builds the `list_pages` dev-mode shim response.
921
909
  * Returns the Vite dev URL as a single-entry page list with `devMode: true`.
@@ -1025,7 +1013,7 @@ function createDevServer(deps = {}) {
1025
1013
  const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
1026
1014
  const server = new Server({
1027
1015
  name: "ait-devtools",
1028
- version: "0.1.108"
1016
+ version: "0.1.110"
1029
1017
  }, { capabilities: { tools: {} } });
1030
1018
  server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
1031
1019
  server.setRequestHandler(CallToolRequestSchema, async (request) => {