@ait-co/devtools 0.1.84 → 0.1.85

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/README.en.md CHANGED
@@ -106,7 +106,7 @@ For environments 3 and 4 (intoss-private relay), the relay QR deep-link carries
106
106
 
107
107
  **"QR window doesn't open"**
108
108
 
109
- Either `build_attach_url` wasn't called first, or `open_in_browser` failed silently in a headless environment. The terminal output includes a path to a saved PNG open that file directly, or scan the text QR printed in the terminal. (Related: [#288](https://github.com/apps-in-toss-community/devtools/issues/288))
109
+ Either `build_attach_url` wasn't called first, or the MCP server is running in a headless environment where no browser can be opened. The tool result always includes a text QR scan it directly with your phone camera. On a local GUI machine, the dashboard opens automatically in the browser.
110
110
 
111
111
  **"Page not attached" — list_pages returns an empty array**
112
112
 
package/README.md CHANGED
@@ -106,7 +106,7 @@ import '@ait-co/devtools/in-app/auto';
106
106
 
107
107
  **"QR 창이 안 열림"**
108
108
 
109
- `build_attach_url`을 먼저 호출하지 않았거나, GUI 없는 headless 환경에서 `open_in_browser`가 실패한 경우입니다. 터미널에 PNG 저장 경로가 출력됩니다 파일을 직접 열거나, 텍스트 QR을 터미널에서 스캔하세요. (관련: [#288](https://github.com/apps-in-toss-community/devtools/issues/288))
109
+ `build_attach_url`을 먼저 호출하지 않았거나, GUI 없는 headless 환경이라 대시보드를 수 없는 경우입니다. 도구 결과에 텍스트 QR이 출력되므로 카메라로 직접 스캔하세요. 로컬 GUI 환경에서는 대시보드가 자동으로 브라우저에 열립니다.
110
110
 
111
111
  **"page 미attach" — list_pages가 빈 배열 반환**
112
112
 
package/dist/mcp/cli.js CHANGED
@@ -3761,7 +3761,7 @@ const DEBUG_TOOL_DEFINITIONS = [
3761
3761
  },
3762
3762
  {
3763
3763
  name: "build_attach_url",
3764
- 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 (polls up to 30 s). On timeout, call build_attach_url again to resume polling. When open_in_browser=true (default), saves the QR as a PNG and opens it in the OS default browser — only works when the MCP server runs on a local GUI machine (not headless/remote containers). \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.",
3764
+ 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 (polls up to 30 s). 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.",
3765
3765
  inputSchema: {
3766
3766
  type: "object",
3767
3767
  properties: {
@@ -3773,10 +3773,6 @@ const DEBUG_TOOL_DEFINITIONS = [
3773
3773
  type: "boolean",
3774
3774
  description: "If true, block after returning the QR until a page attaches to the relay (polls listTargets ~1 s interval, timeout 30 s). On attach, the response includes the attached page list. On timeout, call build_attach_url again to resume polling."
3775
3775
  },
3776
- open_in_browser: {
3777
- type: "boolean",
3778
- description: "If true (default), render the QR as a PNG and open it in the OS default browser. Only works when the MCP server is running on a local GUI machine — headless or remote container environments should set this to false to use the text QR fallback."
3779
- },
3780
3776
  projectRoot: {
3781
3777
  type: "string",
3782
3778
  description: "Absolute path to the mini-app project root (the directory containing its package.json and .ait_urls). When AIT_TUNNEL_BASE_URL is unset (env 2 / relay-mobile only), the daemon reads the app tunnel URL from <projectRoot>/.ait_urls written by the dev server (tunnel:{cdp:true}). Pass this because the daemon's own cwd is fixed at launch. Omit when AIT_TUNNEL_BASE_URL is set explicitly."
@@ -4779,7 +4775,7 @@ async function readMcpSdkVersion() {
4779
4775
  * some test environments that skip the build step).
4780
4776
  */
4781
4777
  function readDevtoolsVersion() {
4782
- return "0.1.84";
4778
+ return "0.1.85";
4783
4779
  }
4784
4780
  /**
4785
4781
  * Derives the next recommended action from a completed diagnostics snapshot.
@@ -5283,7 +5279,7 @@ function createDebugServer(deps) {
5283
5279
  const collector = collectorDep ?? new InMemoryDiagnosticsCollector();
5284
5280
  const server = new Server({
5285
5281
  name: "ait-debug",
5286
- version: "0.1.84"
5282
+ version: "0.1.85"
5287
5283
  }, { capabilities: { tools: { listChanged: true } } });
5288
5284
  server.setRequestHandler(ListToolsRequestSchema, () => {
5289
5285
  const conn = router.active;
@@ -5356,7 +5352,6 @@ function createDebugServer(deps) {
5356
5352
  }
5357
5353
  if (name === "build_attach_url") {
5358
5354
  const waitForAttach = request.params.arguments?.wait_for_attach === true;
5359
- const openInBrowser = request.params.arguments?.open_in_browser !== false;
5360
5355
  const selfdebug = request.params.arguments?.selfdebug === true;
5361
5356
  if (selfdebug && env !== "relay-mobile") return mcpError("build_attach_url: selfdebug=true는 env 2 / relay-sandbox 전용 기능입니다. 현재 환경(env 3/4)에서는 launcher가 없어 self-target 모드를 지원하지 않습니다. launcher self-target이 필요하다면 relay-sandbox 모드로 재시작하세요.");
5362
5357
  if (env === "relay-mobile") {
@@ -5414,8 +5409,8 @@ function createDebugServer(deps) {
5414
5409
  const header = "This tool result is shown to the user directly — do NOT re-print the QR below in your reply (it wastes output tokens). Just tell the user to scan the QR in this output (Ctrl+O to expand if collapsed).";
5415
5410
  const warningPrefix = "";
5416
5411
  const guiAvailable = canOpenBrowser();
5417
- if (openInBrowser && !guiAvailable) {
5418
- const headlessNote = "[open_in_browser] GUI 환경이 감지되지 않았습니다 (headless/remote 환경). open_in_browser=false로 자동 폴백합니다. 텍스트 QR을 폰 카메라로 스캔하거나, 로컬 GUI 환경에서 실행하세요.\n\n";
5412
+ if (!guiAvailable) {
5413
+ const headlessNote = "GUI 환경이 감지되지 않았습니다 (headless/remote 환경). 텍스트 QR을 폰 카메라로 스캔하거나, 로컬 GUI 환경에서 실행하세요.\n\n";
5419
5414
  const qrHeadless = await renderQr(attachUrl);
5420
5415
  const headlessText = `${warningPrefix}${headlessNote}${header}\n${JSON.stringify({
5421
5416
  attachUrl,
@@ -5445,7 +5440,7 @@ function createDebugServer(deps) {
5445
5440
  text: `${headlessText}\n\n${JSON.stringify(pagesResultHl, null, 2)}`
5446
5441
  }] };
5447
5442
  }
5448
- if (openInBrowser && guiAvailable && qrHttpServer) {
5443
+ if (guiAvailable && qrHttpServer) {
5449
5444
  const browserResult = await openQrInBrowser(qrHttpServer.buildAttachPageUrl(attachUrl), `http://127.0.0.1:${qrHttpServer.port}/qr.png?u=${encodeURIComponent(attachUrl)}`);
5450
5445
  if (browserResult.opened) {
5451
5446
  const retriedNote = browserResult.retried ? " (1회 retry 후 성공)" : "";
@@ -5490,7 +5485,7 @@ function createDebugServer(deps) {
5490
5485
  ...browserResult.stderrSummary ? { stderrSummary: browserResult.stderrSummary } : {}
5491
5486
  };
5492
5487
  const stderrNote = browserResult.stderrSummary ? `\nstderr: ${browserResult.stderrSummary}` : "";
5493
- const fallbackNote = `[open_in_browser] 브라우저 자동 열기에 실패했습니다. 다음 URL을 직접 브라우저에서 여세요:\n${browserResult.httpUrl}\n또는 PNG로 받기: ${browserResult.pngUrl}` + stderrNote + "\n\n";
5488
+ const fallbackNote = `브라우저 자동 열기에 실패했습니다. 다음 URL을 직접 브라우저에서 여세요:\n${browserResult.httpUrl}\n또는 PNG로 받기: ${browserResult.pngUrl}` + stderrNote + "\n\n";
5494
5489
  const qr = await renderQr(attachUrl);
5495
5490
  const baseText = `${warningPrefix}${fallbackNote}${header}\n${JSON.stringify({
5496
5491
  attachUrl,
@@ -5585,8 +5580,8 @@ function createDebugServer(deps) {
5585
5580
  const warningPrefix = authorityWarning ? `⚠️ scheme_url 경고: ${authorityWarning}\n\n` : "";
5586
5581
  const header = "This tool result is shown to the user directly — do NOT re-print the QR below in your reply (it wastes output tokens). Just tell the user to scan the QR in this output (Ctrl+O to expand if collapsed).";
5587
5582
  const guiAvailable = canOpenBrowser();
5588
- if (openInBrowser && !guiAvailable) {
5589
- const headlessNote = "[open_in_browser] GUI 환경이 감지되지 않았습니다 (headless/remote 환경). open_in_browser=false로 자동 폴백합니다. 텍스트 QR을 폰 카메라로 스캔하거나, 로컬 GUI 환경에서 실행하세요.\n\n";
5583
+ if (!guiAvailable) {
5584
+ const headlessNote = "GUI 환경이 감지되지 않았습니다 (headless/remote 환경). 텍스트 QR을 폰 카메라로 스캔하거나, 로컬 GUI 환경에서 실행하세요.\n\n";
5590
5585
  const qrHeadless = await renderQr(attachUrl);
5591
5586
  const headlessText = `${warningPrefix}${headlessNote}${header}\n${JSON.stringify({
5592
5587
  attachUrl,
@@ -5616,7 +5611,7 @@ function createDebugServer(deps) {
5616
5611
  text: `${headlessText}\n\n${JSON.stringify(pagesResultHl, null, 2)}`
5617
5612
  }] };
5618
5613
  }
5619
- if (openInBrowser && guiAvailable && qrHttpServer) {
5614
+ if (guiAvailable && qrHttpServer) {
5620
5615
  const browserResult = await openQrInBrowser(qrHttpServer.buildAttachPageUrl(attachUrl), `http://127.0.0.1:${qrHttpServer.port}/qr.png?u=${encodeURIComponent(attachUrl)}`);
5621
5616
  if (browserResult.opened) {
5622
5617
  const retriedNote = browserResult.retried ? " (1회 retry 후 성공)" : "";
@@ -5661,7 +5656,7 @@ function createDebugServer(deps) {
5661
5656
  ...browserResult.stderrSummary ? { stderrSummary: browserResult.stderrSummary } : {}
5662
5657
  };
5663
5658
  const stderrNote = browserResult.stderrSummary ? `\nstderr: ${browserResult.stderrSummary}` : "";
5664
- const fallbackNote = `[open_in_browser] 브라우저 자동 열기에 실패했습니다. 다음 URL을 직접 브라우저에서 여세요:
5659
+ const fallbackNote = `브라우저 자동 열기에 실패했습니다. 다음 URL을 직접 브라우저에서 여세요:
5665
5660
  ${browserResult.httpUrl}\n또는 PNG로 받기: ${browserResult.pngUrl}` + stderrNote + "\n\n";
5666
5661
  const qr = await renderQr(attachUrl);
5667
5662
  const baseText = `${warningPrefix}${fallbackNote}${header}\n${JSON.stringify({
@@ -7117,10 +7112,6 @@ const DEV_TOOL_DEFINITIONS = [
7117
7112
  wait_for_attach: {
7118
7113
  type: "boolean",
7119
7114
  description: "If true, block until a page attaches."
7120
- },
7121
- open_in_browser: {
7122
- type: "boolean",
7123
- description: "If true (default), open the QR PNG in the OS browser."
7124
7115
  }
7125
7116
  },
7126
7117
  required: ["scheme_url"]
@@ -7331,7 +7322,7 @@ function createDevServer(deps = {}) {
7331
7322
  const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
7332
7323
  const server = new Server({
7333
7324
  name: "ait-devtools",
7334
- version: "0.1.84"
7325
+ version: "0.1.85"
7335
7326
  }, { capabilities: { tools: {} } });
7336
7327
  server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
7337
7328
  server.setRequestHandler(CallToolRequestSchema, async (request) => {