@ada-mcp/mcp-server 0.1.15 → 0.1.16

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 +10 -10
  2. package/dist/cli.cjs +226 -116
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,27 +8,27 @@ ADA MCP server package that supports:
8
8
 
9
9
  ## 标准安装(Cursor / MCP)
10
10
 
11
- 请使用 **`@ada-mcp/launcher@0.1.12`** 拉起本包(见 [launcher README](../ada-mcp-launcher/README.md)):
11
+ 请使用 **`@ada-mcp/launcher@0.1.13`** 拉起本包(见 [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.12"]
18
+ "args": ["dlx", "@ada-mcp/launcher@0.1.13"]
19
19
  }
20
20
  }
21
21
  }
22
22
  ```
23
23
 
24
- 本包版本:**`@ada-mcp/mcp-server@0.1.15`**(由 launcher 默认拉取;依赖锁定 `playwright@1.59.1`)。
24
+ 本包版本:**`@ada-mcp/mcp-server@0.1.16`**(由 launcher 默认拉取;依赖锁定 `playwright@1.59.1`)。
25
25
 
26
26
  直接调试本包(无 launcher 拉包前测速):
27
27
 
28
28
  ```bash
29
- pnpm dlx @ada-mcp/mcp-server@0.1.15
29
+ pnpm dlx @ada-mcp/mcp-server@0.1.16
30
30
  # npx 等价:
31
- npx -y @ada-mcp/mcp-server@0.1.15
31
+ npx -y @ada-mcp/mcp-server@0.1.16
32
32
  ```
33
33
 
34
34
  ## 启动时自动安装依赖(默认仅 Playwright)
@@ -83,27 +83,27 @@ npx -y @ada-mcp/mcp-server@0.1.15
83
83
  在标准 `args` 后追加,例如安装全部依赖:
84
84
 
85
85
  ```json
86
- "args": ["dlx", "@ada-mcp/launcher@0.1.12", "--install-deps=all"]
86
+ "args": ["dlx", "@ada-mcp/launcher@0.1.13", "--install-deps=all"]
87
87
  ```
88
88
 
89
89
  ## Cursor MCP 配置
90
90
 
91
- **pnpm(推荐)**:`pnpm` + `dlx @ada-mcp/launcher@0.1.12`
91
+ **pnpm(推荐)**:`pnpm` + `dlx @ada-mcp/launcher@0.1.13`
92
92
 
93
- **npx 等价**(`launcher@0.1.7+`):`npx` + `-y @ada-mcp/launcher@0.1.12`(内层同样 `npx -y` mcp-server,测速逻辑与 pnpm 一致)
93
+ **npx 等价**(`launcher@0.1.7+`):`npx` + `-y @ada-mcp/launcher@0.1.13`(内层同样 `npx -y` mcp-server,测速逻辑与 pnpm 一致)
94
94
 
95
95
  ```json
96
96
  {
97
97
  "mcpServers": {
98
98
  "ada-mcp": {
99
99
  "command": "npx",
100
- "args": ["-y", "@ada-mcp/launcher@0.1.12"]
100
+ "args": ["-y", "@ada-mcp/launcher@0.1.13"]
101
101
  }
102
102
  }
103
103
  }
