@ada-mcp/mcp-server 0.1.7 → 0.1.8

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 (3) hide show
  1. package/README.md +6 -6
  2. package/dist/cli.cjs +154 -48
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,25 +8,25 @@ ADA MCP server package that supports:
8
8
 
9
9
  ## 标准安装(Cursor / MCP)
10
10
 
11
- 请使用 **`@ada-mcp/launcher@0.1.2`** 拉起本包(见 [launcher README](../ada-mcp-launcher/README.md)):
11
+ 请使用 **`@ada-mcp/launcher@0.1.3`** 拉起本包(见 [launcher README](../ada-mcp-launcher/README.md)):
12
12
 
13
13
  ```json
14
14
  {
15
15
  "mcpServers": {
16
16
  "ada-mcp": {
17
17
  "command": "pnpm",
18
- "args": ["dlx", "@ada-mcp/launcher@0.1.2"]
18
+ "args": ["dlx", "@ada-mcp/launcher@0.1.3"]
19
19
  }
20
20
  }
21
21
  }
22
22
  ```
23
23
 
24
- 本包版本:**`@ada-mcp/mcp-server@0.1.6`**(由 launcher 默认拉取)。
24
+ 本包版本:**`@ada-mcp/mcp-server@0.1.7`**(由 launcher 默认拉取)。
25
25
 
26
26
  直接调试本包(无 launcher 拉包前测速):
27
27
 
28
28
  ```bash
29
- pnpm dlx @ada-mcp/mcp-server@0.1.6
29
+ pnpm dlx @ada-mcp/mcp-server@0.1.7
30
30
  ```
31
31
 
32
32
  ## 启动时自动安装依赖(默认仅 Playwright)
@@ -81,12 +81,12 @@ pnpm dlx @ada-mcp/mcp-server@0.1.6
81
81
  在标准 `args` 后追加,例如安装全部依赖:
82
82
 
83
83
  ```json
84
- "args": ["dlx", "@ada-mcp/launcher@0.1.2", "--install-deps=all"]
84
+ "args": ["dlx", "@ada-mcp/launcher@0.1.3", "--install-deps=all"]
85
85
  ```
86
86
 
87
87
  ## Cursor MCP 配置
88
88
 
89
- 与上文**标准配置**相同:`pnpm` + `dlx @ada-mcp/launcher@0.1.2`。
89
+ 与上文**标准配置**相同:`pnpm` + `dlx @ada-mcp/launcher@0.1.3`。
90
90
 
91
91
  Windows 若找不到 `pnpm`,可写完整路径,例如 `C:\\Users\\<你>\\AppData\\Roaming\\npm\\pnpm.cmd`,或改用 npx:
92
92
 
package/dist/cli.cjs CHANGED
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/bootstrap-deps.ts
27
- var import_node_fs2 = __toESM(require("node:fs"));
27
+ var import_node_fs3 = __toESM(require("node:fs"));
28
28
  var import_node_path10 = __toESM(require("node:path"));
29
29
 
30
30
  // ../ada-agent/dist/config.js
@@ -2720,7 +2720,7 @@ function createJsonLogger(source) {
2720
2720
  }
2721
2721
 
2722
2722
  // ../ada-agent/dist/bundled-config.generated.js
