@ada-mcp/mcp-server 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -3568,6 +3568,39 @@ function resolveBundledPlaywrightCli() {
3568
3568
  const version = String(JSON.parse(raw).version ?? "");
3569
3569
  return { command: "node", cliArgs: [import_node_path5.default.join(root, "cli.js")], version };
3570
3570
  }
3571
+ function resolveChromiumBrowserVersion() {
3572
+ try {
3573
+ const browsersPath = require2.resolve("playwright-core/browsers.json");
3574
+ const raw = (0, import_node_fs.readFileSync)(browsersPath, "utf8");
3575
+ const parsed = JSON.parse(raw);
3576
+ const chromium = parsed.browsers?.find((b) => b.name === "chromium");
3577
+ return String(chromium?.browserVersion ?? "").trim();
3578
+ } catch {
3579
+ return "";
3580
+ }
3581
+ }
3582
+ function playwrightChromiumZipUrl(host, browserVersion) {
3583
+ const h = normalizeHostUrl(host);
3584
+ const base = h.includes("cdn.npmmirror.com/binaries/playwright") || h.endsWith("/binaries/playwright") ? "https://cdn.npmmirror.com/binaries/playwright" : h.includes("npmmirror.com") && !h.includes("/mirrors/playwright") ? "https://npmmirror.com/mirrors/playwright" : h;
3585
+ return `${base}/builds/cft/${browserVersion}/win64/chrome-win64.zip`;
3586
+ }
3587
+ async function probePlaywrightBrowserArtifact(host, browserVersion) {
3588
+ const url = playwrightChromiumZipUrl(host, browserVersion);
3589
+ const started = Date.now();
3590
+ const controller = new AbortController();
3591
+ const timer = setTimeout(() => controller.abort(), 8e3);
3592
+ try {
3593
+ const response = await fetch(url, { method: "HEAD", redirect: "follow", signal: controller.signal });
3594
+ if (response.status === 200) {
3595
+ return Date.now() - started;
3596
+ }
3597
+ return null;
3598
+ } catch {
3599
+ return null;
3600
+ } finally {
3601
+ clearTimeout(timer);
3602
+ }
3603
+ }
3571
3604
  function requiredAppiumDrivers(config) {
3572
3605
  return Array.from(new Set(config.appium.requiredDrivers ?? []));
3573
3606
  }
@@ -3677,7 +3710,6 @@ async function resolveCompatibleDriverSpecs(driver) {
3677
3710
  return Array.from(new Set(specs));
3678
3711
  }
3679
3712
  var detectedBestRegistryByKey = /* @__PURE__ */ new Map();
3680
- var detectedBestPlaywrightHost = null;
3681
3713
  var PROGRESS_STEPS = [
3682
3714
  "deps.ensure.start",
3683
3715
  "registry.probe.start",
@@ -3859,40 +3891,43 @@ async function probePlaywrightHostLatency(host) {
3859
3891
  }
3860
3892
  return best;
3861
3893
  }