104
104
  ```
105
105
 
106
- Windows 若找不到 `pnpm`,可将 `command` 改为 `pnpm.cmd` 绝对路径;无 pnpm 时只能直接 `npx -y @ada-mcp/mcp-server@0.1.15`(无 launcher 拉包测速)。
106
+ Windows 若找不到 `pnpm`,可将 `command` 改为 `pnpm.cmd` 绝对路径;无 pnpm 时只能直接 `npx -y @ada-mcp/mcp-server@0.1.16`(无 launcher 拉包测速)。
107
107
 
108
108
  ## Remote mode
109
109
 
package/dist/cli.cjs CHANGED
@@ -3429,14 +3429,7 @@ async function detectLocalBrowsers() {
3429
3429
  }
3430
3430
  function logSeleniumDriverGuidance(onLogLine) {
3431
3431
  onLogLine?.(
3432
- "[selenium] \u5B89\u88C5\u524D\u4F1A\u68C0\u6D4B\u672C\u673A Chrome/Chromium \u4E0E Firefox \u7248\u672C\uFF1B\u9A71\u52A8\u653E\u5165\u9879\u76EE\u76EE\u5F55\u540E\u53EF\u81EA\u884C\u66FF\u6362\u8986\u76D6\u3002"
3433
- );
3434
- onLogLine?.("[selenium] \u5404\u6D4F\u89C8\u5668\u9A71\u52A8\u624B\u52A8\u4E0B\u8F7D\u53C2\u8003\uFF1A");
3435
- for (const ref of SELENIUM_DRIVER_MANUAL_DOWNLOAD_REFERENCES) {
3436
- onLogLine?.(`[selenium] ${ref.browser} (${ref.platforms}) \u2014 ${ref.vendor}: ${ref.url}`);
3437
- }
3438
- onLogLine?.(
3439
- "[selenium] \u81EA\u52A8\u4E0B\u8F7D\u5931\u8D25\u65F6\u5C06\u8DF3\u8FC7\u5BF9\u5E94\u9A71\u52A8\u5E76\u7EE7\u7EED\uFF0C\u8BF7\u6309\u4E0A\u8868\u81EA\u884C\u4E0B\u8F7D\u540E\u653E\u5165\u9A71\u52A8\u76EE\u5F55\u6216\u914D\u7F6E PATH/ADA_GECKODRIVER_PATH/ADA_CHROMEDRIVER_PATH\u3002"
3432
+ "[selenium] \u5C06\u68C0\u6D4B\u672C\u673A Chrome/Firefox \u5E76\u5C1D\u8BD5\u4E0B\u8F7D\u9A71\u52A8\u81F3\u76EE\u5F55\uFF1B\u5931\u8D25\u53EF\u624B\u52A8\u653E\u5165 geckodriver/chromedriver\uFF08\u89C1\u63A5\u5165\u624B\u518C Selenium \u8282\uFF09"
3440
3433
  );
3441
3434
  }
3442
3435
  async function detectInstalledChromeMajorVersion() {
@@ -3657,7 +3650,7 @@ async function ensureNativeWebDrivers(options = {}) {
3657
3650
  }
3658
3651
  return resolved;
3659
3652
  }
3660
- var import_node_child_process, import_promises4, import_node_path4, DEFAULT_NATIVE_DRIVERS_DIR, CHROME_FOR_TESTING_JSON, SELENIUM_DRIVER_MANUAL_DOWNLOAD_REFERENCES;
3653
+ var import_node_child_process, import_promises4, import_node_path4, DEFAULT_NATIVE_DRIVERS_DIR, CHROME_FOR_TESTING_JSON;
3661
3654
  var init_src2 = __esm({
3662
3655
  "../../packages/native-drivers/src/index.ts"() {
3663
3656
  "use strict";
@@ -3666,48 +3659,17 @@ var init_src2 = __esm({
3666
3659
  import_node_path4 = __toESM(require("node:path"), 1);
3667
3660
  DEFAULT_NATIVE_DRIVERS_DIR = "dirver";
3668
3661
  CHROME_FOR_TESTING_JSON = "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json";
3669
- SELENIUM_DRIVER_MANUAL_DOWNLOAD_REFERENCES = [
3670
- {
3671
- browser: "Chrome/Chromium",
3672
- platforms: "Windows/Linux/macOS",
3673
- vendor: "\u8C37\u6B4C",
3674
- url: "https://chromedriver.storage.googleapis.com/index.html"
3675
- },
3676
- {
3677
- browser: "Firefox",
3678
- platforms: "Windows/Linux/macOS",
3679
- vendor: "Mozilla",
3680
- url: "https://github.com/mozilla/geckodriver/releases"
3681
- },
3682
- {
3683
- browser: "Edge",
3684
- platforms: "win10",
3685
- vendor: "\u5FAE\u8F6F",
3686
- url: "https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/"
3687
- },
3688
- {
3689
- browser: "Internet Explorer",
3690
- platforms: "Windows",
3691
- vendor: "Selenium \u9879\u76EE\u7EC4",
3692
- url: "https://selenium-release.storage.googleapis.com/index.html"
3693
- },
3694
- {
3695
- browser: "Safari",
3696
- platforms: "macOS El Capitan \u53CA\u66F4\u9AD8\u7248\u672C",
3697
- vendor: "\u82F9\u679C",
3698
- url: "\uFF08\u7CFB\u7EDF\u5185\u7F6E\uFF0C\u65E0\u9700\u5355\u72EC\u4E0B\u8F7D\uFF09"
3699
- },
3700
- {
3701
- browser: "Opera",
3702
- platforms: "Windows/macOS/Linux",
3703
- vendor: "Opera",
3704
- url: "https://github.com/operasoftware/operachromiumdriver/releases"
3705
- }
3706
- ];
3707
3662
  }
3708
3663
  });
3709
3664
 
3710
3665
  // ../ada-agent/src/dependency-installer.ts
3666
+ function playwrightInstallPackageSpec() {
3667
+ const fromEnv = process.env.ADA_PLAYWRIGHT_VERSION?.trim();
3668
+ return `playwright@${fromEnv || PINNED_PLAYWRIGHT_VERSION}`;
3669
+ }
3670
+ function resolveInstallPackageSpecs(packages) {
3671
+ return packages.map((pkg) => pkg === "playwright" ? playwrightInstallPackageSpec() : pkg);
3672
+ }
3711
3673
  function shouldUseShell(command) {
3712
3674
  if (process.platform !== "win32") {
3713
3675
  return false;
@@ -3722,6 +3684,69 @@ function hasPackage(packageName) {
3722
3684
  return false;
3723
3685
  }
3724
3686
  }
3687
+ function briefErrorMessage(error) {
3688
+ if (error instanceof Error) {
3689
+ return error.message.split(/\r?\n/)[0]?.trim() || error.message;
3690
+ }
3691
+ return String(error).split(/\r?\n/)[0]?.trim() || String(error);
3692
+ }
3693
+ function shouldEmitPlaywrightCliLine(line) {
3694
+ const t = line.trim();
3695
+ if (!t) {
3696
+ return false;
3697
+ }
3698
+ if (/^\s*at\s/.test(line) || t.includes("coreBundle.js") || t.includes("processTicksAndRejections")) {
3699
+ return false;
3700
+ }
3701
+ if (t.includes("<Error>") || t.includes("NoSuchKey") || t.startsWith("<?xml")) {
3702
+ return false;
3703
+ }
3704
+ if (t.includes("Download failure, code=") && !t.startsWith("Error:")) {
3705
+ return false;
3706
+ }
3707
+ return true;
3708
+ }
3709
+ function summarizePlaywrightCliLine(line) {
3710
+ const t = line.trim();
3711
+ if (/^Downloading Chrome for Testing/i.test(t) || /^Downloading chromium/i.test(t)) {
3712
+ const from = t.match(/\bfrom\s+(https?:\/\/\S+)/i)?.[1];
3713
+ return from ? `[playwright] \u6B63\u5728\u4E0B\u8F7D Chromium\uFF08${from}\uFF09` : "[playwright] \u6B63\u5728\u4E0B\u8F7D Chromium\u2026";
3714
+ }
3715
+ if (/^Error:\s*Download failed:/i.test(t)) {
3716
+ const code = t.match(/\bcode[=\s]+(\d{3})\b/i)?.[1] ?? t.match(/returned code (\d{3})/i)?.[1];
3717
+ return code ? `[playwright][warn] \u955C\u50CF\u8FD4\u56DE HTTP ${code}\uFF0C\u5C06\u5C1D\u8BD5\u4E0B\u4E00\u4E2A CDN` : "[playwright][warn] \u955C\u50CF\u4E0B\u8F7D\u5931\u8D25\uFF0C\u5C06\u5C1D\u8BD5\u4E0B\u4E00\u4E2A CDN";
3718
+ }
3719
+ if (/^Failed to install browsers/i.test(t) || /^Failed to download Chrome/i.test(t)) {
3720
+ return "[playwright][warn] \u5F53\u524D\u955C\u50CF\u672A\u5B89\u88C5\u6210\u529F";
3721
+ }
3722
+ if (/^Progress:/i.test(t)) {
3723
+ return null;
3724
+ }
3725
+ if (t.length > 200) {
3726
+ return `[playwright] ${t.slice(0, 120)}\u2026`;
3727
+ }
3728
+ return t.startsWith("[playwright]") ? t : `[playwright] ${t}`;
3729
+ }
3730
+ function createPlaywrightInstallLogSink(onLogLine) {
3731
+ if (!onLogLine) {
3732
+ return void 0;
3733
+ }
3734
+ const seen = /* @__PURE__ */ new Set();
3735
+ return (line) => {
3736
+ if (!shouldEmitPlaywrightCliLine(line)) {
3737
+ return;
3738
+ }
3739
+ const summary = summarizePlaywrightCliLine(line);
3740
+ if (!summary) {
3741
+ return;
3742
+ }
3743
+ if (seen.has(summary)) {
3744
+ return;
3745
+ }
3746
+ seen.add(summary);
3747
+ onLogLine(summary);
3748
+ };
3749
+ }
3725
3750
  function runCommand2(command, args, options) {
3726
3751
  return new Promise((resolve, reject) => {
3727
3752
  const onLogLine = options?.onLogLine;
@@ -3746,7 +3771,7 @@ function runCommand2(command, args, options) {
3746
3771
  buf = parts.pop() ?? "";
3747
3772
  for (const line of parts) {
3748
3773
  const t = line.trimEnd();
3749
- if (t.length > 0) {
3774
+ if (t.length > 0 && (options?.logFilter?.(t) ?? true)) {
3750
3775
  onLogLine(t);
3751
3776
  }
3752
3777
  }
@@ -3997,8 +4022,15 @@ function stepMeta(stage) {
3997
4022
  };
3998
4023
  }
3999
4024
  function progress(stage, details) {
4025
+ if (depsHumanLog) {
4026
+ const label = PROGRESS_HUMAN_LABELS[stage];
4027
+ if (label) {
4028
+ depsHumanLog(label);
4029
+ }
4030
+ return;
4031
+ }
4000
4032
  const meta = stepMeta(stage);
4001
- log("info", {
4033
+ depsStructuredLog("info", {
4002
4034
  event: "deps.progress",
4003
4035
  details: {
4004
4036
  stage,
@@ -4007,6 +4039,12 @@ function progress(stage, details) {
4007
4039
  }
4008
4040
  });
4009
4041
  }
4042
+ function depsStructuredLog(level, payload) {
4043
+ if (depsHumanLog) {
4044
+ return;
4045
+ }
4046
+ log(level, payload);
4047
+ }
4010
4048
  function normalizeRegistryUrl(url) {
4011
4049
  return url.replace(/\/$/, "");
4012
4050
  }
@@ -4079,7 +4117,7 @@ async function detectBestRegistry(config, baseProxy) {
4079
4117
  }
4080
4118
  }
4081
4119
  detectedBestRegistryByKey.set(cacheKey, best);
4082
- log("info", {
4120
+ depsStructuredLog("info", {
4083
4121
  event: "deps.registry.auto-selected",
4084
4122
  details: {
4085
4123
  selected: best,
@@ -4175,11 +4213,14 @@ async function rankPlaywrightHosts(config) {
4175
4213
  const withArtifact = reachable.filter((x) => x.artifactOk);
4176
4214
  const pool = withArtifact.length > 0 ? withArtifact : reachable;
4177
4215
  pool.sort((a, b) => {
4178
- if (a.artifactOk !== b.artifactOk) {
4179
- return a.artifactOk ? -1 : 1;
4180
- }
4181
- if (a.latency !== b.latency) {
4182
- return (a.latency ?? 0) - (b.latency ?? 0);
4216
+ if (withArtifact.length > 0) {
4217
+ if (a.artifactOk !== b.artifactOk) {
4218
+ return a.artifactOk ? -1 : 1;
4219
+ }
4220
+ if (a.latency !== b.latency) {
4221
+ return (a.latency ?? 0) - (b.latency ?? 0);
4222
+ }
4223
+ return a.priority - b.priority;
4183
4224
  }
4184
4225
  return a.priority - b.priority;
4185
4226
  });
@@ -4192,37 +4233,43 @@ async function rankPlaywrightHosts(config) {
4192
4233
  return ranked.length > 0 ? ranked : [...candidates];
4193
4234
  }
4194
4235
  async function runInstallWithPriority(config, packages, onLogLine) {
4236
+ const specs = resolveInstallPackageSpecs(packages);
4195
4237
  const npmProxy = await detectBestRegistry(config, npmProxyRegistry());
4196
4238
  const pnpmProxy = await detectBestRegistry(config, pnpmProxyRegistry());
4197
- progress("packages.install.start", { packages, npmProxy, pnpmProxy });
4239
+ progress("packages.install.start", { packages: specs, npmProxy, pnpmProxy });
4240
+ if (packages.includes("playwright")) {
4241
+ onLogLine?.(
4242
+ `[deps] playwright \u5C06\u5B89\u88C5\u9501\u5B9A\u7248\u672C ${specs.find((s) => s.startsWith("playwright@")) ?? playwrightInstallPackageSpec()}\uFF08\u907F\u514D\u955C\u50CF latest \u4E0E\u6D4F\u89C8\u5668\u5305\u4E0D\u540C\u6B65\uFF09`
4243
+ );
4244
+ }
4198
4245
  onLogLine?.(
4199
- `[deps] \u5728\u7EBF\u5B89\u88C5\u5305: ${packages.join(" ")} (registry \u63A2\u6D4B: npm=${npmProxy}, pnpm=${pnpmProxy}\uFF1B\u987A\u5E8F: pnpm -> pnpm-proxy -> npm -> npm-proxy)`
4246
+ `[deps] \u5728\u7EBF\u5B89\u88C5\u5305: ${specs.join(" ")} (registry \u63A2\u6D4B: npm=${npmProxy}, pnpm=${pnpmProxy}\uFF1B\u987A\u5E8F: pnpm -> pnpm-proxy -> npm -> npm-proxy)`
4200
4247
  );
4201
4248
  const strategies = [
4202
4249
  {
4203
4250
  name: "pnpm",
4204
- run: () => runCommand2("pnpm", ["add", ...packages], {
4251
+ run: () => runCommand2("pnpm", ["add", ...specs], {
4205
4252
  timeoutMs: installStrategyTimeoutMs(),
4206
4253
  onLogLine
4207
4254
  })
4208
4255
  },
4209
4256
  {
4210
4257
  name: "pnpm-proxy",
4211
- run: () => runCommand2("pnpm", ["add", ...packages, "--registry", pnpmProxy], {
4258
+ run: () => runCommand2("pnpm", ["add", ...specs, "--registry", pnpmProxy], {
4212
4259
  timeoutMs: installStrategyTimeoutMs(),
4213
4260
  onLogLine
4214
4261
  })
4215
4262
  },
4216
4263
  {
4217
4264
  name: "npm",
4218
- run: () => runCommand2("npm", ["install", ...packages], {
4265
+ run: () => runCommand2("npm", ["install", ...specs], {
4219
4266
  timeoutMs: installStrategyTimeoutMs(),
4220
4267
  onLogLine
4221
4268
  })
4222
4269
  },
4223
4270
  {
4224
4271
  name: "npm-proxy",
4225
- run: () => runCommand2("npm", ["install", ...packages, "--registry", npmProxy], {
4272
+ run: () => runCommand2("npm", ["install", ...specs, "--registry", npmProxy], {
4226
4273
  timeoutMs: installStrategyTimeoutMs(),
4227
4274
  onLogLine
4228
4275
  })
@@ -4231,21 +4278,21 @@ async function runInstallWithPriority(config, packages, onLogLine) {
4231
4278
  let lastError = void 0;
4232
4279
  for (const strategy of strategies) {
4233
4280
  try {
4234
- log("info", { event: "deps.install.strategy.try", details: { strategy: strategy.name, packages } });
4281
+ depsStructuredLog("info", { event: "deps.install.strategy.try", details: { strategy: strategy.name, packages } });
4235
4282
  await strategy.run();
4236
- log("info", { event: "deps.install.strategy.ok", details: { strategy: strategy.name } });
4283
+ depsStructuredLog("info", { event: "deps.install.strategy.ok", details: { strategy: strategy.name } });
4237
4284
  progress("packages.install.done", { strategy: strategy.name });
4238
4285
  return;
4239
4286
  } catch (error) {
4240
4287
  lastError = error;
4241
- log("warn", {
4288
+ depsStructuredLog("warn", {
4242
4289
  event: "deps.install.strategy.fail",
4243
4290
  details: { strategy: strategy.name, message: error instanceof Error ? error.message : String(error) }
4244
4291
  });
4245
4292
  }
4246
4293
  }
4247
- throw new Error(
4248
- `Dependency install failed after all strategies: ${lastError instanceof Error ? lastError.message : String(lastError)}`
4294
+ onLogLine?.(
4295
+ `[deps][warn] \u5305\u5B89\u88C5\u672A\u6210\u529F\uFF08${specs.join(" ")}\uFF09: ${briefErrorMessage(lastError)}\uFF1BMCP \u4ECD\u5C06\u542F\u52A8\uFF0C\u53EF\u7A0D\u540E\u91CD\u8BD5\u6216\u914D\u7F6E registry`
4249
4296
  );
4250
4297
  }
4251
4298
  async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
@@ -4280,12 +4327,12 @@ async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
4280
4327
  ];
4281
4328
  for (const strategy of strategies) {
4282
4329
  try {
4283
- log("info", {
4330
+ depsStructuredLog("info", {
4284
4331
  event: "appium.driver.install.strategy.try",
4285
4332
  details: { strategy: strategy.name, driver, target }
4286
4333
  });
4287
4334
  await strategy.run();
4288
- log("info", {
4335
+ depsStructuredLog("info", {
4289
4336
  event: "appium.driver.install.strategy.ok",
4290
4337
  details: { strategy: strategy.name, driver, target }
4291
4338
  });
@@ -4293,7 +4340,7 @@ async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
4293
4340
  return;
4294
4341
  } catch (error) {
4295
4342
  lastError = error;
4296
- log("warn", {
4343
+ depsStructuredLog("warn", {
4297
4344
  event: "appium.driver.install.strategy.fail",
4298
4345
  details: {
4299
4346
  strategy: strategy.name,
@@ -4310,16 +4357,23 @@ async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
4310
4357
  );
4311
4358
  }
4312
4359
  async function verifyPlaywrightSelfTest(onLogLine) {
4313
- onLogLine?.("[playwright] \u81EA\u68C0\uFF1A\u542F\u52A8 Chromium \u7A7A\u767D\u9875");
4314
- const moduleName = ["play", "wright"].join("");
4315
- const p = require2(moduleName);
4316
- const b = await p.chromium.launch({ headless: true });
4360
+ onLogLine?.("[playwright] \u81EA\u68C0\uFF1A\u542F\u52A8 Chromium");
4317
4361
  try {
4318
- const c = await b.newContext();
4319
- const page = await c.newPage();
4320
- await page.goto("about:blank");
4321
- } finally {
4322
- await b.close();
4362
+ const moduleName = ["play", "wright"].join("");
4363
+ const p = require2(moduleName);
4364
+ const b = await p.chromium.launch({ headless: true });
4365
+ try {
4366
+ const c = await b.newContext();
4367
+ const page = await c.newPage();
4368
+ await page.goto("about:blank");
4369
+ } finally {
4370
+ await b.close();
4371
+ }
4372
+ onLogLine?.("[playwright] \u81EA\u68C0\u901A\u8FC7");
4373
+ return true;
4374
+ } catch (error) {
4375
+ onLogLine?.(`[playwright][warn] \u81EA\u68C0\u672A\u901A\u8FC7: ${briefErrorMessage(error)}`);
4376
+ return false;
4323
4377
  }
4324
4378
  }
4325
4379
  async function installPlaywrightBrowser(config, onLogLine, options) {
@@ -4343,36 +4397,45 @@ async function installPlaywrightBrowser(config, onLogLine, options) {
4343
4397
  const rankedHosts = await rankPlaywrightHosts(config);
4344
4398
  const timeoutMs = playwrightInstallTimeoutMs();
4345
4399
  onLogLine?.(`[playwright] \u5B89\u88C5\u8D85\u65F6\u4E0A\u9650 ${Math.round(timeoutMs / 1e3)}s\uFF08\u53EF\u7528 ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS \u8C03\u6574\uFF09`);
4346
- let lastError;
4400
+ let lastHost = "";
4347
4401
  for (let i = 0; i < rankedHosts.length; i++) {
4348
4402
  const host = rankedHosts[i];
4403
+ lastHost = host;
4349
4404
  if (i > 0) {
4350
- onLogLine?.(`[playwright] \u4E0A\u4E00\u955C\u50CF\u5931\u8D25\uFF0C\u6539\u8BD5 ${host}`);
4405
+ onLogLine?.(`[playwright] \u6362\u955C\u50CF: ${host}`);
4406
+ } else {
4407
+ onLogLine?.(
4408
+ `[playwright] playwright@${version}\uFF0CCDN ${host}\uFF0C\u76EE\u6807 ${targets.length ? targets.join(",") : "chromium"}`
4409
+ );
4351
4410
  }
4352
- onLogLine?.(
4353
- `[playwright] \u4F7F\u7528\u5185\u7F6E playwright@${version} CLI\uFF0C\u955C\u50CF ${host}\uFF0C\u76EE\u6807: ${targets.length ? targets.join(",") : "all"}${options?.force ? " (--force)" : ""}`
4354
- );
4355
4411
  try {
4356
4412
  await runCommand2(command, installArgs, {
4357
4413
  env: { PLAYWRIGHT_DOWNLOAD_HOST: host },
4358
4414
  timeoutMs,
4359
- onLogLine
4415
+ onLogLine: createPlaywrightInstallLogSink(onLogLine)
4360
4416
  });
4361
4417
  progress("playwright.browser.install.done", { selectedHost: host, attempt: i + 1 });
4362
- return;
4418
+ onLogLine?.(`[playwright] \u6D4F\u89C8\u5668\u5B89\u88C5\u5B8C\u6210\uFF08${host}\uFF09`);
4419
+ return true;
4363
4420
  } catch (error) {
4364
- lastError = error;
4365
- log("warn", {
4421
+ onLogLine?.(`[playwright][warn] \u955C\u50CF ${host} \u5931\u8D25: ${briefErrorMessage(error)}`);
4422
+ depsStructuredLog("warn", {
4366
4423
  event: "deps.playwright.browser.install.host.fail",
4367
4424
  details: {
4368
4425
  host,
4369
4426
  attempt: i + 1,
4370
- message: error instanceof Error ? error.message : String(error)
4427
+ message: briefErrorMessage(error)
4371
4428
  }
4372
4429
  });
4373
4430
  }
4374
4431
  }
4375
- throw lastError instanceof Error ? lastError : new Error(String(lastError ?? "playwright browser install failed"));
4432
+ onLogLine?.(
4433
+ `[playwright][warn] \u6D4F\u89C8\u5668\u672A\u5B89\u88C5\u5B8C\u6210\uFF08\u5DF2\u5C1D\u8BD5 ${rankedHosts.length} \u4E2A CDN\uFF09\u3002\u53EF\u8BBE\u7F6E PLAYWRIGHT_DOWNLOAD_HOST=https://cdn.playwright.dev \u540E\u91CD\u8BD5\uFF0C\u6216\u6267\u884C: npx playwright@${PINNED_PLAYWRIGHT_VERSION} install chromium`
4434
+ );
4435
+ if (lastHost) {
4436
+ onLogLine?.(`[playwright][warn] \u6700\u540E\u5C1D\u8BD5: ${lastHost}`);
4437
+ }
4438
+ return false;
4376
4439
  }
