@ada-mcp/mcp-server 0.1.14 → 0.1.15
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.md +139 -139
- package/dist/cli.cjs +278 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,139 +1,139 @@
|
|
|
1
|
-
# @ada-mcp/mcp-server
|
|
2
|
-
|
|
3
|
-
ADA MCP server package that supports:
|
|
4
|
-
|
|
5
|
-
- Local stdio mode (default) for MCP hosts
|
|
6
|
-
- Remote HTTP mode (`server`) with API key authentication
|
|
7
|
-
- MCP **Streamable HTTP** on `POST|GET|DELETE /mcp` (same port as legacy REST), with optional SSE per MCP spec (`@modelcontextprotocol/sdk` transport)
|
|
8
|
-
|
|
9
|
-
## 标准安装(Cursor / MCP)
|
|
10
|
-
|
|
11
|
-
请使用 **`@ada-mcp/launcher@0.1.
|
|
12
|
-
|
|
13
|
-
```json
|
|
14
|
-
{
|
|
15
|
-
"mcpServers": {
|
|
16
|
-
"ada-mcp": {
|
|
17
|
-
"command": "pnpm",
|
|
18
|
-
"args": ["dlx", "@ada-mcp/launcher@0.1.
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
本包版本:**`@ada-mcp/mcp-server@0.1.
|
|
25
|
-
|
|
26
|
-
直接调试本包(无 launcher 拉包前测速):
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
pnpm dlx @ada-mcp/mcp-server@0.1.
|
|
30
|
-
# npx 等价:
|
|
31
|
-
npx -y @ada-mcp/mcp-server@0.1.
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## 启动时自动安装依赖(默认仅 Playwright)
|
|
35
|
-
|
|
36
|
-
进程启动前会按配置自动执行 `install-deps`(日志在 stderr):
|
|
37
|
-
|
|
38
|
-
| 配置 | 含义 |
|
|
39
|
-
|------|------|
|
|
40
|
-
| (未配置) | 仅安装 **Playwright + 浏览器** |
|
|
41
|
-
| `playwright` | 仅 Playwright(显式写法,与默认相同) |
|
|
42
|
-
| `selenium` | **仅** Selenium 原生驱动(GeckoDriver/ChromeDriver) |
|
|
43
|
-
| `appium` | **仅** Appium 包 + 移动端驱动 |
|
|
44
|
-
| `playwright,selenium` | 组合(逗号连接多类) |
|
|
45
|
-
| `all` | 上述全部 |
|
|
46
|
-
| `none` / `skip` | 不自动安装 |
|
|
47
|
-
|
|
48
|
-
**环境变量**
|
|
49
|
-
|
|
50
|
-
- `ADA_MCP_INSTALL_DEPS`:范围,如 `playwright`、`playwright,selenium`、`all`、`none`
|
|
51
|
-
- `ADA_MCP_SKIP_INSTALL_DEPS=1`:跳过自动安装
|
|
52
|
-
- `ADA_MCP_INSTALL_DEPS_FORCE=1`:强制重装
|
|
53
|
-
- `ADA_MCP_GECKODRIVER_VERSION` / `ADA_MCP_CHROMEDRIVER_VERSION`:Selenium 驱动版本
|
|
54
|
-
- `ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS`:浏览器下载超时(默认 15 分钟)
|
|
55
|
-
- `ADA_INSTALL_STRATEGY_TIMEOUT_MS`:npm 装包超时(默认 2 分钟)
|
|
56
|
-
|
|
57
|
-
## 代理与镜像(`0.1.10+` 推荐)
|
|
58
|
-
|
|
59
|
-
| 阶段 | 自动探测最快镜像 |
|
|
60
|
-
|------|------------------|
|
|
61
|
-
| `pnpm dlx @ada-mcp/launcher` | **是** — 拉包前测速(推荐) |
|
|
62
|
-
| `pnpm dlx @ada-mcp/mcp-server` | tarball 仍走本机源;**同次安装的依赖**由 `preinstall` 测速(仅写入官方 Playwright CDN,`0.1.9+`) |
|
|
63
|
-
| 启动后 `install-deps` | 是 — 内置国内镜像测速(**无需配置**) |
|
|
64
|
-
|
|
65
|
-
默认 npm 探测候选(按优先级,延迟相同取靠前):阿里云 npmmirror → 腾讯云 → 华为云 → npm 官方。
|
|
66
|
-
|
|
67
|
-
| 变量 | 说明 |
|
|
68
|
-
|------|------|
|
|
69
|
-
| `npm_config_registry` | 可选;仅加速 **dlx** 拉包(推荐 `https://registry.npmmirror.com`) |
|
|
70
|
-
| `ADA_REGISTRY_CANDIDATES` | 可选;在默认五镜像**之外**追加候选 |
|
|
71
|
-
| `ADA_NPM_PROXY_REGISTRY` / `ADA_PNPM_PROXY_REGISTRY` | 可选;覆盖探测主候选(默认 npmmirror) |
|
|
72
|
-
| `PLAYWRIGHT_DOWNLOAD_HOST` | 可选;Playwright 浏览器 CDN |
|
|
73
|
-
|
|
74
|
-
详见 [ADA-MCP-接入手册 §3.9.2](../../docs/ADA-MCP-接入手册.md#392-代理与镜像配置)。
|
|
75
|
-
|
|
76
|
-
**CLI 参数**(写在 MCP `args` 末尾)
|
|
77
|
-
|
|
78
|
-
- `--install-deps=playwright,selenium`
|
|
79
|
-
- `--skip-install-deps`
|
|
80
|
-
- `--install-deps-force`
|
|
81
|
-
- `--geckodriver-version=latest` `--chromedriver-version=match-chrome`
|
|
82
|
-
|
|
83
|
-
在标准 `args` 后追加,例如安装全部依赖:
|
|
84
|
-
|
|
85
|
-
```json
|
|
86
|
-
"args": ["dlx", "@ada-mcp/launcher@0.1.
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Cursor MCP 配置
|
|
90
|
-
|
|
91
|
-
**pnpm(推荐)**:`pnpm` + `dlx @ada-mcp/launcher@0.1.
|
|
92
|
-
|
|
93
|
-
**npx 等价**(`launcher@0.1.7+`):`npx` + `-y @ada-mcp/launcher@0.1.
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{
|
|
97
|
-
"mcpServers": {
|
|
98
|
-
"ada-mcp": {
|
|
99
|
-
"command": "npx",
|
|
100
|
-
"args": ["-y", "@ada-mcp/launcher@0.1.
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Windows 若找不到 `pnpm`,可将 `command` 改为 `pnpm.cmd` 绝对路径;无 pnpm 时只能直接 `npx -y @ada-mcp/mcp-server@0.1.
|
|
107
|
-
|
|
108
|
-
## Remote mode
|
|
109
|
-
|
|
110
|
-
Set API key in environment variable first:
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
export ADA_MCP_REMOTE_API_KEY=your_token
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Windows PowerShell:
|
|
117
|
-
|
|
118
|
-
```powershell
|
|
119
|
-
$env:ADA_MCP_REMOTE_API_KEY="your_token"
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Then run:
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
pnpm dlx @ada-mcp/mcp-server server --host=127.0.0.1 --port=8787 --allow-risky=true --risky-mode=whitelist --risky-commands=custom
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Streamable HTTP (`/mcp`)
|
|
129
|
-
|
|
130
|
-
- Endpoint: `http://<host>:<port>/mcp` — same API key headers as below (`x-api-key` or `Authorization: Bearer`).
|
|
131
|
-
- First request: `POST /mcp` with JSON-RPC `initialize` (no `Mcp-Session-Id`); server returns a session id in `Mcp-Session-Id` response header.
|
|
132
|
-
- Follow-up: `POST /mcp` with body + `Mcp-Session-Id`; for server-initiated streaming, open `GET /mcp` with `Accept: text/event-stream` and the same session header.
|
|
133
|
-
- Session teardown: `DELETE /mcp` with `Mcp-Session-Id`.
|
|
134
|
-
|
|
135
|
-
When listening on all interfaces (e.g. `--host=0.0.0.0`), set allowed Host headers to satisfy DNS rebinding checks:
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
pnpm dlx @ada-mcp/mcp-server server --host=0.0.0.0 --port=8787 --api-key=your_token --allowed-hosts=localhost,127.0.0.1
|
|
139
|
-
```
|
|
1
|
+
# @ada-mcp/mcp-server
|
|
2
|
+
|
|
3
|
+
ADA MCP server package that supports:
|
|
4
|
+
|
|
5
|
+
- Local stdio mode (default) for MCP hosts
|
|
6
|
+
- Remote HTTP mode (`server`) with API key authentication
|
|
7
|
+
- MCP **Streamable HTTP** on `POST|GET|DELETE /mcp` (same port as legacy REST), with optional SSE per MCP spec (`@modelcontextprotocol/sdk` transport)
|
|
8
|
+
|
|
9
|
+
## 标准安装(Cursor / MCP)
|
|
10
|
+
|
|
11
|
+
请使用 **`@ada-mcp/launcher@0.1.12`** 拉起本包(见 [launcher README](../ada-mcp-launcher/README.md)):
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"ada-mcp": {
|
|
17
|
+
"command": "pnpm",
|
|
18
|
+
"args": ["dlx", "@ada-mcp/launcher@0.1.12"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
本包版本:**`@ada-mcp/mcp-server@0.1.15`**(由 launcher 默认拉取;依赖锁定 `playwright@1.59.1`)。
|
|
25
|
+
|
|
26
|
+
直接调试本包(无 launcher 拉包前测速):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm dlx @ada-mcp/mcp-server@0.1.15
|
|
30
|
+
# npx 等价:
|
|
31
|
+
npx -y @ada-mcp/mcp-server@0.1.15
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 启动时自动安装依赖(默认仅 Playwright)
|
|
35
|
+
|
|
36
|
+
进程启动前会按配置自动执行 `install-deps`(日志在 stderr):
|
|
37
|
+
|
|
38
|
+
| 配置 | 含义 |
|
|
39
|
+
|------|------|
|
|
40
|
+
| (未配置) | 仅安装 **Playwright + 浏览器** |
|
|
41
|
+
| `playwright` | 仅 Playwright(显式写法,与默认相同) |
|
|
42
|
+
| `selenium` | **仅** Selenium 原生驱动(GeckoDriver/ChromeDriver) |
|
|
43
|
+
| `appium` | **仅** Appium 包 + 移动端驱动 |
|
|
44
|
+
| `playwright,selenium` | 组合(逗号连接多类) |
|
|
45
|
+
| `all` | 上述全部 |
|
|
46
|
+
| `none` / `skip` | 不自动安装 |
|
|
47
|
+
|
|
48
|
+
**环境变量**
|
|
49
|
+
|
|
50
|
+
- `ADA_MCP_INSTALL_DEPS`:范围,如 `playwright`、`playwright,selenium`、`all`、`none`
|
|
51
|
+
- `ADA_MCP_SKIP_INSTALL_DEPS=1`:跳过自动安装
|
|
52
|
+
- `ADA_MCP_INSTALL_DEPS_FORCE=1`:强制重装
|
|
53
|
+
- `ADA_MCP_GECKODRIVER_VERSION` / `ADA_MCP_CHROMEDRIVER_VERSION`:Selenium 驱动版本
|
|
54
|
+
- `ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS`:浏览器下载超时(默认 15 分钟)
|
|
55
|
+
- `ADA_INSTALL_STRATEGY_TIMEOUT_MS`:npm 装包超时(默认 2 分钟)
|
|
56
|
+
|
|
57
|
+
## 代理与镜像(`0.1.10+` 推荐)
|
|
58
|
+
|
|
59
|
+
| 阶段 | 自动探测最快镜像 |
|
|
60
|
+
|------|------------------|
|
|
61
|
+
| `pnpm dlx @ada-mcp/launcher` | **是** — 拉包前测速(推荐) |
|
|
62
|
+
| `pnpm dlx @ada-mcp/mcp-server` | tarball 仍走本机源;**同次安装的依赖**由 `preinstall` 测速(仅写入官方 Playwright CDN,`0.1.9+`) |
|
|
63
|
+
| 启动后 `install-deps` | 是 — 内置国内镜像测速(**无需配置**) |
|
|
64
|
+
|
|
65
|
+
默认 npm 探测候选(按优先级,延迟相同取靠前):阿里云 npmmirror → 腾讯云 → 华为云 → npm 官方。
|
|
66
|
+
|
|
67
|
+
| 变量 | 说明 |
|
|
68
|
+
|------|------|
|
|
69
|
+
| `npm_config_registry` | 可选;仅加速 **dlx** 拉包(推荐 `https://registry.npmmirror.com`) |
|
|
70
|
+
| `ADA_REGISTRY_CANDIDATES` | 可选;在默认五镜像**之外**追加候选 |
|
|
71
|
+
| `ADA_NPM_PROXY_REGISTRY` / `ADA_PNPM_PROXY_REGISTRY` | 可选;覆盖探测主候选(默认 npmmirror) |
|
|
72
|
+
| `PLAYWRIGHT_DOWNLOAD_HOST` | 可选;Playwright 浏览器 CDN |
|
|
73
|
+
|
|
74
|
+
详见 [ADA-MCP-接入手册 §3.9.2](../../docs/ADA-MCP-接入手册.md#392-代理与镜像配置)。
|
|
75
|
+
|
|
76
|
+
**CLI 参数**(写在 MCP `args` 末尾)
|
|
77
|
+
|
|
78
|
+
- `--install-deps=playwright,selenium`
|
|
79
|
+
- `--skip-install-deps`
|
|
80
|
+
- `--install-deps-force`
|
|
81
|
+
- `--geckodriver-version=latest` `--chromedriver-version=match-chrome`
|
|
82
|
+
|
|
83
|
+
在标准 `args` 后追加,例如安装全部依赖:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
"args": ["dlx", "@ada-mcp/launcher@0.1.12", "--install-deps=all"]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Cursor MCP 配置
|
|
90
|
+
|
|
91
|
+
**pnpm(推荐)**:`pnpm` + `dlx @ada-mcp/launcher@0.1.12`
|
|
92
|
+
|
|
93
|
+
**npx 等价**(`launcher@0.1.7+`):`npx` + `-y @ada-mcp/launcher@0.1.12`(内层同样 `npx -y` mcp-server,测速逻辑与 pnpm 一致)
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"ada-mcp": {
|
|
99
|
+
"command": "npx",
|
|
100
|
+
"args": ["-y", "@ada-mcp/launcher@0.1.12"]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Windows 若找不到 `pnpm`,可将 `command` 改为 `pnpm.cmd` 绝对路径;无 pnpm 时只能直接 `npx -y @ada-mcp/mcp-server@0.1.15`(无 launcher 拉包测速)。
|
|
107
|
+
|
|
108
|
+
## Remote mode
|
|
109
|
+
|
|
110
|
+
Set API key in environment variable first:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
export ADA_MCP_REMOTE_API_KEY=your_token
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Windows PowerShell:
|
|
117
|
+
|
|
118
|
+
```powershell
|
|
119
|
+
$env:ADA_MCP_REMOTE_API_KEY="your_token"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Then run:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pnpm dlx @ada-mcp/mcp-server server --host=127.0.0.1 --port=8787 --allow-risky=true --risky-mode=whitelist --risky-commands=custom
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Streamable HTTP (`/mcp`)
|
|
129
|
+
|
|
130
|
+
- Endpoint: `http://<host>:<port>/mcp` — same API key headers as below (`x-api-key` or `Authorization: Bearer`).
|
|
131
|
+
- First request: `POST /mcp` with JSON-RPC `initialize` (no `Mcp-Session-Id`); server returns a session id in `Mcp-Session-Id` response header.
|
|
132
|
+
- Follow-up: `POST /mcp` with body + `Mcp-Session-Id`; for server-initiated streaming, open `GET /mcp` with `Accept: text/event-stream` and the same session header.
|
|
133
|
+
- Session teardown: `DELETE /mcp` with `Mcp-Session-Id`.
|
|
134
|
+
|
|
135
|
+
When listening on all interfaces (e.g. `--host=0.0.0.0`), set allowed Host headers to satisfy DNS rebinding checks:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pnpm dlx @ada-mcp/mcp-server server --host=0.0.0.0 --port=8787 --api-key=your_token --allowed-hosts=localhost,127.0.0.1
|
|
139
|
+
```
|
package/dist/cli.cjs
CHANGED
|
@@ -2887,7 +2887,7 @@ var init_config = __esm({
|
|
|
2887
2887
|
],
|
|
2888
2888
|
nativeDriversDir: "dirver",
|
|
2889
2889
|
geckodriverVersion: "latest",
|
|
2890
|
-
chromedriverVersion: "
|
|
2890
|
+
chromedriverVersion: "match-chrome"
|
|
2891
2891
|
},
|
|
2892
2892
|
appium: {
|
|
2893
2893
|
serverUrl: "http://127.0.0.1:4723",
|
|
@@ -3277,30 +3277,171 @@ async function resolveChromedriverCfTVersion(requested) {
|
|
|
3277
3277
|
}
|
|
3278
3278
|
return hit.version;
|
|
3279
3279
|
}
|
|
3280
|
-
|
|
3281
|
-
|
|
3280
|
+
function parseBrowserVersionString(raw) {
|
|
3281
|
+
const match = raw.match(/(\d+\.\d+(?:\.\d+)*(?:\.\d+)?)/);
|
|
3282
|
+
if (!match) {
|
|
3282
3283
|
return void 0;
|
|
3283
3284
|
}
|
|
3284
|
-
const
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
"
|
|
3291
|
-
|
|
3292
|
-
)
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3285
|
+
const version = match[1];
|
|
3286
|
+
return { version, major: version.split(".")[0] };
|
|
3287
|
+
}
|
|
3288
|
+
async function runCommandCapture(command, args) {
|
|
3289
|
+
return new Promise((resolve) => {
|
|
3290
|
+
const child = (0, import_node_child_process.spawn)(command, args, {
|
|
3291
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
3292
|
+
shell: process.platform === "win32"
|
|
3293
|
+
});
|
|
3294
|
+
let out = "";
|
|
3295
|
+
child.stdout?.on("data", (chunk) => {
|
|
3296
|
+
out += chunk.toString("utf8");
|
|
3297
|
+
});
|
|
3298
|
+
child.on("exit", (code) => resolve(code === 0 ? out.trim() : void 0));
|
|
3299
|
+
child.on("error", () => resolve(void 0));
|
|
3300
|
+
});
|
|
3301
|
+
}
|
|
3302
|
+
async function detectChromeFromExecutable(exePath) {
|
|
3303
|
+
if (!await fileExists(exePath)) {
|
|
3304
|
+
return void 0;
|
|
3305
|
+
}
|
|
3306
|
+
if (process.platform === "win32") {
|
|
3307
|
+
const version = await readWindowsFileVersion(exePath);
|
|
3308
|
+
if (!version) {
|
|
3309
|
+
return void 0;
|
|
3310
|
+
}
|
|
3311
|
+
const parsed2 = parseBrowserVersionString(version);
|
|
3312
|
+
if (!parsed2) {
|
|
3313
|
+
return void 0;
|
|
3314
|
+
}
|
|
3315
|
+
return { path: exePath, version: parsed2.version, major: parsed2.major };
|
|
3316
|
+
}
|
|
3317
|
+
const out = await runCommandCapture(exePath, ["--version"]);
|
|
3318
|
+
if (!out) {
|
|
3319
|
+
return void 0;
|
|
3320
|
+
}
|
|
3321
|
+
const parsed = parseBrowserVersionString(out);
|
|
3322
|
+
if (!parsed) {
|
|
3323
|
+
return void 0;
|
|
3324
|
+
}
|
|
3325
|
+
return { path: exePath, version: parsed.version, major: parsed.major };
|
|
3326
|
+
}
|
|
3327
|
+
async function detectFirefoxFromExecutable(exePath) {
|
|
3328
|
+
if (!await fileExists(exePath)) {
|
|
3329
|
+
return void 0;
|
|
3330
|
+
}
|
|
3331
|
+
if (process.platform === "win32") {
|
|
3332
|
+
const version = await readWindowsFileVersion(exePath);
|
|
3333
|
+
if (!version) {
|
|
3334
|
+
return void 0;
|
|
3335
|
+
}
|
|
3336
|
+
const parsed2 = parseBrowserVersionString(version);
|
|
3337
|
+
if (!parsed2) {
|
|
3338
|
+
return void 0;
|
|
3339
|
+
}
|
|
3340
|
+
return { path: exePath, version: parsed2.version, major: parsed2.major };
|
|
3341
|
+
}
|
|
3342
|
+
const out = await runCommandCapture(exePath, ["--version"]);
|
|
3343
|
+
if (!out) {
|
|
3344
|
+
return void 0;
|
|
3345
|
+
}
|
|
3346
|
+
const parsed = parseBrowserVersionString(out);
|
|
3347
|
+
if (!parsed) {
|
|
3348
|
+
return void 0;
|
|
3349
|
+
}
|
|
3350
|
+
return { path: exePath, version: parsed.version, major: parsed.major };
|
|
3351
|
+
}
|
|
3352
|
+
async function detectLocalBrowsers() {
|
|
3353
|
+
const result = {};
|
|
3354
|
+
if (process.platform === "win32") {
|
|
3355
|
+
const chromeCandidates = [
|
|
3356
|
+
import_node_path4.default.join(process.env["ProgramFiles"] ?? "C:\\Program Files", "Google", "Chrome", "Application", "chrome.exe"),
|
|
3357
|
+
import_node_path4.default.join(
|
|
3358
|
+
process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)",
|
|
3359
|
+
"Google",
|
|
3360
|
+
"Chrome",
|
|
3361
|
+
"Application",
|
|
3362
|
+
"chrome.exe"
|
|
3363
|
+
),
|
|
3364
|
+
import_node_path4.default.join(process.env["ProgramFiles"] ?? "C:\\Program Files", "Chromium", "Application", "chrome.exe")
|
|
3365
|
+
];
|
|
3366
|
+
for (const p of chromeCandidates) {
|
|
3367
|
+
const hit = await detectChromeFromExecutable(p);
|
|
3368
|
+
if (hit) {
|
|
3369
|
+
result.chrome = hit;
|
|
3370
|
+
break;
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
const firefoxCandidates = [
|
|
3374
|
+
import_node_path4.default.join(process.env["ProgramFiles"] ?? "C:\\Program Files", "Mozilla Firefox", "firefox.exe"),
|
|
3375
|
+
import_node_path4.default.join(
|
|
3376
|
+
process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)",
|
|
3377
|
+
"Mozilla Firefox",
|
|
3378
|
+
"firefox.exe"
|
|
3379
|
+
)
|
|
3380
|
+
];
|
|
3381
|
+
for (const p of firefoxCandidates) {
|
|
3382
|
+
const hit = await detectFirefoxFromExecutable(p);
|
|
3383
|
+
if (hit) {
|
|
3384
|
+
result.firefox = hit;
|
|
3385
|
+
break;
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
return result;
|
|
3389
|
+
}
|
|
3390
|
+
if (process.platform === "darwin") {
|
|
3391
|
+
const chromePaths = [
|
|
3392
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
3393
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium"
|
|
3394
|
+
];
|
|
3395
|
+
for (const p of chromePaths) {
|
|
3396
|
+
const hit = await detectChromeFromExecutable(p);
|
|
3397
|
+
if (hit) {
|
|
3398
|
+
result.chrome = hit;
|
|
3399
|
+
break;
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
const firefoxPath = "/Applications/Firefox.app/Contents/MacOS/firefox";
|
|
3403
|
+
const ff = await detectFirefoxFromExecutable(firefoxPath);
|
|
3404
|
+
if (ff) {
|
|
3405
|
+
result.firefox = ff;
|
|
3406
|
+
}
|
|
3407
|
+
return result;
|
|
3408
|
+
}
|
|
3409
|
+
const chromeCommands = ["google-chrome-stable", "google-chrome", "chromium-browser", "chromium"];
|
|
3410
|
+
for (const cmd of chromeCommands) {
|
|
3411
|
+
if (!await commandOnPath(cmd)) {
|
|
3296
3412
|
continue;
|
|
3297
3413
|
}
|
|
3298
|
-
const
|
|
3299
|
-
|
|
3300
|
-
|
|
3414
|
+
const out = await runCommandCapture(cmd, ["--version"]);
|
|
3415
|
+
const parsed = out ? parseBrowserVersionString(out) : void 0;
|
|
3416
|
+
if (parsed) {
|
|
3417
|
+
result.chrome = { path: cmd, version: parsed.version, major: parsed.major };
|
|
3418
|
+
break;
|
|
3301
3419
|
}
|
|
3302
3420
|
}
|
|
3303
|
-
|
|
3421
|
+
if (await commandOnPath("firefox")) {
|
|
3422
|
+
const out = await runCommandCapture("firefox", ["--version"]);
|
|
3423
|
+
const parsed = out ? parseBrowserVersionString(out) : void 0;
|
|
3424
|
+
if (parsed) {
|
|
3425
|
+
result.firefox = { path: "firefox", version: parsed.version, major: parsed.major };
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
return result;
|
|
3429
|
+
}
|
|
3430
|
+
function logSeleniumDriverGuidance(onLogLine) {
|
|
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"
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
3442
|
+
async function detectInstalledChromeMajorVersion() {
|
|
3443
|
+
const browsers = await detectLocalBrowsers();
|
|
3444
|
+
return browsers.chrome?.major;
|
|
3304
3445
|
}
|
|
3305
3446
|
async function readWindowsFileVersion(exePath) {
|
|
3306
3447
|
return new Promise((resolve) => {
|
|
@@ -3343,7 +3484,7 @@ async function downloadGeckodriver(driversDir, versionInput, onLogLine) {
|
|
|
3343
3484
|
await import_promises4.default.mkdir(driversDir, { recursive: true });
|
|
3344
3485
|
const zipPath = import_node_path4.default.join(driversDir, `_download_geckodriver_${version}.zip`);
|
|
3345
3486
|
const extractDir = import_node_path4.default.join(driversDir, `_extract_geckodriver_${version}`);
|
|
3346
|
-
onLogLine?.(`[selenium] \u4E0B\u8F7D geckodriver ${tag} \
|
|
3487
|
+
onLogLine?.(`[selenium] \u4E0B\u8F7D geckodriver ${tag} \u2192 ${driversDir}`);
|
|
3347
3488
|
onLogLine?.(`[selenium] URL: ${url}`);
|
|
3348
3489
|
await downloadToFile(url, zipPath);
|
|
3349
3490
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
@@ -3356,7 +3497,7 @@ async function downloadGeckodriver(driversDir, versionInput, onLogLine) {
|
|
|
3356
3497
|
await copyExecutable(found, dest);
|
|
3357
3498
|
await import_promises4.default.rm(zipPath, { force: true });
|
|
3358
3499
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
3359
|
-
onLogLine?.(`[selenium] geckodriver \u5DF2\u5199\
|
|
3500
|
+
onLogLine?.(`[selenium] geckodriver \u5DF2\u5199\u5165: ${dest}`);
|
|
3360
3501
|
return { path: dest, version: tag };
|
|
3361
3502
|
}
|
|
3362
3503
|
async function downloadChromedriver(driversDir, versionInput, onLogLine) {
|
|
@@ -3376,7 +3517,7 @@ async function downloadChromedriver(driversDir, versionInput, onLogLine) {
|
|
|
3376
3517
|
await import_promises4.default.mkdir(driversDir, { recursive: true });
|
|
3377
3518
|
const zipPath = import_node_path4.default.join(driversDir, `_download_chromedriver_${major}.zip`);
|
|
3378
3519
|
const extractDir = import_node_path4.default.join(driversDir, `_extract_chromedriver_${major}`);
|
|
3379
|
-
onLogLine?.(`[selenium] \u4E0B\u8F7D chromedriver ${fullVersion} (\u4E3B\u7248\
|
|
3520
|
+
onLogLine?.(`[selenium] \u4E0B\u8F7D chromedriver ${fullVersion} (\u4E3B\u7248\u672C ${major}) \u2192 ${driversDir}`);
|
|
3380
3521
|
onLogLine?.(`[selenium] URL: ${url}`);
|
|
3381
3522
|
await downloadToFile(url, zipPath);
|
|
3382
3523
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
@@ -3393,7 +3534,7 @@ async function downloadChromedriver(driversDir, versionInput, onLogLine) {
|
|
|
3393
3534
|
}
|
|
3394
3535
|
await import_promises4.default.rm(zipPath, { force: true });
|
|
3395
3536
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
3396
|
-
onLogLine?.(`[selenium] chromedriver \u5DF2\u5199\
|
|
3537
|
+
onLogLine?.(`[selenium] chromedriver \u5DF2\u5199\u5165: ${destVersioned}`);
|
|
3397
3538
|
return { path: destVersioned, version: fullVersion, major };
|
|
3398
3539
|
}
|
|
3399
3540
|
async function saveNativeDriverManifest(manifest, workspaceRoot) {
|
|
@@ -3403,38 +3544,91 @@ async function saveNativeDriverManifest(manifest, workspaceRoot) {
|
|
|
3403
3544
|
const file = import_node_path4.default.join(dir, "native-drivers.json");
|
|
3404
3545
|
await import_promises4.default.writeFile(file, JSON.stringify(manifest, null, 2), "utf8");
|
|
3405
3546
|
}
|
|
3547
|
+
function resolveDefaultChromedriverVersion(requested, browsers) {
|
|
3548
|
+
if (requested && requested !== "latest") {
|
|
3549
|
+
return requested;
|
|
3550
|
+
}
|
|
3551
|
+
if (browsers.chrome?.major) {
|
|
3552
|
+
return "match-chrome";
|
|
3553
|
+
}
|
|
3554
|
+
return requested ?? "latest";
|
|
3555
|
+
}
|
|
3556
|
+
function formatDownloadError(error) {
|
|
3557
|
+
return error instanceof Error ? error.message : String(error);
|
|
3558
|
+
}
|
|
3406
3559
|
async function ensureNativeWebDrivers(options = {}) {
|
|
3407
3560
|
const root = options.workspaceRoot ?? await resolveWorkspaceRoot3();
|
|
3408
3561
|
const driversDir = options.driversDir ?? await resolveNativeDriversDir(root);
|
|
3409
3562
|
await import_promises4.default.mkdir(driversDir, { recursive: true });
|
|
3410
3563
|
const log2 = options.onLogLine;
|
|
3564
|
+
logSeleniumDriverGuidance(log2);
|
|
3411
3565
|
log2?.(`[selenium] \u539F\u751F\u9A71\u52A8\u76EE\u5F55: ${driversDir}`);
|
|
3566
|
+
const browsers = await detectLocalBrowsers();
|
|
3567
|
+
if (browsers.chrome) {
|
|
3568
|
+
log2?.(
|
|
3569
|
+
`[selenium] \u68C0\u6D4B\u5230\u672C\u673A Chrome/Chromium: ${browsers.chrome.version} (\u4E3B\u7248\u672C ${browsers.chrome.major}) \u2014 ${browsers.chrome.path}`
|
|
3570
|
+
);
|
|
3571
|
+
} else {
|
|
3572
|
+
log2?.("[selenium] \u672A\u68C0\u6D4B\u5230\u672C\u673A Chrome/Chromium\uFF08chromedriver \u5C06\u4F7F\u7528 latest \u6216\u663E\u5F0F\u6307\u5B9A\u7248\u672C\uFF09");
|
|
3573
|
+
}
|
|
3574
|
+
if (browsers.firefox) {
|
|
3575
|
+
log2?.(
|
|
3576
|
+
`[selenium] \u68C0\u6D4B\u5230\u672C\u673A Firefox: ${browsers.firefox.version} (\u4E3B\u7248\u672C ${browsers.firefox.major}) \u2014 ${browsers.firefox.path}`
|
|
3577
|
+
);
|
|
3578
|
+
} else {
|
|
3579
|
+
log2?.("[selenium] \u672A\u68C0\u6D4B\u5230\u672C\u673A Firefox\uFF08geckodriver \u5C06\u4F7F\u7528 latest \u6216\u663E\u5F0F\u6307\u5B9A\u7248\u672C\uFF09");
|
|
3580
|
+
}
|
|
3412
3581
|
const localChromeVersions = await listLocalChromedriverVersions(driversDir);
|
|
3413
3582
|
if (localChromeVersions.length > 0) {
|
|
3414
|
-
log2?.(`[selenium] \u76EE\u5F55\u5185\u5DF2\
|
|
3583
|
+
log2?.(`[selenium] \u76EE\u5F55\u5185\u5DF2\u6709 chromedriver \u7248\u672C: ${localChromeVersions.join(", ")}`);
|
|
3584
|
+
}
|
|
3585
|
+
const chromedriverRequest = resolveDefaultChromedriverVersion(options.chromedriverVersion, browsers);
|
|
3586
|
+
if (chromedriverRequest === "match-chrome" && browsers.chrome) {
|
|
3587
|
+
log2?.(
|
|
3588
|
+
`[selenium] chromedriver \u5C06\u5C1D\u8BD5\u5339\u914D\u672C\u673A Chrome \u4E3B\u7248\u672C ${browsers.chrome.major}\uFF08chrome-for-testing \u76EE\u5F55\uFF09`
|
|
3589
|
+
);
|
|
3415
3590
|
}
|
|
3416
3591
|
const localGecko = await findGeckodriverInDir(driversDir, options.geckodriverVersion);
|
|
3417
3592
|
const hasLocalGecko = Boolean(localGecko && await fileExists(localGecko));
|
|
3418
3593
|
let geckoVersion = options.geckodriverVersion;
|
|
3419
3594
|
if (options.geckodriverVersion !== "skip" && (options.force || !hasLocalGecko)) {
|
|
3420
|
-
|
|
3421
|
-
|
|
3595
|
+
try {
|
|
3596
|
+
const downloaded = await downloadGeckodriver(driversDir, options.geckodriverVersion ?? "latest", log2);
|
|
3597
|
+
geckoVersion = downloaded.version;
|
|
3598
|
+
} catch (error) {
|
|
3599
|
+
log2?.(`[selenium][warn] geckodriver \u81EA\u52A8\u4E0B\u8F7D\u5931\u8D25\uFF0C\u5DF2\u8DF3\u8FC7: ${formatDownloadError(error)}`);
|
|
3600
|
+
log2?.(
|
|
3601
|
+
"[selenium][warn] \u8BF7\u5C06 geckodriver \u653E\u5165\u4E0A\u8FF0\u76EE\u5F55\u6216\u914D\u7F6E PATH / ADA_GECKODRIVER_PATH\uFF1B\u53EF\u53C2\u8003 Mozilla \u53D1\u5E03\u9875\u624B\u52A8\u4E0B\u8F7D\u3002"
|
|
3602
|
+
);
|
|
3603
|
+
}
|
|
3422
3604
|
} else if (hasLocalGecko) {
|
|
3423
3605
|
log2?.(`[selenium] \u590D\u7528\u5DF2\u6709 geckodriver: ${localGecko}`);
|
|
3424
3606
|
}
|
|
3425
|
-
const localChrome = await findChromedriverInDir(driversDir,
|
|
3607
|
+
const localChrome = await findChromedriverInDir(driversDir, chromedriverRequest);
|
|
3426
3608
|
const hasLocalChrome = Boolean(localChrome && await fileExists(localChrome.path));
|
|
3427
|
-
if (
|
|
3428
|
-
|
|
3609
|
+
if (chromedriverRequest !== "skip" && (options.force || !hasLocalChrome)) {
|
|
3610
|
+
try {
|
|
3611
|
+
await downloadChromedriver(driversDir, chromedriverRequest ?? "latest", log2);
|
|
3612
|
+
} catch (error) {
|
|
3613
|
+
log2?.(`[selenium][warn] chromedriver \u81EA\u52A8\u4E0B\u8F7D\u5931\u8D25\uFF0C\u5DF2\u8DF3\u8FC7: ${formatDownloadError(error)}`);
|
|
3614
|
+
if (browsers.chrome) {
|
|
3615
|
+
log2?.(
|
|
3616
|
+
`[selenium][warn] \u672C\u673A Chrome \u4E3B\u7248\u672C\u4E3A ${browsers.chrome.major}\uFF0C\u8BF7\u4E0B\u8F7D\u5339\u914D\u7248\u672C\u7684 chromedriver \u653E\u5165\u76EE\u5F55\u6216\u914D\u7F6E ADA_CHROMEDRIVER_PATH\u3002`
|
|
3617
|
+
);
|
|
3618
|
+
}
|
|
3619
|
+
log2?.(
|
|
3620
|
+
"[selenium][warn] \u53EF\u53C2\u8003 chrome-for-testing / chromedriver.storage \u624B\u52A8\u4E0B\u8F7D\uFF1B\u5DF2\u653E\u5165 dirver/ \u7684\u9A71\u52A8\u4F1A\u5728\u4E0B\u6B21\u542F\u52A8\u65F6\u81EA\u52A8\u590D\u7528\u3002"
|
|
3621
|
+
);
|
|
3622
|
+
}
|
|
3429
3623
|
} else if (hasLocalChrome) {
|
|
3430
|
-
log2?.(`[selenium] \u590D\u7528\u5DF2\u6709 chromedriver: ${localChrome.path} (\u4E3B\u7248\
|
|
3624
|
+
log2?.(`[selenium] \u590D\u7528\u5DF2\u6709 chromedriver: ${localChrome.path} (\u4E3B\u7248\u672C ${localChrome.version})`);
|
|
3431
3625
|
}
|
|
3432
3626
|
const resolved = await resolveNativeDrivers({
|
|
3433
3627
|
driversDir,
|
|
3434
3628
|
workspaceRoot: root,
|
|
3435
3629
|
selection: {
|
|
3436
3630
|
geckodriverVersion: geckoVersion,
|
|
3437
|
-
chromedriverVersion:
|
|
3631
|
+
chromedriverVersion: chromedriverRequest ?? localChrome?.version
|
|
3438
3632
|
}
|
|
3439
3633
|
});
|
|
3440
3634
|
await saveNativeDriverManifest(
|
|
@@ -3449,14 +3643,21 @@ async function ensureNativeWebDrivers(options = {}) {
|
|
|
3449
3643
|
if (resolved.geckodriverPath) {
|
|
3450
3644
|
process.env.ADA_GECKODRIVER_PATH = resolved.geckodriverPath;
|
|
3451
3645
|
log2?.(`[selenium] \u4F7F\u7528 geckodriver: ${resolved.geckodriverPath}`);
|
|
3646
|
+
} else if (options.geckodriverVersion !== "skip") {
|
|
3647
|
+
log2?.("[selenium][warn] \u672A\u627E\u5230\u53EF\u7528 geckodriver\uFF08\u81EA\u52A8\u4E0B\u8F7D\u5DF2\u8DF3\u8FC7\u6216\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5\uFF09");
|
|
3452
3648
|
}
|
|
3453
3649
|
if (resolved.chromedriverPath) {
|
|
3454
3650
|
process.env.ADA_CHROMEDRIVER_PATH = resolved.chromedriverPath;
|
|
3455
3651
|
log2?.(`[selenium] \u4F7F\u7528 chromedriver: ${resolved.chromedriverPath}`);
|
|
3652
|
+
} else if (chromedriverRequest !== "skip") {
|
|
3653
|
+
log2?.("[selenium][warn] \u672A\u627E\u5230\u53EF\u7528 chromedriver\uFF08\u81EA\u52A8\u4E0B\u8F7D\u5DF2\u8DF3\u8FC7\u6216\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5\uFF09");
|
|
3654
|
+
}
|
|
3655
|
+
if (!resolved.geckodriverOk && !resolved.chromedriverOk) {
|
|
3656
|
+
log2?.("[selenium][warn] \u5F53\u524D\u65E0\u53EF\u7528\u539F\u751F WebDriver\uFF1BSelenium \u4EFB\u52A1\u53EF\u80FD\u5931\u8D25\uFF0C\u8BF7\u6309\u4E0A\u6587\u53C2\u8003\u5730\u5740\u81EA\u884C\u4E0B\u8F7D\u3002");
|
|
3456
3657
|
}
|
|
3457
3658
|
return resolved;
|
|
3458
3659
|
}
|
|
3459
|
-
var import_node_child_process, import_promises4, import_node_path4, DEFAULT_NATIVE_DRIVERS_DIR, CHROME_FOR_TESTING_JSON;
|
|
3660
|
+
var import_node_child_process, import_promises4, import_node_path4, DEFAULT_NATIVE_DRIVERS_DIR, CHROME_FOR_TESTING_JSON, SELENIUM_DRIVER_MANUAL_DOWNLOAD_REFERENCES;
|
|
3460
3661
|
var init_src2 = __esm({
|
|
3461
3662
|
"../../packages/native-drivers/src/index.ts"() {
|
|
3462
3663
|
"use strict";
|
|
@@ -3465,6 +3666,44 @@ var init_src2 = __esm({
|
|
|
3465
3666
|
import_node_path4 = __toESM(require("node:path"), 1);
|
|
3466
3667
|
DEFAULT_NATIVE_DRIVERS_DIR = "dirver";
|
|
3467
3668
|
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
|
+
];
|
|
3468
3707
|
}
|
|
3469
3708
|
});
|
|
3470
3709
|
|
|
@@ -3543,7 +3782,7 @@ function runCommand2(command, args, options) {
|
|
|
3543
3782
|
});
|
|
3544
3783
|
});
|
|
3545
3784
|
}
|
|
3546
|
-
function
|
|
3785
|
+
function runCommandCapture2(command, args) {
|
|
3547
3786
|
return new Promise((resolve) => {
|
|
3548
3787
|
const child = (0, import_node_child_process2.spawn)(command, args, {
|
|
3549
3788
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -3665,7 +3904,7 @@ async function ensureNodeEnvironmentForInstall(onLogLine) {
|
|
|
3665
3904
|
const requiredNpmMajor = 10;
|
|
3666
3905
|
const runtimeNode = process.versions.node;
|
|
3667
3906
|
const runtimeMajor = majorOf(runtimeNode);
|
|
3668
|
-
const nodeVersion = await
|
|
3907
|
+
const nodeVersion = await runCommandCapture2("node", ["-v"]);
|
|
3669
3908
|
if (nodeVersion.code === 0) {
|
|
3670
3909
|
const nodeMajor = majorOf(nodeVersion.stdout);
|
|
3671
3910
|
onLogLine?.(`[deps] Node \u7248\u672C\u68C0\u6D4B\uFF1A\u7CFB\u7EDF=${nodeVersion.stdout}\uFF0C\u5185\u7F6E=${runtimeNode}`);
|
|
@@ -3684,7 +3923,7 @@ async function ensureNodeEnvironmentForInstall(onLogLine) {
|
|
|
3684
3923
|
`[deps][warn] \u672A\u4ECE PATH \u68C0\u6D4B\u5230 node\uFF0C\u5F53\u524D\u8FD0\u884C\u65F6 Node.js=${runtimeNode}\uFF08\u53EF\u6267\u884C\u7A0B\u5E8F\u5185\u7F6E\uFF09\uFF0C\u7EE7\u7EED\u5C1D\u8BD5\u5B89\u88C5\u3002`
|
|
3685
3924
|
);
|
|
3686
3925
|
}
|
|
3687
|
-
const npmVersion = await
|
|
3926
|
+
const npmVersion = await runCommandCapture2("npm", ["-v"]);
|
|
3688
3927
|
if (npmVersion.code !== 0) {
|
|
3689
3928
|
const message = "\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u7684 npm\uFF08PATH \u4E2D\u4E0D\u53EF\u7528\uFF09\u3002\u8BF7\u5B89\u88C5 Node.js 22+\uFF08\u542B npm\uFF09\u5E76\u91CD\u542F\u7EC8\u7AEF\u540E\u91CD\u8BD5\u3002";
|
|
3690
3929
|
onLogLine?.(`[deps] ${message}`);
|
|
@@ -3737,7 +3976,7 @@ async function resolveCompatibleDriverSpecs(driver) {
|
|
|
3737
3976
|
const preferred = driver === "uiautomator2" ? process.env.ADA_APPIUM_DRIVER_SPEC_UIAUTOMATOR2 ?? `${pkg}@2` : process.env.ADA_APPIUM_DRIVER_SPEC_XCUITEST ?? `${pkg}@7`;
|
|
3738
3977
|
const fallbackRange = driver === "uiautomator2" ? process.env.ADA_APPIUM_DRIVER_RANGE_UIAUTOMATOR2 ?? "<3" : process.env.ADA_APPIUM_DRIVER_RANGE_XCUITEST ?? "<8";
|
|
3739
3978
|
const specs = [preferred];
|
|
3740
|
-
const view = await
|
|
3979
|
+
const view = await runCommandCapture2("npm", ["view", `${pkg}@${fallbackRange}`, "version"]);
|
|
3741
3980
|
if (view.code === 0 && view.stdout) {
|
|
3742
3981
|
const version = view.stdout.trim().split(/\r?\n/).pop()?.trim();
|
|
3743
3982
|
if (version) {
|
|
@@ -4159,7 +4398,7 @@ async function verifyAppiumCommand() {
|
|
|
4159
4398
|
}
|
|
4160
4399
|
}
|
|
4161
4400
|
async function getInstalledAppiumDrivers() {
|
|
4162
|
-
const check = await
|
|
4401
|
+
const check = await runCommandCapture2("npm", ["exec", "appium", "driver", "list", "--installed", "--json"]);
|
|
4163
4402
|
if (check.code === 0 && check.stdout) {
|
|
4164
4403
|
try {
|
|
4165
4404
|
const parsed = JSON.parse(check.stdout);
|
|
@@ -4168,7 +4407,7 @@ async function getInstalledAppiumDrivers() {
|
|
|
4168
4407
|
} catch {
|
|
4169
4408
|
}
|
|
4170
4409
|
}
|
|
4171
|
-
const fallback = await
|
|
4410
|
+
const fallback = await runCommandCapture2("npm", ["exec", "appium", "driver", "list", "--installed"]);
|
|
4172
4411
|
if (fallback.code !== 0) {
|
|
4173
4412
|
return [];
|
|
4174
4413
|
}
|
|
@@ -4238,6 +4477,7 @@ async function ensureSeleniumNativeDrivers(config, options, onLogLine) {
|
|
|
4238
4477
|
}
|
|
4239
4478
|
const geckoVer = options?.geckodriverVersion ?? config.dependencies.geckodriverVersion ?? "latest";
|
|
4240
4479
|
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");
|
|
4241
4481
|
try {
|
|
4242
4482
|
const catalog = await listChromedriverCfTVersions();
|
|
4243
4483
|
onLogLine?.(
|