2723
- var bundledDefaultConfigYaml = 'agent:\r\n id: "ada-agent-local"\r\n mode: "foreground"\r\n setupOnFirstRun: true\r\n\r\nbootstrapUI:\r\n enabled: true\r\n mode: "auto" # auto | cli | gui\r\n host: "127.0.0.1"\r\n port: 17650\r\n autoOpenBrowser: true\r\n sessionTtlSec: 600\r\n secretsProvider: "auto" # auto | keychain | credman | file\r\n native:\r\n enabled: false\r\n command: "" # e.g. ./bootstrap-ui / .\\bootstrap-ui.exe\r\n args: []\r\n timeoutMs: 120000\r\n fallbackToWeb: true\r\n\r\ntransport:\r\n mode: "auto"\r\n streamProtocol: "websocket"\r\n requestPath: "/api/v1/execute"\r\n healthPath: "/health"\r\n streamPath: "/ws"\r\n requestTimeoutMs: 15000\r\n\r\ngraphics:\r\n enabled: false\r\n fallbackOnSemanticFailure: false\r\n minConfidence: 0.8\r\n\r\nmonitoring:\r\n enabled: false\r\n platforms: ["web", "android", "ios", "harmony"] # \u53EF\u9009\u5B50\u96C6\r\n sampleEvery: 1 # \u6BCF N \u6761\u64CD\u4F5C\u91C7\u6837\u4E00\u6B21\uFF0C1 \u8868\u793A\u5168\u91CF\r\n outputDir: "artifacts/monitoring"\r\n onFailureOnly: false # true \u65F6\u4EC5\u5931\u8D25\u64CD\u4F5C\u6293\u56FE\uFF0C\u6027\u80FD\u66F4\u4F18\r\n groupBySession: true # \u6309 sessionId/requestId \u5206\u5C42\u5F52\u6863\r\n nonBlocking: true # true \u65F6\u76D1\u63A7\u5F02\u6B65\u6267\u884C\uFF0C\u4E0D\u963B\u585E\u4E3B\u94FE\u8DEF\r\n resolution:\r\n maxWidth: 1280\r\n maxHeight: 720\r\n keepAspectRatio: true # \u4FDD\u6301\u6BD4\u4F8B\uFF0C\u907F\u514D\u76D1\u63A7\u56FE\u50CF\u53D8\u5F62\r\n\r\nqueue:\r\n inboxDir: "tasks/inbox"\r\n processedDir: "tasks/processed"\r\n failedDir: "tasks/failed"\r\n pollIntervalMs: 3000\r\n maxFileRetryAttempts: 2\r\n\r\ndependencies:\r\n autoInstallOnStart: true\r\n playwrightBrowser: "chromium" # chromium | firefox | webkit | all\r\n playwrightInstallTargets: ["chrome"] # chromium | chrome | msedge | firefox | webkit | all\r\n playwrightDownloadHost: "https://npmmirror.com/mirrors/playwright"\r\n npmRegistryCandidates:\r\n - "https://registry.npmmirror.com"\r\n - "https://mirrors.cloud.tencent.com/npm"\r\n - "https://repo.huaweicloud.com/repository/npm"\r\n - "https://registry.npmjs.org"\r\n playwrightHostCandidates:\r\n - "https://npmmirror.com/mirrors/playwright"\r\n - "https://playwright.azureedge.net"\r\n # \u539F\u751F WebDriver\uFF08geckodriver / chromedriver\uFF09\u7EDF\u4E00\u653E\u5728\u9879\u76EE dirver \u76EE\u5F55\r\n nativeDriversDir: "dirver"\r\n geckodriverVersion: "latest" # \u5982 0.36.0\uFF1Binstall-deps --only=selenium \u65F6\u4E0B\u8F7D\u5230\u6B64\u76EE\u5F55\r\n chromedriverVersion: "latest" # \u5982 137\u3001135\u3001match-chrome\uFF08\u5339\u914D\u672C\u673A Chrome \u4E3B\u7248\u672C\uFF09\r\n\r\nappium:\r\n serverUrl: "http://127.0.0.1:4723"\r\n requiredDrivers: ["uiautomator2", "xcuitest", "harmonyos"]\r\n';
2723
+ var bundledDefaultConfigYaml = 'agent:\r\n id: "ada-agent-local"\r\n mode: "foreground"\r\n setupOnFirstRun: true\r\n\r\nbootstrapUI:\r\n enabled: true\r\n mode: "auto" # auto | cli | gui\r\n host: "127.0.0.1"\r\n port: 17650\r\n autoOpenBrowser: true\r\n sessionTtlSec: 600\r\n secretsProvider: "auto" # auto | keychain | credman | file\r\n native:\r\n enabled: false\r\n command: "" # e.g. ./bootstrap-ui / .\\bootstrap-ui.exe\r\n args: []\r\n timeoutMs: 120000\r\n fallbackToWeb: true\r\n\r\ntransport:\r\n mode: "auto"\r\n streamProtocol: "websocket"\r\n requestPath: "/api/v1/execute"\r\n healthPath: "/health"\r\n streamPath: "/ws"\r\n requestTimeoutMs: 15000\r\n\r\ngraphics:\r\n enabled: false\r\n fallbackOnSemanticFailure: false\r\n minConfidence: 0.8\r\n\r\nmonitoring:\r\n enabled: false\r\n platforms: ["web", "android", "ios", "harmony"] # \u53EF\u9009\u5B50\u96C6\r\n sampleEvery: 1 # \u6BCF N \u6761\u64CD\u4F5C\u91C7\u6837\u4E00\u6B21\uFF0C1 \u8868\u793A\u5168\u91CF\r\n outputDir: "artifacts/monitoring"\r\n onFailureOnly: false # true \u65F6\u4EC5\u5931\u8D25\u64CD\u4F5C\u6293\u56FE\uFF0C\u6027\u80FD\u66F4\u4F18\r\n groupBySession: true # \u6309 sessionId/requestId \u5206\u5C42\u5F52\u6863\r\n nonBlocking: true # true \u65F6\u76D1\u63A7\u5F02\u6B65\u6267\u884C\uFF0C\u4E0D\u963B\u585E\u4E3B\u94FE\u8DEF\r\n resolution:\r\n maxWidth: 1280\r\n maxHeight: 720\r\n keepAspectRatio: true # \u4FDD\u6301\u6BD4\u4F8B\uFF0C\u907F\u514D\u76D1\u63A7\u56FE\u50CF\u53D8\u5F62\r\n\r\nqueue:\r\n inboxDir: "tasks/inbox"\r\n processedDir: "tasks/processed"\r\n failedDir: "tasks/failed"\r\n pollIntervalMs: 3000\r\n maxFileRetryAttempts: 2\r\n\r\ndependencies:\r\n autoInstallOnStart: true\r\n playwrightBrowser: "chromium" # chromium | firefox | webkit | all\r\n playwrightInstallTargets: ["chromium"] # chromium | chrome | msedge | firefox | webkit | all\r\n playwrightDownloadHost: "https://cdn.playwright.dev"\r\n # \u56FD\u5185 npm \u955C\u50CF\uFF08\u6309\u4F18\u5148\u7EA7\uFF1Binstall-deps \u542F\u52A8\u65F6\u6D4B\u901F\u9009\u6700\u5FEB\uFF0C\u65E0\u9700\u7528\u6237\u914D\u7F6E\uFF09\r\n npmRegistryCandidates:\r\n - "https://registry.npmmirror.com" # \u963F\u91CC\u4E91 / npmmirror\uFF08\u63A8\u8350\uFF09\r\n - "https://mirrors.cloud.tencent.com/npm" # \u817E\u8BAF\u4E91\r\n - "https://repo.huaweicloud.com/repository/npm" # \u534E\u4E3A\u4E91\r\n - "https://registry.npmjs.org" # \u5B98\u65B9\u515C\u5E95\r\n playwrightHostCandidates:\r\n - "https://cdn.playwright.dev"\r\n - "https://playwright.azureedge.net"\r\n - "https://npmmirror.com/mirrors/playwright"\r\n - "https://cdn.npmmirror.com/binaries/playwright"\r\n # \u539F\u751F WebDriver\uFF08geckodriver / chromedriver\uFF09\u7EDF\u4E00\u653E\u5728\u9879\u76EE dirver \u76EE\u5F55\r\n nativeDriversDir: "dirver"\r\n geckodriverVersion: "latest" # \u5982 0.36.0\uFF1Binstall-deps --only=selenium \u65F6\u4E0B\u8F7D\u5230\u6B64\u76EE\u5F55\r\n chromedriverVersion: "latest" # \u5982 137\u3001135\u3001match-chrome\uFF08\u5339\u914D\u672C\u673A Chrome \u4E3B\u7248\u672C\uFF09\r\n\r\nappium:\r\n serverUrl: "http://127.0.0.1:4723"\r\n requiredDrivers: ["uiautomator2", "xcuitest", "harmonyos"]\r\n';
2724
2724
 