3862
- async function detectBestPlaywrightHost(config) {
3863
- if (detectedBestPlaywrightHost) {
3864
- return detectedBestPlaywrightHost;
3865
- }
3894
+ async function rankPlaywrightHosts(config) {
3866
3895
  const candidates = playwrightHostCandidates(config);
3867
- progress("playwright.host.probe.start", { candidates });
3896
+ const browserVersion = resolveChromiumBrowserVersion();
3897
+ progress("playwright.host.probe.start", { candidates, browserVersion: browserVersion || void 0 });
3868
3898
  const probeResults = await Promise.all(candidates.map(async (candidate) => {
3869
3899
  progress("playwright.host.probe.try", { candidate });
3870
- const latency = await probePlaywrightHostLatency(candidate);
3871
- progress("playwright.host.probe.result", { candidate, latencyMs: latency });
3872
- return { candidate, latency };
3900
+ const artifactLatency = browserVersion ? await probePlaywrightBrowserArtifact(candidate, browserVersion) : null;
3901
+ const rootLatency = await probePlaywrightHostLatency(candidate);
3902
+ const latency = artifactLatency ?? rootLatency;
3903
+ const artifactOk = artifactLatency !== null;
3904
+ progress("playwright.host.probe.result", {
3905
+ candidate,
3906
+ latencyMs: latency,
3907
+ artifactOk,
3908
+ browserVersion: browserVersion || void 0
3909
+ });
3910
+ return { candidate, latency, artifactOk, priority: playwrightHostPriorityIndex(candidates, candidate) };
3873
3911
  }));
3874
- let best = candidates[0] ?? PLAYWRIGHT_HOST_FALLBACK;
3875
- let bestLatency = Number.POSITIVE_INFINITY;
3876
- let bestPriority = Number.POSITIVE_INFINITY;
3877
- for (const { candidate, latency } of probeResults) {
3878
- if (latency === null)
3879
- continue;
3880
- const priority = playwrightHostPriorityIndex(candidates, candidate);
3881
- if (latency < bestLatency || latency === bestLatency && priority < bestPriority) {
3882
- best = candidate;
3883
- bestLatency = latency;
3884
- bestPriority = priority;
3912
+ const reachable = probeResults.filter((x) => x.latency !== null);
3913
+ const withArtifact = reachable.filter((x) => x.artifactOk);
3914
+ const pool = withArtifact.length > 0 ? withArtifact : reachable;
3915
+ pool.sort((a, b) => {
3916
+ if (a.artifactOk !== b.artifactOk) {
3917
+ return a.artifactOk ? -1 : 1;
3885
3918
  }
3886
- }
3887
- detectedBestPlaywrightHost = best;
3888
- log("info", {
3889
- event: "deps.playwright.host.auto-selected",
3890
- details: {
3891
- selected: best,
3892
- candidates
3919
+ if (a.latency !== b.latency) {
3920
+ return (a.latency ?? 0) - (b.latency ?? 0);
3893
3921
  }
3922
+ return a.priority - b.priority;
3894
3923
  });
3895
- return best;
3924
+ const ranked = pool.map((x) => x.candidate);
3925
+ for (const candidate of candidates) {
3926
+ if (!ranked.includes(candidate)) {
3927
+ ranked.push(candidate);
3928
+ }
3929
+ }
3930
+ return ranked.length > 0 ? ranked : [...candidates];
3896
3931
  }
3897
3932
  async function runInstallWithPriority(config, packages, onLogLine) {
3898
3933
  const npmProxy = await detectBestRegistry(config, npmProxyRegistry());
@@ -4035,16 +4070,37 @@ async function installPlaywrightBrowser(config, onLogLine, options) {
4035
4070
  if (targets.length > 0) {
4036
4071
  installArgs.push(...targets);
4037
4072
  }
4038
- const selectedHost = await detectBestPlaywrightHost(config);
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)" : ""}`);
4073
+ const rankedHosts = await rankPlaywrightHosts(config);
4040
4074
  const timeoutMs = playwrightInstallTimeoutMs();
4041
4075
  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, {
4043
- env: { PLAYWRIGHT_DOWNLOAD_HOST: selectedHost },
4044
- timeoutMs,
4045
- onLogLine
4046
- });
4047
- progress("playwright.browser.install.done", { selectedHost });
4076
+ let lastError;
4077
+ for (let i = 0; i < rankedHosts.length; i++) {
4078
+ const host = rankedHosts[i];
4079
+ if (i > 0) {
4080
+ onLogLine?.(`[playwright] \u4E0A\u4E00\u955C\u50CF\u5931\u8D25\uFF0C\u6539\u8BD5 ${host}`);
4081
+ }
4082
+ onLogLine?.(`[playwright] \u4F7F\u7528\u5185\u7F6E playwright@${version} CLI\uFF0C\u955C\u50CF ${host}\uFF0C\u76EE\u6807: ${targets.length ? targets.join(",") : "all"}${options?.force ? " (--force)" : ""}`);
4083
+ try {
4084
+ await runCommand2(command, installArgs, {
4085
+ env: { PLAYWRIGHT_DOWNLOAD_HOST: host },
4086
+ timeoutMs,
4087
+ onLogLine
4088
+ });
4089
+ progress("playwright.browser.install.done", { selectedHost: host, attempt: i + 1 });
4090
+ return;
4091
+ } catch (error) {
4092
+ lastError = error;
4093
+ log("warn", {
4094
+ event: "deps.playwright.browser.install.host.fail",
4095
+ details: {
4096
+ host,
4097
+ attempt: i + 1,
4098
+ message: error instanceof Error ? error.message : String(error)
4099
+ }
4100
+ });
4101
+ }
4102
+ }
4103
+ throw lastError instanceof Error ? lastError : new Error(String(lastError ?? "playwright browser install failed"));
4048
4104
  }
4049
4105
  async function checkPlaywrightLaunchable() {
4050
4106
  try {
@@ -6624,6 +6680,13 @@ function resolveBootstrapInstallDeps(argv2) {
6624
6680
  if (nativeDir) extras.nativeDriversDir = nativeDir;
6625
6681
  return { skip: false, scopes, force, extras };
6626
6682
  }
6683
+ var PREINSTALL_PLAYWRIGHT_HOST_ALLOW = /* @__PURE__ */ new Set([
6684
+ "https://cdn.playwright.dev",
6685
+ "https://playwright.azureedge.net"
6686
+ ]);
6687
+ function normalizePlaywrightHost(url) {
6688
+ return url.replace(/\/$/, "");
6689
+ }
6627
6690
  function applyPreinstallPlaywrightHostFile() {
6628
6691
  if (process.env.PLAYWRIGHT_DOWNLOAD_HOST?.trim()) {
6629
6692
  return;
@@ -6634,12 +6697,18 @@ function applyPreinstallPlaywrightHostFile() {
6634
6697
  for (const root of roots) {
6635
6698
  const file = import_node_path10.default.join(root, ".ada-mcp-playwright-host");
6636
6699
  try {
6637
- const host = import_node_fs3.default.readFileSync(file, "utf8").trim();
6638
- if (host.length > 0) {
6700
+ const host = normalizePlaywrightHost(import_node_fs3.default.readFileSync(file, "utf8").trim());
6701
+ if (host.length > 0 && PREINSTALL_PLAYWRIGHT_HOST_ALLOW.has(host)) {
6639
6702
  process.env.PLAYWRIGHT_DOWNLOAD_HOST = host;
6640
6703
  console.error(`[ADA-MCP] using playwright CDN from ${file}: ${host}`);
6641
6704
  return;
6642
6705
  }
6706
+ if (host.length > 0) {
6707
+ console.error(
6708
+ `[ADA-MCP] ignore preinstall playwright CDN (runtime will re-probe): ${host}`
6709
+ );
6710
+ return;
6711
+ }
6643
6712
  } catch {
6644
6713
  }
6645
6714
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ada-mcp/mcp-server",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "ADA MCP server for web/mobile automation (stdio + remote HTTP)",
5
5
  "private": false,
6
6
  "type": "commonjs",
@@ -35,7 +35,7 @@
35
35
  "express": "^5.2.1",
36
36
  "jimp": "^1.6.0",
37
37
  "js-yaml": "^4.1.0",
38
- "playwright": "^1.59.1",
38
+ "playwright": "1.59.1",
39
39
  "selenium-webdriver": "^4.34.0"
40
40
  },
41
41
  "devDependencies": {
@@ -62,7 +62,11 @@ async function main() {
62
62
  console.error(`[ada-mcp preinstall] registry ${candidate} -> ${latency === null ? "fail" : `${latency}ms`}`);
63
63
  }
64
64
 
65
- const pwCandidates = playwrightHostCandidateList();
65
+ /** preinstall 阶段依赖尚未安装,无法校验浏览器包是否存在;仅测官方 CDN,避免写入国内镜像后 404 */
66
+ const pwCandidates = [
67
+ "https://cdn.playwright.dev",
68
+ "https://playwright.azureedge.net"
69
+ ];
66
70
  const pw = await detectBestPlaywrightHost(pwCandidates);
67
71
  const hostFile = path.join(root, ".ada-mcp-playwright-host");
68
72
  fs.writeFileSync(hostFile, `${pw.best}\n`, "utf8");