4377
4440
  async function checkPlaywrightLaunchable() {
4378
4441
  try {
@@ -4477,7 +4540,6 @@ async function ensureSeleniumNativeDrivers(config, options, onLogLine) {
4477
4540
  }
4478
4541
  const geckoVer = options?.geckodriverVersion ?? config.dependencies.geckodriverVersion ?? "latest";
4479
4542
  const chromeVer = options?.chromedriverVersion ?? config.dependencies.chromedriverVersion ?? "latest";
4480
- onLogLine?.("[selenium] \u5C06\u68C0\u6D4B\u672C\u673A Chrome/Firefox \u7248\u672C\u5E76\u5C1D\u8BD5\u5339\u914D\u9A71\u52A8\uFF1B\u4E0B\u8F7D\u5931\u8D25\u65F6\u8DF3\u8FC7\u5E76\u63D0\u793A\u624B\u52A8\u4E0B\u8F7D\uFF08\u89C1\u5B89\u88C5\u65E5\u5FD7\u53C2\u8003\u5730\u5740\uFF09\u3002");
4481
4543
  try {
4482
4544
  const catalog = await listChromedriverCfTVersions();
4483
4545
  onLogLine?.(
@@ -4616,6 +4678,28 @@ async function saveInstallState(state) {
4616
4678
  await import_promises5.default.writeFile(file, JSON.stringify(state, null, 2), "utf8");
4617
4679
  }
4618
4680
  async function ensureDriverDependencies(config, options) {
4681
+ const previousHumanLog = depsHumanLog;
4682
+ depsHumanLog = options?.onLogLine;
4683
+ try {
4684
+ return await ensureDriverDependenciesImpl(config, options);
4685
+ } catch (error) {
4686
+ options?.onLogLine?.(`[deps][warn] \u4F9D\u8D56\u5B89\u88C5\u5F02\u5E38\u5DF2\u5FFD\u7565: ${briefErrorMessage(error)}`);
4687
+ const only = options?.only ?? "all";
4688
+ return {
4689
+ scope: only,
4690
+ force: options?.force ?? false,
4691
+ elapsedMs: 0,
4692
+ requestedDrivers: [],
4693
+ installedPackages: [],
4694
+ skippedPackages: [],
4695
+ installedDrivers: [],
4696
+ skippedDrivers: []
4697
+ };
4698
+ } finally {
4699
+ depsHumanLog = previousHumanLog;
4700
+ }
4701
+ }
4702
+ async function ensureDriverDependenciesImpl(config, options) {
4619
4703
  const startedAt = Date.now();
4620
4704
  const only = options?.only ?? "all";
4621
4705
  const force = options?.force === true;
@@ -4656,12 +4740,12 @@ async function ensureDriverDependencies(config, options) {
4656
4740
  }
4657
4741
  if (packagesToInstall.length > 0) {
4658
4742
  progress("deps.package.missing", { missing, installing: packagesToInstall });
4659
- log("warn", { event: "deps.missing", details: { missing, installing: packagesToInstall } });
4743
+ onLogLine?.(`[deps] \u5C06\u5B89\u88C5: ${packagesToInstall.join(", ")}`);
4660
4744
  await runInstallWithPriority(config, packagesToInstall, onLogLine);
4661
4745
  installedPackages.push(...packagesToInstall);
4662
4746
  } else {
4663
4747
  progress("deps.package.ok", { missing: [] });
4664
- log("info", { event: "deps.check.ok", details: { missing: [] } });
4748
+ depsStructuredLog("info", { event: "deps.check.ok", details: { missing: [] } });
4665
4749
  }
4666
4750
  if (hasPackage("playwright") && needPlaywright) {
4667
4751
  progress("playwright.selfcheck.start");
@@ -4669,7 +4753,7 @@ async function ensureDriverDependencies(config, options) {
4669
4753
  const reinstallForTargets = force && Boolean(pwOverride?.length);
4670
4754
  const userRequestedBrowserTargets = Boolean(pwOverride?.length);
4671
4755
  if (!launchOk || reinstallForTargets || userRequestedBrowserTargets || force) {
4672
- log("warn", {
4756
+ depsStructuredLog("warn", {
4673
4757
  event: "deps.playwright.browser.missing",
4674
4758
  details: {
4675
4759
  action: "install-playwright-browser",
@@ -4682,19 +4766,21 @@ async function ensureDriverDependencies(config, options) {
4682
4766
  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"
4683
4767
  );
4684
4768
  }
4685
- await installPlaywrightBrowser(configForPlaywright, onLogLine, {
4769
+ const browserInstalled = await installPlaywrightBrowser(configForPlaywright, onLogLine, {
4686
4770
  force: force || reinstallForTargets || !launchOk
4687
4771
  });
4688
- progress("playwright.selfcheck.verify");
4689
- await verifyPlaywrightSelfTest(onLogLine);
4690
- state.playwrightReady = true;
4691
- progress("playwright.selfcheck.done");
4772
+ if (browserInstalled) {
4773
+ progress("playwright.selfcheck.verify");
4774
+ state.playwrightReady = await verifyPlaywrightSelfTest(onLogLine);
4775
+ progress("playwright.selfcheck.done");
4776
+ } else {
4777
+ state.playwrightReady = false;
4778
+ }
4692
4779
  } else if (!force && state.playwrightReady) {
4693
4780
  progress("playwright.selfcheck.skip.cache", { cached: true, healthy: true });
4694
4781
  } else {
4695
4782
  progress("playwright.selfcheck.verify");
4696
- await verifyPlaywrightSelfTest(onLogLine);
4697
- state.playwrightReady = true;
4783
+ state.playwrightReady = await verifyPlaywrightSelfTest(onLogLine);
4698
4784
  progress("playwright.selfcheck.done");
4699
4785
  }
4700
4786
  }
@@ -4708,12 +4794,16 @@ async function ensureDriverDependencies(config, options) {
4708
4794
  progress("selenium.check.done", sel);
4709
4795
  }
4710
4796
  if (hasPackage("appium") && needAppium) {
4711
- progress("appium.selfcheck.start");
4712
- await verifyAppiumCommand();
4713
- if (!force && state.appiumReady) {
4714
- progress("appium.selfcheck.skip.cache", { cached: true, healthy: true });
4715
- } else {
4716
- state.appiumReady = true;
4797
+ try {
4798
+ progress("appium.selfcheck.start");
4799
+ await verifyAppiumCommand();
4800
+ if (!force && state.appiumReady) {
4801
+ progress("appium.selfcheck.skip.cache", { cached: true, healthy: true });
4802
+ } else {
4803
+ state.appiumReady = true;
4804
+ }
4805
+ } catch (error) {
4806
+ onLogLine?.(`[appium][warn] ${briefErrorMessage(error)}`);
4717
4807
  }
4718
4808
  }
4719
4809
  if (hasPackage("appium") && needDrivers) {
@@ -4732,11 +4822,15 @@ async function ensureDriverDependencies(config, options) {
4732
4822
  requiredDrivers: required
4733
4823
  }
4734
4824
  };
4735
- await ensureAppiumDrivers(scopedConfig, onLogLine);
4736
- installedDrivers.push(...missingBefore);
4737
- skippedDrivers.push(...required.filter((x) => !missingBefore.includes(x)));
4738
- state.driversReady = true;
4739
- progress("appium.driver.ensure.done");
4825
+ try {
4826
+ await ensureAppiumDrivers(scopedConfig, onLogLine);
4827
+ installedDrivers.push(...missingBefore);
4828
+ skippedDrivers.push(...required.filter((x) => !missingBefore.includes(x)));
4829
+ state.driversReady = true;
4830
+ progress("appium.driver.ensure.done");
4831
+ } catch (error) {
4832
+ onLogLine?.(`[appium][warn] \u9A71\u52A8\u5B89\u88C5\u672A\u5B8C\u6210: ${briefErrorMessage(error)}`);
4833
+ }
4740
4834
  }
4741
4835
  }
4742
4836
  state.androidHome = homes.androidHome;
@@ -4744,7 +4838,7 @@ async function ensureDriverDependencies(config, options) {
4744
4838
  await saveInstallState(state);
4745
4839
  const installedPkgs = Array.from(new Set(installedPackages));
4746
4840
  progress("deps.ensure.done", { installedPackages: installedPkgs, missingDetected: missing });
4747
- log("info", { event: "deps.install.completed", details: { installedPackages: installedPkgs } });
4841
+ depsStructuredLog("info", { event: "deps.install.completed", details: { installedPackages: installedPkgs } });
4748
4842
  const requestedPackages = ["playwright", "appium"].filter((pkg) => pkg === "playwright" ? needPlaywright : needAppium);
4749
4843
  let nativeDriversDir;
4750
4844
  let geckodriverPath;
@@ -4828,7 +4922,7 @@ async function getDependencyHealth(config) {
4828
4922
  missingAppiumDrivers
4829
4923
  };
4830
4924
  }
4831
- var import_node_module, import_node_fs, import_node_child_process2, import_promises5, import_node_path5, require2, DEFAULT_NPM_REGISTRY_CANDIDATES, detectedBestRegistryByKey, PROGRESS_STEPS, DEFAULT_PLAYWRIGHT_HOST_CANDIDATES, PLAYWRIGHT_HOST_FALLBACK, PW_INSTALL_TARGETS;
4925
+ var import_node_module, import_node_fs, import_node_child_process2, import_promises5, import_node_path5, require2, PINNED_PLAYWRIGHT_VERSION, depsHumanLog, DEFAULT_NPM_REGISTRY_CANDIDATES, detectedBestRegistryByKey, PROGRESS_STEPS, PROGRESS_HUMAN_LABELS, DEFAULT_PLAYWRIGHT_HOST_CANDIDATES, PLAYWRIGHT_HOST_FALLBACK, PW_INSTALL_TARGETS;
4832
4926
  var init_dependency_installer = __esm({
4833
4927
  "../ada-agent/src/dependency-installer.ts"() {
4834
4928
  import_node_module = require("node:module");
@@ -4840,6 +4934,7 @@ var init_dependency_installer = __esm({
4840
4934
  init_config();
4841
4935
  init_src2();
4842
4936
  require2 = (0, import_node_module.createRequire)(import_node_path5.default.join(process.cwd(), "package.json"));
4937
+ PINNED_PLAYWRIGHT_VERSION = "1.59.1";
4843
4938
  DEFAULT_NPM_REGISTRY_CANDIDATES = [
4844
4939
  "https://registry.npmmirror.com",
4845
4940
  "https://mirrors.cloud.tencent.com/npm",
@@ -4856,6 +4951,15 @@ var init_dependency_installer = __esm({
4856
4951
  "appium.driver.ensure.start",
4857
4952
  "deps.ensure.done"
4858
4953
  ];
4954
+ PROGRESS_HUMAN_LABELS = {
4955
+ "deps.ensure.start": "[deps] \u5F00\u59CB\u68C0\u6D4B\u4F9D\u8D56",
4956
+ "registry.probe.start": "[deps] \u63A2\u6D4B npm \u955C\u50CF\u2026",
4957
+ "packages.install.start": "[deps] \u5B89\u88C5 npm \u5305\u2026",
4958
+ "playwright.host.probe.start": "[playwright] \u63A2\u6D4B\u6D4F\u89C8\u5668 CDN\u2026",
4959
+ "playwright.browser.install.start": "[playwright] \u5B89\u88C5\u6D4F\u89C8\u5668\u2026",
4960
+ "appium.driver.ensure.start": "[appium] \u5B89\u88C5\u9A71\u52A8\u2026",
4961
+ "deps.ensure.done": "[deps] \u4F9D\u8D56\u68C0\u6D4B\u5B8C\u6210"
4962
+ };
4859
4963
  DEFAULT_PLAYWRIGHT_HOST_CANDIDATES = [
4860
4964
  "https://cdn.playwright.dev",
4861
4965
  "https://playwright.azureedge.net",
@@ -9408,9 +9512,15 @@ async function runBootstrapInstallDeps(argv2) {
9408
9512
  console.error(`[ADA-MCP] dependency bootstrap start (scope=${label}, force=${plan.force})`);
9409
9513
  for (const scope of plan.scopes) {
9410
9514
  console.error(`[ADA-MCP] installing: ${scope}`);
9411
- await installDependencies(scope, plan.force, (line) => {
9412
- console.error(`[ADA-MCP] ${line}`);
9413
- }, plan.extras);
9515
+ try {
9516
+ await installDependencies(scope, plan.force, (line) => {
9517
+ console.error(`[ADA-MCP] ${line}`);
9518
+ }, plan.extras);
9519
+ } catch (error) {
9520
+ const msg = error instanceof Error ? error.message.split(/\r?\n/)[0] : String(error);
9521
+ console.error(`[ADA-MCP][warn] ${scope} \u4F9D\u8D56\u5B89\u88C5\u672A\u5B8C\u6210: ${msg}`);
9522
+ console.error("[ADA-MCP][warn] MCP \u4ECD\u5C06\u542F\u52A8\uFF1B\u53EF\u8BBE\u7F6E PLAYWRIGHT_DOWNLOAD_HOST=https://cdn.playwright.dev \u6216 --skip-install-deps");
9523
+ }
9414
9524
  }
9415
9525
  console.error("[ADA-MCP] dependency bootstrap done");
9416
9526
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ada-mcp/mcp-server",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "ADA MCP server for web/mobile automation (stdio + remote HTTP)",
5
5
  "private": false,
6
6
  "type": "commonjs",