2725
2725
  // ../ada-agent/dist/config.js
2726
2726
  var DEFAULT_CONFIG_RELATIVE = import_node_path2.default.join("config", "default.yaml");
@@ -2785,8 +2785,8 @@ var defaultConfig = {
2785
2785
  dependencies: {
2786
2786
  autoInstallOnStart: true,
2787
2787
  playwrightBrowser: "chromium",
2788
- playwrightInstallTargets: ["chrome"],
2789
- playwrightDownloadHost: "https://npmmirror.com/mirrors/playwright",
2788
+ playwrightInstallTargets: ["chromium"],
2789
+ playwrightDownloadHost: "https://cdn.playwright.dev",
2790
2790
  npmRegistryCandidates: [
2791
2791
  "https://registry.npmmirror.com",
2792
2792
  "https://mirrors.cloud.tencent.com/npm",
@@ -2794,8 +2794,10 @@ var defaultConfig = {
2794
2794
  "https://registry.npmjs.org"
2795
2795
  ],
2796
2796
  playwrightHostCandidates: [
2797
+ "https://cdn.playwright.dev",
2798
+ "https://playwright.azureedge.net",
2797
2799
  "https://npmmirror.com/mirrors/playwright",
2798
- "https://playwright.azureedge.net"
2800
+ "https://cdn.npmmirror.com/binaries/playwright"
2799
2801
  ],
2800
2802
  nativeDriversDir: "dirver",
2801
2803
  geckodriverVersion: "latest",
@@ -2906,6 +2908,7 @@ async function loadSecret(provider, cwd = process.cwd()) {
2906
2908
 
2907
2909
  // ../ada-agent/dist/dependency-installer.js
2908
2910
  var import_node_module = require("node:module");
2911
+ var import_node_fs = require("node:fs");
2909
2912
  var import_node_child_process2 = require("node:child_process");
2910
2913
  var import_promises5 = __toESM(require("node:fs/promises"), 1);
2911
2914
  var import_node_path5 = __toESM(require("node:path"), 1);
@@ -3544,19 +3547,51 @@ function playwrightInstallTargets(config) {
3544
3547
  const legacy = browserArg(config);
3545
3548
  return legacy ? [legacy] : [];
3546
3549
  }
3550
+ function expandPlaywrightInstallTargets(targets) {
3551
+ if (targets.length === 0) {
3552
+ return targets;
3553
+ }
3554
+ const lower = targets.map((x) => x.toLowerCase());
3555
+ if (lower.includes("chromium") || lower.includes("firefox") || lower.includes("webkit")) {
3556
+ return lower;
3557
+ }
3558
+ const channelOnly = lower.every((x) => x === "chrome" || x === "msedge");
3559
+ if (channelOnly) {
3560
+ return ["chromium", ...lower];
3561
+ }
3562
+ return lower;
3563
+ }
3564
+ function resolveBundledPlaywrightCli() {
3565
+ const pkgPath = require2.resolve("playwright/package.json");
3566
+ const root = import_node_path5.default.dirname(pkgPath);
3567
+ const raw = (0, import_node_fs.readFileSync)(pkgPath, "utf8");
3568
+ const version = String(JSON.parse(raw).version ?? "");
3569
+ return { command: "node", cliArgs: [import_node_path5.default.join(root, "cli.js")], version };
3570
+ }
3547
3571
  function requiredAppiumDrivers(config) {
3548
3572
  return Array.from(new Set(config.appium.requiredDrivers ?? []));
3549
3573
  }
3574
+ var DEFAULT_NPM_REGISTRY_CANDIDATES = [
3575
+ "https://registry.npmmirror.com",
3576
+ "https://mirrors.cloud.tencent.com/npm",
3577
+ "https://repo.huaweicloud.com/repository/npm",
3578
+ "https://registry.npmjs.org"
3579
+ ];
3550
3580
  function npmProxyRegistry() {
3551
- return process.env.ADA_NPM_PROXY_REGISTRY ?? "https://registry.npmmirror.com";
3581
+ return process.env.ADA_NPM_PROXY_REGISTRY ?? DEFAULT_NPM_REGISTRY_CANDIDATES[0];
3552
3582
  }
3553
3583
  function pnpmProxyRegistry() {
3554
3584
  return process.env.ADA_PNPM_PROXY_REGISTRY ?? npmProxyRegistry();
3555
3585
  }
3586
+ function parsePositiveMs(raw, fallback) {
3587
+ const parsed = raw ? Number(raw) : fallback;
3588
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
3589
+ }
3556
3590
  function installStrategyTimeoutMs() {
3557
- const raw = process.env.ADA_INSTALL_STRATEGY_TIMEOUT_MS;
3558
- const parsed = raw ? Number(raw) : 2e4;
3559
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 2e4;
3591
+ return parsePositiveMs(process.env.ADA_INSTALL_STRATEGY_TIMEOUT_MS, 12e4);
3592
+ }
3593
+ function playwrightInstallTimeoutMs() {
3594
+ return parsePositiveMs(process.env.ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS, 9e5);
3560
3595
  }
3561
3596
  function majorOf(versionLike) {
3562
3597
  const text = versionLike.trim().replace(/^v/i, "");
@@ -3679,10 +3714,23 @@ function normalizeRegistryUrl(url) {
3679
3714
  }
3680
3715
  function registryCandidates(config, baseProxy) {
3681
3716
  const primary = normalizeRegistryUrl(baseProxy);
3682
- const configured = Array.isArray(config.dependencies.npmRegistryCandidates) ? config.dependencies.npmRegistryCandidates.map((x) => normalizeRegistryUrl(String(x).trim())).filter(Boolean) : [];
3683
- const fallback = "https://registry.npmjs.org";
3717
+ const fromConfig = Array.isArray(config.dependencies.npmRegistryCandidates) ? config.dependencies.npmRegistryCandidates.map((x) => normalizeRegistryUrl(String(x).trim())).filter(Boolean) : [];
3718
+ const configured = fromConfig.length > 0 ? fromConfig : [...DEFAULT_NPM_REGISTRY_CANDIDATES];
3684
3719
  const extra = process.env.ADA_REGISTRY_CANDIDATES ? process.env.ADA_REGISTRY_CANDIDATES.split(",").map((x) => normalizeRegistryUrl(x.trim())).filter(Boolean) : [];
3685
- return Array.from(/* @__PURE__ */ new Set([primary, ...configured, ...extra, fallback]));
3720
+ const ordered = [primary, ...configured, ...extra];
3721
+ const seen = /* @__PURE__ */ new Set();
3722
+ const out = [];
3723
+ for (const url of ordered) {
3724
+ if (!seen.has(url)) {
3725
+ seen.add(url);
3726
+ out.push(url);
3727
+ }
3728
+ }
3729
+ return out;
3730
+ }
3731
+ function registryPriorityIndex(candidates, registry) {
3732
+ const idx = candidates.indexOf(normalizeRegistryUrl(registry));
3733
+ return idx >= 0 ? idx : Number.POSITIVE_INFINITY;
3686
3734
  }
3687
3735
  async function probeRegistryLatency(registry) {
3688
3736
  const target = `${normalizeRegistryUrl(registry)}/appium`;
@@ -3718,14 +3766,17 @@ async function detectBestRegistry(config, baseProxy) {
3718
3766
  progress("registry.probe.result", { candidate, latencyMs: latency });
3719
3767
  return { candidate, latency };
3720
3768
  }));
3721
- let best = normalizeRegistryUrl(baseProxy);
3769
+ let best = candidates[0] ?? normalizeRegistryUrl(baseProxy);
3722
3770
  let bestLatency = Number.POSITIVE_INFINITY;
3771
+ let bestPriority = Number.POSITIVE_INFINITY;
3723
3772
  for (const { candidate, latency } of probeResults) {
3724
3773
  if (latency === null)
3725
3774
  continue;
3726
- if (latency < bestLatency) {
3775
+ const priority = registryPriorityIndex(candidates, candidate);
3776
+ if (latency < bestLatency || latency === bestLatency && priority < bestPriority) {
3727
3777
  best = candidate;
3728
3778
  bestLatency = latency;
3779
+ bestPriority = priority;
3729
3780
  }
3730
3781
  }
3731
3782
  detectedBestRegistryByKey.set(cacheKey, best);
@@ -3744,19 +3795,46 @@ function playwrightDownloadHost(config) {
3744
3795
  function normalizeHostUrl(url) {
3745
3796
  return url.replace(/\/$/, "");
3746
3797
  }
3798
+ var DEFAULT_PLAYWRIGHT_HOST_CANDIDATES = [
3799
+ "https://cdn.playwright.dev",
3800
+ "https://playwright.azureedge.net",
3801
+ "https://npmmirror.com/mirrors/playwright",
3802
+ "https://cdn.npmmirror.com/binaries/playwright"
3803
+ ];
3804
+ var PLAYWRIGHT_HOST_FALLBACK = DEFAULT_PLAYWRIGHT_HOST_CANDIDATES[0];
3805
+ function playwrightProbeUrls(host) {
3806
+ const h = normalizeHostUrl(host);
3807
+ if (h.includes("npmmirror.com/mirrors/playwright")) {
3808
+ return [h, "https://cdn.npmmirror.com/binaries/playwright"];
3809
+ }
3810
+ return [h];
3811
+ }
3747
3812
  function playwrightHostCandidates(config) {
3748
3813
  const configured = normalizeHostUrl(playwrightDownloadHost(config));
3749
- const configuredCandidates = Array.isArray(config.dependencies.playwrightHostCandidates) ? config.dependencies.playwrightHostCandidates.map((x) => normalizeHostUrl(String(x).trim())).filter(Boolean) : [];
3750
- const fallback = "https://playwright.azureedge.net";
3814
+ const fromConfig = Array.isArray(config.dependencies.playwrightHostCandidates) ? config.dependencies.playwrightHostCandidates.map((x) => normalizeHostUrl(String(x).trim())).filter(Boolean) : [];
3815
+ const configuredList = fromConfig.length > 0 ? fromConfig : [...DEFAULT_PLAYWRIGHT_HOST_CANDIDATES];
3751
3816
  const extra = process.env.ADA_PLAYWRIGHT_HOST_CANDIDATES ? process.env.ADA_PLAYWRIGHT_HOST_CANDIDATES.split(",").map((x) => normalizeHostUrl(x.trim())).filter(Boolean) : [];
3752
- return Array.from(/* @__PURE__ */ new Set([configured, ...configuredCandidates, ...extra, fallback]));
3817
+ const ordered = [configured, ...configuredList, ...extra];
3818
+ const seen = /* @__PURE__ */ new Set();
3819
+ const out = [];
3820
+ for (const url of ordered) {
3821
+ if (!seen.has(url)) {
3822
+ seen.add(url);
3823
+ out.push(url);
3824
+ }
3825
+ }
3826
+ return out;
3753
3827
  }
3754
- async function probeHostLatency(host) {
3828
+ function playwrightHostPriorityIndex(candidates, host) {
3829
+ const idx = candidates.indexOf(normalizeHostUrl(host));
3830
+ return idx >= 0 ? idx : Number.POSITIVE_INFINITY;
3831
+ }
3832
+ async function probeUrlLatency(url) {
3755
3833
  const started = Date.now();
3756
3834
  const controller = new AbortController();
3757
3835
  const timer = setTimeout(() => controller.abort(), 5e3);
3758
3836
  try {
3759
- const response = await fetch(host, {
3837
+ const response = await fetch(url, {
3760
3838
  method: "GET",
3761
3839
  redirect: "manual",
3762
3840
  signal: controller.signal
@@ -3771,6 +3849,16 @@ async function probeHostLatency(host) {
3771
3849
  clearTimeout(timer);
3772
3850
  }
3773
3851
  }
3852
+ async function probePlaywrightHostLatency(host) {
3853
+ let best = null;
3854
+ for (const url of playwrightProbeUrls(host)) {
3855
+ const latency = await probeUrlLatency(url);
3856
+ if (latency !== null && (best === null || latency < best)) {
3857
+ best = latency;
3858
+ }
3859
+ }
3860
+ return best;
3861
+ }
3774
3862
  async function detectBestPlaywrightHost(config) {
3775
3863
  if (detectedBestPlaywrightHost) {
3776
3864
  return detectedBestPlaywrightHost;
@@ -3779,18 +3867,21 @@ async function detectBestPlaywrightHost(config) {
3779
3867
  progress("playwright.host.probe.start", { candidates });
3780
3868
  const probeResults = await Promise.all(candidates.map(async (candidate) => {
3781
3869
  progress("playwright.host.probe.try", { candidate });
3782
- const latency = await probeHostLatency(candidate);
3870
+ const latency = await probePlaywrightHostLatency(candidate);
3783
3871
  progress("playwright.host.probe.result", { candidate, latencyMs: latency });
3784
3872
  return { candidate, latency };
3785
3873
  }));
3786
- let best = normalizeHostUrl(playwrightDownloadHost(config));
3874
+ let best = candidates[0] ?? PLAYWRIGHT_HOST_FALLBACK;
3787
3875
  let bestLatency = Number.POSITIVE_INFINITY;
3876
+ let bestPriority = Number.POSITIVE_INFINITY;
3788
3877
  for (const { candidate, latency } of probeResults) {
3789
3878
  if (latency === null)
3790
3879
  continue;
3791
- if (latency < bestLatency) {
3880
+ const priority = playwrightHostPriorityIndex(candidates, candidate);
3881
+ if (latency < bestLatency || latency === bestLatency && priority < bestPriority) {
3792
3882
  best = candidate;
3793
3883
  bestLatency = latency;
3884
+ bestPriority = priority;
3794
3885
  }
3795
3886
  }
3796
3887
  detectedBestPlaywrightHost = best;
@@ -3807,7 +3898,7 @@ async function runInstallWithPriority(config, packages, onLogLine) {
3807
3898
  const npmProxy = await detectBestRegistry(config, npmProxyRegistry());
3808
3899
  const pnpmProxy = await detectBestRegistry(config, pnpmProxyRegistry());
3809
3900
  progress("packages.install.start", { packages, npmProxy, pnpmProxy });
3810
- onLogLine?.(`[deps] \u5728\u7EBF\u5B89\u88C5\u5305: ${packages.join(" ")} (\u987A\u5E8F: pnpm -> pnpm-proxy -> npm -> npm-proxy)`);
3901
+ onLogLine?.(`[deps] \u5728\u7EBF\u5B89\u88C5\u5305: ${packages.join(" ")} (registry \u63A2\u6D4B: npm=${npmProxy}, pnpm=${pnpmProxy}\uFF1B\u987A\u5E8F: pnpm -> pnpm-proxy -> npm -> npm-proxy)`);
3811
3902
  const strategies = [
3812
3903
  {
3813
3904
  name: "pnpm",
@@ -3928,16 +4019,29 @@ async function verifyPlaywrightSelfTest(onLogLine) {
3928
4019
  await b.close();
3929
4020
  }
3930
4021
  }
3931
- async function installPlaywrightBrowser(config, onLogLine) {
3932
- const targets = playwrightInstallTargets(config);
4022
+ async function installPlaywrightBrowser(config, onLogLine, options) {
4023
+ const rawTargets = playwrightInstallTargets(config);
4024
+ const targets = expandPlaywrightInstallTargets(rawTargets);
4025
+ if (rawTargets.length > 0 && targets.length > rawTargets.length) {
4026
+ onLogLine?.("[playwright] \u914D\u7F6E\u4EC5\u542B chrome/msedge \u901A\u9053\uFF0C\u5DF2\u81EA\u52A8\u52A0\u5165 chromium\uFF08\u81EA\u68C0\u9700 Playwright \u5185\u7F6E\u6D4F\u89C8\u5668\uFF09");
4027
+ }
3933
4028
  progress("playwright.browser.install.start", { targets: targets.length > 0 ? targets : ["all"] });
3934
4029
  onLogLine?.("[playwright] \u5F00\u59CB\u5728\u7EBF\u5B89\u88C5\u6D4F\u89C8\u5668");
3935
- const args = targets.length > 0 ? ["exec", "playwright", "install", ...targets] : ["exec", "playwright", "install"];
4030
+ const { command, cliArgs, version } = resolveBundledPlaywrightCli();
4031
+ const installArgs = [...cliArgs, "install"];
4032
+ if (options?.force) {
4033
+ installArgs.push("--force");
4034
+ }
4035
+ if (targets.length > 0) {
4036
+ installArgs.push(...targets);
4037
+ }
3936
4038
  const selectedHost = await detectBestPlaywrightHost(config);
3937
- onLogLine?.(`[playwright] \u4E0B\u8F7D\u6D4F\u89C8\u5668\uFF08\u955C\u50CF ${selectedHost}\uFF09\uFF0C\u76EE\u6807: ${targets.length ? targets.join(",") : "all"}`);
3938
- await runCommand2("npm", args, {
4039
+ onLogLine?.(`[playwright] \u4F7F\u7528\u5185\u7F6E playwright@${version} CLI\uFF0C\u955C\u50CF ${selectedHost}\uFF0C\u76EE\u6807: ${targets.length ? targets.join(",") : "all"}${options?.force ? " (--force)" : ""}`);
4040
+ const timeoutMs = playwrightInstallTimeoutMs();
4041
+ onLogLine?.(`[playwright] \u5B89\u88C5\u8D85\u65F6\u4E0A\u9650 ${Math.round(timeoutMs / 1e3)}s\uFF08\u53EF\u7528 ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS \u8C03\u6574\uFF09`);
4042
+ await runCommand2(command, installArgs, {
3939
4043
  env: { PLAYWRIGHT_DOWNLOAD_HOST: selectedHost },
3940
- timeoutMs: installStrategyTimeoutMs(),
4044
+ timeoutMs,
3941
4045
  onLogLine
3942
4046
  });
3943
4047
  progress("playwright.browser.install.done", { selectedHost });
@@ -4191,7 +4295,9 @@ async function ensureDriverDependencies(config, options) {
4191
4295
  if (force) {
4192
4296
  onLogLine?.(userRequestedBrowserTargets ? "[playwright] --force\uFF1A\u91CD\u65B0\u5B89\u88C5\u5F53\u524D\u52FE\u9009\u7684\u6D4F\u89C8\u5668\u901A\u9053" : "[playwright] --force\uFF1A\u6309\u914D\u7F6E\u6587\u4EF6\u4E2D\u7684\u76EE\u6807\u91CD\u65B0\u5B89\u88C5\u6D4F\u89C8\u5668");
4193
4297
  }
4194
- await installPlaywrightBrowser(configForPlaywright, onLogLine);
4298
+ await installPlaywrightBrowser(configForPlaywright, onLogLine, {
4299
+ force: force || reinstallForTargets || !launchOk
4300
+ });
4195
4301
  progress("playwright.selfcheck.verify");
4196
4302
  await verifyPlaywrightSelfTest(onLogLine);
4197
4303
  state.playwrightReady = true;
@@ -4364,7 +4470,7 @@ function getString(value) {
4364
4470
  }
4365
4471
 
4366
4472
  // ../../packages/plugin-host/src/index.ts
4367
- var import_node_fs = __toESM(require("node:fs"), 1);
4473
+ var import_node_fs2 = __toESM(require("node:fs"), 1);
4368
4474
  var import_node_path6 = __toESM(require("node:path"), 1);
4369
4475
  var import_node_module2 = require("node:module");
4370
4476
  function assertManifest(plugin) {
@@ -4516,10 +4622,10 @@ function loadPluginFromModule(requireFn, moduleId) {
4516
4622
  }
4517
4623
  }
4518
4624
  function registerPluginsFromDirectory(host, pluginDir) {
4519
- if (!import_node_fs.default.existsSync(pluginDir)) {
4625
+ if (!import_node_fs2.default.existsSync(pluginDir)) {
4520
4626
  return [];
4521
4627
  }
4522
- const entries = import_node_fs.default.readdirSync(pluginDir, { withFileTypes: true }).filter((ent) => ent.isFile() && (ent.name.endsWith(".cjs") || ent.name.endsWith(".js"))).map((ent) => import_node_path6.default.join(pluginDir, ent.name)).sort((a, b) => a.localeCompare(b));
4628
+ const entries = import_node_fs2.default.readdirSync(pluginDir, { withFileTypes: true }).filter((ent) => ent.isFile() && (ent.name.endsWith(".cjs") || ent.name.endsWith(".js"))).map((ent) => import_node_path6.default.join(pluginDir, ent.name)).sort((a, b) => a.localeCompare(b));
4523
4629
  if (entries.length === 0) {
4524
4630
  return [];
4525
4631
  }
@@ -4874,7 +4980,7 @@ function normalizePlaywrightTargets(raw) {
4874
4980
  return { playwrightBrowser: "all", playwrightInstallTargets: ["all"] };
4875
4981
  }
4876
4982
  if (list.length === 0) {
4877
- return { playwrightBrowser: "chromium", playwrightInstallTargets: ["chrome"] };
4983
+ return { playwrightBrowser: "chromium", playwrightInstallTargets: ["chromium"] };
4878
4984
  }
4879
4985
  const ordered = ["chromium", "chrome", "firefox", "webkit", "msedge"].filter((x) => list.includes(x));
4880
4986
  const primary = ordered.find((x) => x === "chromium" || x === "firefox" || x === "webkit") ?? "chromium";
@@ -6528,7 +6634,7 @@ function applyPreinstallPlaywrightHostFile() {
6528
6634
  for (const root of roots) {
6529
6635
  const file = import_node_path10.default.join(root, ".ada-mcp-playwright-host");
6530
6636
  try {
6531
- const host = import_node_fs2.default.readFileSync(file, "utf8").trim();
6637
+ const host = import_node_fs3.default.readFileSync(file, "utf8").trim();
6532
6638
  if (host.length > 0) {
6533
6639
  process.env.PLAYWRIGHT_DOWNLOAD_HOST = host;
6534
6640
  console.error(`[ADA-MCP] using playwright CDN from ${file}: ${host}`);
@@ -6567,7 +6673,7 @@ async function runBootstrapInstallDeps(argv2) {
6567
6673
 
6568
6674
  // src/main.ts
6569
6675
  var import_promises13 = __toESM(require("node:fs/promises"));
6570
- var import_node_fs4 = require("node:fs");
6676
+ var import_node_fs5 = require("node:fs");
6571
6677
  var import_node_net2 = __toESM(require("node:net"));
6572
6678
  var import_node_path14 = __toESM(require("node:path"));
6573
6679
  var import_node_child_process5 = require("node:child_process");
@@ -6577,7 +6683,7 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
6577
6683
  var import_types = require("@modelcontextprotocol/sdk/types.js");
6578
6684
 
6579
6685
  // src/executor.ts
6580
- var import_node_fs3 = require("node:fs");
6686
+ var import_node_fs4 = require("node:fs");
6581
6687
  var import_node_path11 = __toESM(require("node:path"));
6582
6688
  var import_node_url3 = require("node:url");
6583
6689
  var import_meta = {};
@@ -6596,7 +6702,7 @@ function ensureBundledPluginDir() {
6596
6702
  candidates.push(import_node_path11.default.join(dirname, "..", "plugins"));
6597
6703
  }
6598
6704
  for (const dir of candidates) {
6599
- if ((0, import_node_fs3.existsSync)(dir)) {
6705
+ if ((0, import_node_fs4.existsSync)(dir)) {
6600
6706
  process.env.ADA_PLUGIN_DIR = dir;
6601
6707
  return;
6602
6708
  }
@@ -6752,7 +6858,7 @@ function parseServerEndpoint(serverUrl) {
6752
6858
  }
6753
6859
  function commandAvailable(command) {
6754
6860
  if (import_node_path14.default.isAbsolute(command)) {
6755
- return (0, import_node_fs4.existsSync)(command);
6861
+ return (0, import_node_fs5.existsSync)(command);
6756
6862
  }
6757
6863
  const checker = process.platform === "win32" ? "where.exe" : "which";
6758
6864
  const checked = (0, import_node_child_process5.spawnSync)(checker, [command], {
@@ -6796,7 +6902,7 @@ function resolveAppiumNodeEntrypoint() {
6796
6902
  import_node_path14.default.join(process.cwd(), "..", "..", "node_modules", "appium", "build", "lib", "main.js")
6797
6903
  ];
6798
6904
  for (const p of candidates) {
6799
- if ((0, import_node_fs4.existsSync)(p)) {
6905
+ if ((0, import_node_fs5.existsSync)(p)) {
6800
6906
  return p;
6801
6907
  }
6802
6908
  }
@@ -6815,11 +6921,11 @@ function loadPersistedHomes() {
6815
6921
  import_node_path14.default.join(process.cwd(), "..", ".ada-agent", "deps-install-state.json")
6816
6922
  ];
6817
6923
  for (const file of candidates) {
6818
- if (!(0, import_node_fs4.existsSync)(file)) {
6924
+ if (!(0, import_node_fs5.existsSync)(file)) {
6819
6925
  continue;
6820
6926
  }
6821
6927
  try {
6822
- const raw = (0, import_node_fs4.readFileSync)(file, "utf8");
6928
+ const raw = (0, import_node_fs5.readFileSync)(file, "utf8");
6823
6929
  const parsed = JSON.parse(raw);
6824
6930
  const androidHome = typeof parsed.androidHome === "string" ? parsed.androidHome.trim() : "";
6825
6931
  const appiumHome = typeof parsed.appiumHome === "string" ? parsed.appiumHome.trim() : "";
@@ -6852,11 +6958,11 @@ function resolveAndroidSdkRoot() {
6852
6958
  process.env.USERPROFILE ? import_node_path14.default.join(process.env.USERPROFILE, "AppData", "Local", "Android", "Sdk") : null
6853
6959
  ].map((v) => typeof v === "string" ? v.trim() : "").filter(Boolean);
6854
6960
  for (const sdkRoot of candidates) {
6855
- if (persisted.androidHome && sdkRoot === persisted.androidHome && (0, import_node_fs4.existsSync)(sdkRoot)) {
6961
+ if (persisted.androidHome && sdkRoot === persisted.androidHome && (0, import_node_fs5.existsSync)(sdkRoot)) {
6856
6962
  return sdkRoot;
6857
6963
  }
6858
6964
  const platformTools = import_node_path14.default.join(sdkRoot, "platform-tools");
6859
- if ((0, import_node_fs4.existsSync)(platformTools)) {
6965
+ if ((0, import_node_fs5.existsSync)(platformTools)) {
6860
6966
  return sdkRoot;
6861
6967
  }
6862
6968
  }
@@ -6867,11 +6973,11 @@ function getAppiumExtensionsFile(homeDir) {
6867
6973
  }
6868
6974
  function hasAppiumDriver(homeDir, driverName) {
6869
6975
  const file = getAppiumExtensionsFile(homeDir);
6870
- if (!(0, import_node_fs4.existsSync)(file)) {
6976
+ if (!(0, import_node_fs5.existsSync)(file)) {
6871
6977
  return false;
6872
6978
  }
6873
6979
  try {
6874
- const text = (0, import_node_fs4.readFileSync)(file, "utf8");
6980
+ const text = (0, import_node_fs5.readFileSync)(file, "utf8");
6875
6981
  return text.toLowerCase().includes(driverName.toLowerCase());
6876
6982
  } catch {
6877
6983
  return false;
@@ -6894,7 +7000,7 @@ function resolveAppiumHome(platform) {
6894
7000
  }
6895
7001
  }
6896
7002
  for (const candidate of uniq) {
6897
- if ((0, import_node_fs4.existsSync)(getAppiumExtensionsFile(candidate))) {
7003
+ if ((0, import_node_fs5.existsSync)(getAppiumExtensionsFile(candidate))) {
6898
7004
  return candidate;
6899
7005
  }
6900
7006
  }
@@ -8358,7 +8464,7 @@ async function startMcpServer() {
8358
8464
  mcpServers: {
8359
8465
  "ada-mcp": {
8360
8466
  command: "pnpm",
8361
- args: ["dlx", "@ada-mcp/launcher@0.1.2"]
8467
+ args: ["dlx", "@ada-mcp/launcher@0.1.3"]
8362
8468
  }
8363
8469
  }
8364
8470
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ada-mcp/mcp-server",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "ADA MCP server for web/mobile automation (stdio + remote HTTP)",
5
5
  "private": false,
6
6
  "type": "commonjs",