@ada-mcp/mcp-server 0.1.14 → 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.
- package/README.md +139 -139
- package/dist/cli.cjs +455 -105
- 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.13`** 拉起本包(见 [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.13"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
本包版本:**`@ada-mcp/mcp-server@0.1.16`**(由 launcher 默认拉取;依赖锁定 `playwright@1.59.1`)。
|
|
25
|
+
|
|
26
|
+
直接调试本包(无 launcher 拉包前测速):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm dlx @ada-mcp/mcp-server@0.1.16
|
|
30
|
+
# npx 等价:
|
|
31
|
+
npx -y @ada-mcp/mcp-server@0.1.16
|
|
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.13", "--install-deps=all"]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Cursor MCP 配置
|
|
90
|
+
|
|
91
|
+
**pnpm(推荐)**:`pnpm` + `dlx @ada-mcp/launcher@0.1.13`
|
|
92
|
+
|
|
93
|
+
**npx 等价**(`launcher@0.1.7+`):`npx` + `-y @ada-mcp/launcher@0.1.13`(内层同样 `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.13"]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Windows 若找不到 `pnpm`,可将 `command` 改为 `pnpm.cmd` 绝对路径;无 pnpm 时只能直接 `npx -y @ada-mcp/mcp-server@0.1.16`(无 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,164 @@ 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] \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"
|
|
3433
|
+
);
|
|
3434
|
+
}
|
|
3435
|
+
async function detectInstalledChromeMajorVersion() {
|
|
3436
|
+
const browsers = await detectLocalBrowsers();
|
|
3437
|
+
return browsers.chrome?.major;
|
|
3304
3438
|
}
|
|
3305
3439
|
async function readWindowsFileVersion(exePath) {
|
|
3306
3440
|
return new Promise((resolve) => {
|
|
@@ -3343,7 +3477,7 @@ async function downloadGeckodriver(driversDir, versionInput, onLogLine) {
|
|
|
3343
3477
|
await import_promises4.default.mkdir(driversDir, { recursive: true });
|
|
3344
3478
|
const zipPath = import_node_path4.default.join(driversDir, `_download_geckodriver_${version}.zip`);
|
|
3345
3479
|
const extractDir = import_node_path4.default.join(driversDir, `_extract_geckodriver_${version}`);
|
|
3346
|
-
onLogLine?.(`[selenium] \u4E0B\u8F7D geckodriver ${tag} \
|
|
3480
|
+
onLogLine?.(`[selenium] \u4E0B\u8F7D geckodriver ${tag} \u2192 ${driversDir}`);
|
|
3347
3481
|
onLogLine?.(`[selenium] URL: ${url}`);
|
|
3348
3482
|
await downloadToFile(url, zipPath);
|
|
3349
3483
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
@@ -3356,7 +3490,7 @@ async function downloadGeckodriver(driversDir, versionInput, onLogLine) {
|
|
|
3356
3490
|
await copyExecutable(found, dest);
|
|
3357
3491
|
await import_promises4.default.rm(zipPath, { force: true });
|
|
3358
3492
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
3359
|
-
onLogLine?.(`[selenium] geckodriver \u5DF2\u5199\
|
|
3493
|
+
onLogLine?.(`[selenium] geckodriver \u5DF2\u5199\u5165: ${dest}`);
|
|
3360
3494
|
return { path: dest, version: tag };
|
|
3361
3495
|
}
|
|
3362
3496
|
async function downloadChromedriver(driversDir, versionInput, onLogLine) {
|
|
@@ -3376,7 +3510,7 @@ async function downloadChromedriver(driversDir, versionInput, onLogLine) {
|
|
|
3376
3510
|
await import_promises4.default.mkdir(driversDir, { recursive: true });
|
|
3377
3511
|
const zipPath = import_node_path4.default.join(driversDir, `_download_chromedriver_${major}.zip`);
|
|
3378
3512
|
const extractDir = import_node_path4.default.join(driversDir, `_extract_chromedriver_${major}`);
|
|
3379
|
-
onLogLine?.(`[selenium] \u4E0B\u8F7D chromedriver ${fullVersion} (\u4E3B\u7248\
|
|
3513
|
+
onLogLine?.(`[selenium] \u4E0B\u8F7D chromedriver ${fullVersion} (\u4E3B\u7248\u672C ${major}) \u2192 ${driversDir}`);
|
|
3380
3514
|
onLogLine?.(`[selenium] URL: ${url}`);
|
|
3381
3515
|
await downloadToFile(url, zipPath);
|
|
3382
3516
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
@@ -3393,7 +3527,7 @@ async function downloadChromedriver(driversDir, versionInput, onLogLine) {
|
|
|
3393
3527
|
}
|
|
3394
3528
|
await import_promises4.default.rm(zipPath, { force: true });
|
|
3395
3529
|
await import_promises4.default.rm(extractDir, { recursive: true, force: true });
|
|
3396
|
-
onLogLine?.(`[selenium] chromedriver \u5DF2\u5199\
|
|
3530
|
+
onLogLine?.(`[selenium] chromedriver \u5DF2\u5199\u5165: ${destVersioned}`);
|
|
3397
3531
|
return { path: destVersioned, version: fullVersion, major };
|
|
3398
3532
|
}
|
|
3399
3533
|
async function saveNativeDriverManifest(manifest, workspaceRoot) {
|
|
@@ -3403,38 +3537,91 @@ async function saveNativeDriverManifest(manifest, workspaceRoot) {
|
|
|
3403
3537
|
const file = import_node_path4.default.join(dir, "native-drivers.json");
|
|
3404
3538
|
await import_promises4.default.writeFile(file, JSON.stringify(manifest, null, 2), "utf8");
|
|
3405
3539
|
}
|
|
3540
|
+
function resolveDefaultChromedriverVersion(requested, browsers) {
|
|
3541
|
+
if (requested && requested !== "latest") {
|
|
3542
|
+
return requested;
|
|
3543
|
+
}
|
|
3544
|
+
if (browsers.chrome?.major) {
|
|
3545
|
+
return "match-chrome";
|
|
3546
|
+
}
|
|
3547
|
+
return requested ?? "latest";
|
|
3548
|
+
}
|
|
3549
|
+
function formatDownloadError(error) {
|
|
3550
|
+
return error instanceof Error ? error.message : String(error);
|
|
3551
|
+
}
|
|
3406
3552
|
async function ensureNativeWebDrivers(options = {}) {
|
|
3407
3553
|
const root = options.workspaceRoot ?? await resolveWorkspaceRoot3();
|
|
3408
3554
|
const driversDir = options.driversDir ?? await resolveNativeDriversDir(root);
|
|
3409
3555
|
await import_promises4.default.mkdir(driversDir, { recursive: true });
|
|
3410
3556
|
const log2 = options.onLogLine;
|
|
3557
|
+
logSeleniumDriverGuidance(log2);
|
|
3411
3558
|
log2?.(`[selenium] \u539F\u751F\u9A71\u52A8\u76EE\u5F55: ${driversDir}`);
|
|
3559
|
+
const browsers = await detectLocalBrowsers();
|
|
3560
|
+
if (browsers.chrome) {
|
|
3561
|
+
log2?.(
|
|
3562
|
+
`[selenium] \u68C0\u6D4B\u5230\u672C\u673A Chrome/Chromium: ${browsers.chrome.version} (\u4E3B\u7248\u672C ${browsers.chrome.major}) \u2014 ${browsers.chrome.path}`
|
|
3563
|
+
);
|
|
3564
|
+
} else {
|
|
3565
|
+
log2?.("[selenium] \u672A\u68C0\u6D4B\u5230\u672C\u673A Chrome/Chromium\uFF08chromedriver \u5C06\u4F7F\u7528 latest \u6216\u663E\u5F0F\u6307\u5B9A\u7248\u672C\uFF09");
|
|
3566
|
+
}
|
|
3567
|
+
if (browsers.firefox) {
|
|
3568
|
+
log2?.(
|
|
3569
|
+
`[selenium] \u68C0\u6D4B\u5230\u672C\u673A Firefox: ${browsers.firefox.version} (\u4E3B\u7248\u672C ${browsers.firefox.major}) \u2014 ${browsers.firefox.path}`
|
|
3570
|
+
);
|
|
3571
|
+
} else {
|
|
3572
|
+
log2?.("[selenium] \u672A\u68C0\u6D4B\u5230\u672C\u673A Firefox\uFF08geckodriver \u5C06\u4F7F\u7528 latest \u6216\u663E\u5F0F\u6307\u5B9A\u7248\u672C\uFF09");
|
|
3573
|
+
}
|
|
3412
3574
|
const localChromeVersions = await listLocalChromedriverVersions(driversDir);
|
|
3413
3575
|
if (localChromeVersions.length > 0) {
|
|
3414
|
-
log2?.(`[selenium] \u76EE\u5F55\u5185\u5DF2\
|
|
3576
|
+
log2?.(`[selenium] \u76EE\u5F55\u5185\u5DF2\u6709 chromedriver \u7248\u672C: ${localChromeVersions.join(", ")}`);
|
|
3577
|
+
}
|
|
3578
|
+
const chromedriverRequest = resolveDefaultChromedriverVersion(options.chromedriverVersion, browsers);
|
|
3579
|
+
if (chromedriverRequest === "match-chrome" && browsers.chrome) {
|
|
3580
|
+
log2?.(
|
|
3581
|
+
`[selenium] chromedriver \u5C06\u5C1D\u8BD5\u5339\u914D\u672C\u673A Chrome \u4E3B\u7248\u672C ${browsers.chrome.major}\uFF08chrome-for-testing \u76EE\u5F55\uFF09`
|
|
3582
|
+
);
|
|
3415
3583
|
}
|
|
3416
3584
|
const localGecko = await findGeckodriverInDir(driversDir, options.geckodriverVersion);
|
|
3417
3585
|
const hasLocalGecko = Boolean(localGecko && await fileExists(localGecko));
|
|
3418
3586
|
let geckoVersion = options.geckodriverVersion;
|
|
3419
3587
|
if (options.geckodriverVersion !== "skip" && (options.force || !hasLocalGecko)) {
|
|
3420
|
-
|
|
3421
|
-
|
|
3588
|
+
try {
|
|
3589
|
+
const downloaded = await downloadGeckodriver(driversDir, options.geckodriverVersion ?? "latest", log2);
|
|
3590
|
+
geckoVersion = downloaded.version;
|
|
3591
|
+
} catch (error) {
|
|
3592
|
+
log2?.(`[selenium][warn] geckodriver \u81EA\u52A8\u4E0B\u8F7D\u5931\u8D25\uFF0C\u5DF2\u8DF3\u8FC7: ${formatDownloadError(error)}`);
|
|
3593
|
+
log2?.(
|
|
3594
|
+
"[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"
|
|
3595
|
+
);
|
|
3596
|
+
}
|
|
3422
3597
|
} else if (hasLocalGecko) {
|
|
3423
3598
|
log2?.(`[selenium] \u590D\u7528\u5DF2\u6709 geckodriver: ${localGecko}`);
|
|
3424
3599
|
}
|
|
3425
|
-
const localChrome = await findChromedriverInDir(driversDir,
|
|
3600
|
+
const localChrome = await findChromedriverInDir(driversDir, chromedriverRequest);
|
|
3426
3601
|
const hasLocalChrome = Boolean(localChrome && await fileExists(localChrome.path));
|
|
3427
|
-
if (
|
|
3428
|
-
|
|
3602
|
+
if (chromedriverRequest !== "skip" && (options.force || !hasLocalChrome)) {
|
|
3603
|
+
try {
|
|
3604
|
+
await downloadChromedriver(driversDir, chromedriverRequest ?? "latest", log2);
|
|
3605
|
+
} catch (error) {
|
|
3606
|
+
log2?.(`[selenium][warn] chromedriver \u81EA\u52A8\u4E0B\u8F7D\u5931\u8D25\uFF0C\u5DF2\u8DF3\u8FC7: ${formatDownloadError(error)}`);
|
|
3607
|
+
if (browsers.chrome) {
|
|
3608
|
+
log2?.(
|
|
3609
|
+
`[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`
|
|
3610
|
+
);
|
|
3611
|
+
}
|
|
3612
|
+
log2?.(
|
|
3613
|
+
"[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"
|
|
3614
|
+
);
|
|
3615
|
+
}
|
|
3429
3616
|
} else if (hasLocalChrome) {
|
|
3430
|
-
log2?.(`[selenium] \u590D\u7528\u5DF2\u6709 chromedriver: ${localChrome.path} (\u4E3B\u7248\
|
|
3617
|
+
log2?.(`[selenium] \u590D\u7528\u5DF2\u6709 chromedriver: ${localChrome.path} (\u4E3B\u7248\u672C ${localChrome.version})`);
|
|
3431
3618
|
}
|
|
3432
3619
|
const resolved = await resolveNativeDrivers({
|
|
3433
3620
|
driversDir,
|
|
3434
3621
|
workspaceRoot: root,
|
|
3435
3622
|
selection: {
|
|
3436
3623
|
geckodriverVersion: geckoVersion,
|
|
3437
|
-
chromedriverVersion:
|
|
3624
|
+
chromedriverVersion: chromedriverRequest ?? localChrome?.version
|
|
3438
3625
|
}
|
|
3439
3626
|
});
|
|
3440
3627
|
await saveNativeDriverManifest(
|
|
@@ -3449,10 +3636,17 @@ async function ensureNativeWebDrivers(options = {}) {
|
|
|
3449
3636
|
if (resolved.geckodriverPath) {
|
|
3450
3637
|
process.env.ADA_GECKODRIVER_PATH = resolved.geckodriverPath;
|
|
3451
3638
|
log2?.(`[selenium] \u4F7F\u7528 geckodriver: ${resolved.geckodriverPath}`);
|
|
3639
|
+
} else if (options.geckodriverVersion !== "skip") {
|
|
3640
|
+
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
3641
|
}
|
|
3453
3642
|
if (resolved.chromedriverPath) {
|
|
3454
3643
|
process.env.ADA_CHROMEDRIVER_PATH = resolved.chromedriverPath;
|
|
3455
3644
|
log2?.(`[selenium] \u4F7F\u7528 chromedriver: ${resolved.chromedriverPath}`);
|
|
3645
|
+
} else if (chromedriverRequest !== "skip") {
|
|
3646
|
+
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");
|
|
3647
|
+
}
|
|
3648
|
+
if (!resolved.geckodriverOk && !resolved.chromedriverOk) {
|
|
3649
|
+
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
3650
|
}
|
|
3457
3651
|
return resolved;
|
|
3458
3652
|
}
|
|
@@ -3469,6 +3663,13 @@ var init_src2 = __esm({
|
|
|
3469
3663
|
});
|
|
3470
3664
|
|
|
3471
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
|
+
}
|
|
3472
3673
|
function shouldUseShell(command) {
|
|
3473
3674
|
if (process.platform !== "win32") {
|
|
3474
3675
|
return false;
|
|
@@ -3483,6 +3684,69 @@ function hasPackage(packageName) {
|
|
|
3483
3684
|
return false;
|
|
3484
3685
|
}
|
|
3485
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
|
+
}
|
|
3486
3750
|
function runCommand2(command, args, options) {
|
|
3487
3751
|
return new Promise((resolve, reject) => {
|
|
3488
3752
|
const onLogLine = options?.onLogLine;
|
|
@@ -3507,7 +3771,7 @@ function runCommand2(command, args, options) {
|
|
|
3507
3771
|
buf = parts.pop() ?? "";
|
|
3508
3772
|
for (const line of parts) {
|
|
3509
3773
|
const t = line.trimEnd();
|
|
3510
|
-
if (t.length > 0) {
|
|
3774
|
+
if (t.length > 0 && (options?.logFilter?.(t) ?? true)) {
|
|
3511
3775
|
onLogLine(t);
|
|
3512
3776
|
}
|
|
3513
3777
|
}
|
|
@@ -3543,7 +3807,7 @@ function runCommand2(command, args, options) {
|
|
|
3543
3807
|
});
|
|
3544
3808
|
});
|
|
3545
3809
|
}
|
|
3546
|
-
function
|
|
3810
|
+
function runCommandCapture2(command, args) {
|
|
3547
3811
|
return new Promise((resolve) => {
|
|
3548
3812
|
const child = (0, import_node_child_process2.spawn)(command, args, {
|
|
3549
3813
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -3665,7 +3929,7 @@ async function ensureNodeEnvironmentForInstall(onLogLine) {
|
|
|
3665
3929
|
const requiredNpmMajor = 10;
|
|
3666
3930
|
const runtimeNode = process.versions.node;
|
|
3667
3931
|
const runtimeMajor = majorOf(runtimeNode);
|
|
3668
|
-
const nodeVersion = await
|
|
3932
|
+
const nodeVersion = await runCommandCapture2("node", ["-v"]);
|
|
3669
3933
|
if (nodeVersion.code === 0) {
|
|
3670
3934
|
const nodeMajor = majorOf(nodeVersion.stdout);
|
|
3671
3935
|
onLogLine?.(`[deps] Node \u7248\u672C\u68C0\u6D4B\uFF1A\u7CFB\u7EDF=${nodeVersion.stdout}\uFF0C\u5185\u7F6E=${runtimeNode}`);
|
|
@@ -3684,7 +3948,7 @@ async function ensureNodeEnvironmentForInstall(onLogLine) {
|
|
|
3684
3948
|
`[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
3949
|
);
|
|
3686
3950
|
}
|
|
3687
|
-
const npmVersion = await
|
|
3951
|
+
const npmVersion = await runCommandCapture2("npm", ["-v"]);
|
|
3688
3952
|
if (npmVersion.code !== 0) {
|
|
3689
3953
|
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
3954
|
onLogLine?.(`[deps] ${message}`);
|
|
@@ -3737,7 +4001,7 @@ async function resolveCompatibleDriverSpecs(driver) {
|
|
|
3737
4001
|
const preferred = driver === "uiautomator2" ? process.env.ADA_APPIUM_DRIVER_SPEC_UIAUTOMATOR2 ?? `${pkg}@2` : process.env.ADA_APPIUM_DRIVER_SPEC_XCUITEST ?? `${pkg}@7`;
|
|
3738
4002
|
const fallbackRange = driver === "uiautomator2" ? process.env.ADA_APPIUM_DRIVER_RANGE_UIAUTOMATOR2 ?? "<3" : process.env.ADA_APPIUM_DRIVER_RANGE_XCUITEST ?? "<8";
|
|
3739
4003
|
const specs = [preferred];
|
|
3740
|
-
const view = await
|
|
4004
|
+
const view = await runCommandCapture2("npm", ["view", `${pkg}@${fallbackRange}`, "version"]);
|
|
3741
4005
|
if (view.code === 0 && view.stdout) {
|
|
3742
4006
|
const version = view.stdout.trim().split(/\r?\n/).pop()?.trim();
|
|
3743
4007
|
if (version) {
|
|
@@ -3758,8 +4022,15 @@ function stepMeta(stage) {
|
|
|
3758
4022
|
};
|
|
3759
4023
|
}
|
|
3760
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
|
+
}
|
|
3761
4032
|
const meta = stepMeta(stage);
|
|
3762
|
-
|
|
4033
|
+
depsStructuredLog("info", {
|
|
3763
4034
|
event: "deps.progress",
|
|
3764
4035
|
details: {
|
|
3765
4036
|
stage,
|
|
@@ -3768,6 +4039,12 @@ function progress(stage, details) {
|
|
|
3768
4039
|
}
|
|
3769
4040
|
});
|
|
3770
4041
|
}
|
|
4042
|
+
function depsStructuredLog(level, payload) {
|
|
4043
|
+
if (depsHumanLog) {
|
|
4044
|
+
return;
|
|
4045
|
+
}
|
|
4046
|
+
log(level, payload);
|
|
4047
|
+
}
|
|
3771
4048
|
function normalizeRegistryUrl(url) {
|
|
3772
4049
|
return url.replace(/\/$/, "");
|
|
3773
4050
|
}
|
|
@@ -3840,7 +4117,7 @@ async function detectBestRegistry(config, baseProxy) {
|
|
|
3840
4117
|
}
|
|
3841
4118
|
}
|
|
3842
4119
|
detectedBestRegistryByKey.set(cacheKey, best);
|
|
3843
|
-
|
|
4120
|
+
depsStructuredLog("info", {
|
|
3844
4121
|
event: "deps.registry.auto-selected",
|
|
3845
4122
|
details: {
|
|
3846
4123
|
selected: best,
|
|
@@ -3936,11 +4213,14 @@ async function rankPlaywrightHosts(config) {
|
|
|
3936
4213
|
const withArtifact = reachable.filter((x) => x.artifactOk);
|
|
3937
4214
|
const pool = withArtifact.length > 0 ? withArtifact : reachable;
|
|
3938
4215
|
pool.sort((a, b) => {
|
|
3939
|
-
if (
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
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;
|
|
3944
4224
|
}
|
|
3945
4225
|
return a.priority - b.priority;
|
|
3946
4226
|
});
|
|
@@ -3953,37 +4233,43 @@ async function rankPlaywrightHosts(config) {
|
|
|
3953
4233
|
return ranked.length > 0 ? ranked : [...candidates];
|
|
3954
4234
|
}
|
|
3955
4235
|
async function runInstallWithPriority(config, packages, onLogLine) {
|
|
4236
|
+
const specs = resolveInstallPackageSpecs(packages);
|
|
3956
4237
|
const npmProxy = await detectBestRegistry(config, npmProxyRegistry());
|
|
3957
4238
|
const pnpmProxy = await detectBestRegistry(config, pnpmProxyRegistry());
|
|
3958
|
-
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
|
+
}
|
|
3959
4245
|
onLogLine?.(
|
|
3960
|
-
`[deps] \u5728\u7EBF\u5B89\u88C5\u5305: ${
|
|
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)`
|
|
3961
4247
|
);
|
|
3962
4248
|
const strategies = [
|
|
3963
4249
|
{
|
|
3964
4250
|
name: "pnpm",
|
|
3965
|
-
run: () => runCommand2("pnpm", ["add", ...
|
|
4251
|
+
run: () => runCommand2("pnpm", ["add", ...specs], {
|
|
3966
4252
|
timeoutMs: installStrategyTimeoutMs(),
|
|
3967
4253
|
onLogLine
|
|
3968
4254
|
})
|
|
3969
4255
|
},
|
|
3970
4256
|
{
|
|
3971
4257
|
name: "pnpm-proxy",
|
|
3972
|
-
run: () => runCommand2("pnpm", ["add", ...
|
|
4258
|
+
run: () => runCommand2("pnpm", ["add", ...specs, "--registry", pnpmProxy], {
|
|
3973
4259
|
timeoutMs: installStrategyTimeoutMs(),
|
|
3974
4260
|
onLogLine
|
|
3975
4261
|
})
|
|
3976
4262
|
},
|
|
3977
4263
|
{
|
|
3978
4264
|
name: "npm",
|
|
3979
|
-
run: () => runCommand2("npm", ["install", ...
|
|
4265
|
+
run: () => runCommand2("npm", ["install", ...specs], {
|
|
3980
4266
|
timeoutMs: installStrategyTimeoutMs(),
|
|
3981
4267
|
onLogLine
|
|
3982
4268
|
})
|
|
3983
4269
|
},
|
|
3984
4270
|
{
|
|
3985
4271
|
name: "npm-proxy",
|
|
3986
|
-
run: () => runCommand2("npm", ["install", ...
|
|
4272
|
+
run: () => runCommand2("npm", ["install", ...specs, "--registry", npmProxy], {
|
|
3987
4273
|
timeoutMs: installStrategyTimeoutMs(),
|
|
3988
4274
|
onLogLine
|
|
3989
4275
|
})
|
|
@@ -3992,21 +4278,21 @@ async function runInstallWithPriority(config, packages, onLogLine) {
|
|
|
3992
4278
|
let lastError = void 0;
|
|
3993
4279
|
for (const strategy of strategies) {
|
|
3994
4280
|
try {
|
|
3995
|
-
|
|
4281
|
+
depsStructuredLog("info", { event: "deps.install.strategy.try", details: { strategy: strategy.name, packages } });
|
|
3996
4282
|
await strategy.run();
|
|
3997
|
-
|
|
4283
|
+
depsStructuredLog("info", { event: "deps.install.strategy.ok", details: { strategy: strategy.name } });
|
|
3998
4284
|
progress("packages.install.done", { strategy: strategy.name });
|
|
3999
4285
|
return;
|
|
4000
4286
|
} catch (error) {
|
|
4001
4287
|
lastError = error;
|
|
4002
|
-
|
|
4288
|
+
depsStructuredLog("warn", {
|
|
4003
4289
|
event: "deps.install.strategy.fail",
|
|
4004
4290
|
details: { strategy: strategy.name, message: error instanceof Error ? error.message : String(error) }
|
|
4005
4291
|
});
|
|
4006
4292
|
}
|
|
4007
4293
|
}
|
|
4008
|
-
|
|
4009
|
-
`
|
|
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`
|
|
4010
4296
|
);
|
|
4011
4297
|
}
|
|
4012
4298
|
async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
|
|
@@ -4041,12 +4327,12 @@ async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
|
|
|
4041
4327
|
];
|
|
4042
4328
|
for (const strategy of strategies) {
|
|
4043
4329
|
try {
|
|
4044
|
-
|
|
4330
|
+
depsStructuredLog("info", {
|
|
4045
4331
|
event: "appium.driver.install.strategy.try",
|
|
4046
4332
|
details: { strategy: strategy.name, driver, target }
|
|
4047
4333
|
});
|
|
4048
4334
|
await strategy.run();
|
|
4049
|
-
|
|
4335
|
+
depsStructuredLog("info", {
|
|
4050
4336
|
event: "appium.driver.install.strategy.ok",
|
|
4051
4337
|
details: { strategy: strategy.name, driver, target }
|
|
4052
4338
|
});
|
|
@@ -4054,7 +4340,7 @@ async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
|
|
|
4054
4340
|
return;
|
|
4055
4341
|
} catch (error) {
|
|
4056
4342
|
lastError = error;
|
|
4057
|
-
|
|
4343
|
+
depsStructuredLog("warn", {
|
|
4058
4344
|
event: "appium.driver.install.strategy.fail",
|
|
4059
4345
|
details: {
|
|
4060
4346
|
strategy: strategy.name,
|
|
@@ -4071,16 +4357,23 @@ async function runAppiumDriverInstallWithPriority(config, driver, onLogLine) {
|
|
|
4071
4357
|
);
|
|
4072
4358
|
}
|
|
4073
4359
|
async function verifyPlaywrightSelfTest(onLogLine) {
|
|
4074
|
-
onLogLine?.("[playwright] \u81EA\u68C0\uFF1A\u542F\u52A8 Chromium
|
|
4075
|
-
const moduleName = ["play", "wright"].join("");
|
|
4076
|
-
const p = require2(moduleName);
|
|
4077
|
-
const b = await p.chromium.launch({ headless: true });
|
|
4360
|
+
onLogLine?.("[playwright] \u81EA\u68C0\uFF1A\u542F\u52A8 Chromium");
|
|
4078
4361
|
try {
|
|
4079
|
-
const
|
|
4080
|
-
const
|
|
4081
|
-
await
|
|
4082
|
-
|
|
4083
|
-
|
|
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;
|
|
4084
4377
|
}
|
|
4085
4378
|
}
|
|
4086
4379
|
async function installPlaywrightBrowser(config, onLogLine, options) {
|
|
@@ -4104,36 +4397,45 @@ async function installPlaywrightBrowser(config, onLogLine, options) {
|
|
|
4104
4397
|
const rankedHosts = await rankPlaywrightHosts(config);
|
|
4105
4398
|
const timeoutMs = playwrightInstallTimeoutMs();
|
|
4106
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`);
|
|
4107
|
-
let
|
|
4400
|
+
let lastHost = "";
|
|
4108
4401
|
for (let i = 0; i < rankedHosts.length; i++) {
|
|
4109
4402
|
const host = rankedHosts[i];
|
|
4403
|
+
lastHost = host;
|
|
4110
4404
|
if (i > 0) {
|
|
4111
|
-
onLogLine?.(`[playwright] \
|
|
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
|
+
);
|
|
4112
4410
|
}
|
|
4113
|
-
onLogLine?.(
|
|
4114
|
-
`[playwright] \u4F7F\u7528\u5185\u7F6E playwright@${version} CLI\uFF0C\u955C\u50CF ${host}\uFF0C\u76EE\u6807: ${targets.length ? targets.join(",") : "all"}${options?.force ? " (--force)" : ""}`
|
|
4115
|
-
);
|
|
4116
4411
|
try {
|
|
4117
4412
|
await runCommand2(command, installArgs, {
|
|
4118
4413
|
env: { PLAYWRIGHT_DOWNLOAD_HOST: host },
|
|
4119
4414
|
timeoutMs,
|
|
4120
|
-
onLogLine
|
|
4415
|
+
onLogLine: createPlaywrightInstallLogSink(onLogLine)
|
|
4121
4416
|
});
|
|
4122
4417
|
progress("playwright.browser.install.done", { selectedHost: host, attempt: i + 1 });
|
|
4123
|
-
|
|
4418
|
+
onLogLine?.(`[playwright] \u6D4F\u89C8\u5668\u5B89\u88C5\u5B8C\u6210\uFF08${host}\uFF09`);
|
|
4419
|
+
return true;
|
|
4124
4420
|
} catch (error) {
|
|
4125
|
-
|
|
4126
|
-
|
|
4421
|
+
onLogLine?.(`[playwright][warn] \u955C\u50CF ${host} \u5931\u8D25: ${briefErrorMessage(error)}`);
|
|
4422
|
+
depsStructuredLog("warn", {
|
|
4127
4423
|
event: "deps.playwright.browser.install.host.fail",
|
|
4128
4424
|
details: {
|
|
4129
4425
|
host,
|
|
4130
4426
|
attempt: i + 1,
|
|
4131
|
-
message:
|
|
4427
|
+
message: briefErrorMessage(error)
|
|
4132
4428
|
}
|
|
4133
4429
|
});
|
|
4134
4430
|
}
|
|
4135
4431
|
}
|
|
4136
|
-
|
|
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;
|
|
4137
4439
|
}
|
|
4138
4440
|
async function checkPlaywrightLaunchable() {
|
|
4139
4441
|
try {
|
|
@@ -4159,7 +4461,7 @@ async function verifyAppiumCommand() {
|
|
|
4159
4461
|
}
|
|
4160
4462
|
}
|
|
4161
4463
|
async function getInstalledAppiumDrivers() {
|
|
4162
|
-
const check = await
|
|
4464
|
+
const check = await runCommandCapture2("npm", ["exec", "appium", "driver", "list", "--installed", "--json"]);
|
|
4163
4465
|
if (check.code === 0 && check.stdout) {
|
|
4164
4466
|
try {
|
|
4165
4467
|
const parsed = JSON.parse(check.stdout);
|
|
@@ -4168,7 +4470,7 @@ async function getInstalledAppiumDrivers() {
|
|
|
4168
4470
|
} catch {
|
|
4169
4471
|
}
|
|
4170
4472
|
}
|
|
4171
|
-
const fallback = await
|
|
4473
|
+
const fallback = await runCommandCapture2("npm", ["exec", "appium", "driver", "list", "--installed"]);
|
|
4172
4474
|
if (fallback.code !== 0) {
|
|
4173
4475
|
return [];
|
|
4174
4476
|
}
|
|
@@ -4376,6 +4678,28 @@ async function saveInstallState(state) {
|
|
|
4376
4678
|
await import_promises5.default.writeFile(file, JSON.stringify(state, null, 2), "utf8");
|
|
4377
4679
|
}
|
|
4378
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) {
|
|
4379
4703
|
const startedAt = Date.now();
|
|
4380
4704
|
const only = options?.only ?? "all";
|
|
4381
4705
|
const force = options?.force === true;
|
|
@@ -4416,12 +4740,12 @@ async function ensureDriverDependencies(config, options) {
|
|
|
4416
4740
|
}
|
|
4417
4741
|
if (packagesToInstall.length > 0) {
|
|
4418
4742
|
progress("deps.package.missing", { missing, installing: packagesToInstall });
|
|
4419
|
-
|
|
4743
|
+
onLogLine?.(`[deps] \u5C06\u5B89\u88C5: ${packagesToInstall.join(", ")}`);
|
|
4420
4744
|
await runInstallWithPriority(config, packagesToInstall, onLogLine);
|
|
4421
4745
|
installedPackages.push(...packagesToInstall);
|
|
4422
4746
|
} else {
|
|
4423
4747
|
progress("deps.package.ok", { missing: [] });
|
|
4424
|
-
|
|
4748
|
+
depsStructuredLog("info", { event: "deps.check.ok", details: { missing: [] } });
|
|
4425
4749
|
}
|
|
4426
4750
|
if (hasPackage("playwright") && needPlaywright) {
|
|
4427
4751
|
progress("playwright.selfcheck.start");
|
|
@@ -4429,7 +4753,7 @@ async function ensureDriverDependencies(config, options) {
|
|
|
4429
4753
|
const reinstallForTargets = force && Boolean(pwOverride?.length);
|
|
4430
4754
|
const userRequestedBrowserTargets = Boolean(pwOverride?.length);
|
|
4431
4755
|
if (!launchOk || reinstallForTargets || userRequestedBrowserTargets || force) {
|
|
4432
|
-
|
|
4756
|
+
depsStructuredLog("warn", {
|
|
4433
4757
|
event: "deps.playwright.browser.missing",
|
|
4434
4758
|
details: {
|
|
4435
4759
|
action: "install-playwright-browser",
|
|
@@ -4442,19 +4766,21 @@ async function ensureDriverDependencies(config, options) {
|
|
|
4442
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"
|
|
4443
4767
|
);
|
|
4444
4768
|
}
|
|
4445
|
-
await installPlaywrightBrowser(configForPlaywright, onLogLine, {
|
|
4769
|
+
const browserInstalled = await installPlaywrightBrowser(configForPlaywright, onLogLine, {
|
|
4446
4770
|
force: force || reinstallForTargets || !launchOk
|
|
4447
4771
|
});
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
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
|
+
}
|
|
4452
4779
|
} else if (!force && state.playwrightReady) {
|
|
4453
4780
|
progress("playwright.selfcheck.skip.cache", { cached: true, healthy: true });
|
|
4454
4781
|
} else {
|
|
4455
4782
|
progress("playwright.selfcheck.verify");
|
|
4456
|
-
await verifyPlaywrightSelfTest(onLogLine);
|
|
4457
|
-
state.playwrightReady = true;
|
|
4783
|
+
state.playwrightReady = await verifyPlaywrightSelfTest(onLogLine);
|
|
4458
4784
|
progress("playwright.selfcheck.done");
|
|
4459
4785
|
}
|
|
4460
4786
|
}
|
|
@@ -4468,12 +4794,16 @@ async function ensureDriverDependencies(config, options) {
|
|
|
4468
4794
|
progress("selenium.check.done", sel);
|
|
4469
4795
|
}
|
|
4470
4796
|
if (hasPackage("appium") && needAppium) {
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
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)}`);
|
|
4477
4807
|
}
|
|
4478
4808
|
}
|
|
4479
4809
|
if (hasPackage("appium") && needDrivers) {
|
|
@@ -4492,11 +4822,15 @@ async function ensureDriverDependencies(config, options) {
|
|
|
4492
4822
|
requiredDrivers: required
|
|
4493
4823
|
}
|
|
4494
4824
|
};
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
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
|
+
}
|
|
4500
4834
|
}
|
|
4501
4835
|
}
|
|
4502
4836
|
state.androidHome = homes.androidHome;
|
|
@@ -4504,7 +4838,7 @@ async function ensureDriverDependencies(config, options) {
|
|
|
4504
4838
|
await saveInstallState(state);
|
|
4505
4839
|
const installedPkgs = Array.from(new Set(installedPackages));
|
|
4506
4840
|
progress("deps.ensure.done", { installedPackages: installedPkgs, missingDetected: missing });
|
|
4507
|
-
|
|
4841
|
+
depsStructuredLog("info", { event: "deps.install.completed", details: { installedPackages: installedPkgs } });
|
|
4508
4842
|
const requestedPackages = ["playwright", "appium"].filter((pkg) => pkg === "playwright" ? needPlaywright : needAppium);
|
|
4509
4843
|
let nativeDriversDir;
|
|
4510
4844
|
let geckodriverPath;
|
|
@@ -4588,7 +4922,7 @@ async function getDependencyHealth(config) {
|
|
|
4588
4922
|
missingAppiumDrivers
|
|
4589
4923
|
};
|
|
4590
4924
|
}
|
|
4591
|
-
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;
|
|
4592
4926
|
var init_dependency_installer = __esm({
|
|
4593
4927
|
"../ada-agent/src/dependency-installer.ts"() {
|
|
4594
4928
|
import_node_module = require("node:module");
|
|
@@ -4600,6 +4934,7 @@ var init_dependency_installer = __esm({
|
|
|
4600
4934
|
init_config();
|
|
4601
4935
|
init_src2();
|
|
4602
4936
|
require2 = (0, import_node_module.createRequire)(import_node_path5.default.join(process.cwd(), "package.json"));
|
|
4937
|
+
PINNED_PLAYWRIGHT_VERSION = "1.59.1";
|
|
4603
4938
|
DEFAULT_NPM_REGISTRY_CANDIDATES = [
|
|
4604
4939
|
"https://registry.npmmirror.com",
|
|
4605
4940
|
"https://mirrors.cloud.tencent.com/npm",
|
|
@@ -4616,6 +4951,15 @@ var init_dependency_installer = __esm({
|
|
|
4616
4951
|
"appium.driver.ensure.start",
|
|
4617
4952
|
"deps.ensure.done"
|
|
4618
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
|
+
};
|
|
4619
4963
|
DEFAULT_PLAYWRIGHT_HOST_CANDIDATES = [
|
|
4620
4964
|
"https://cdn.playwright.dev",
|
|
4621
4965
|
"https://playwright.azureedge.net",
|
|
@@ -9168,9 +9512,15 @@ async function runBootstrapInstallDeps(argv2) {
|
|
|
9168
9512
|
console.error(`[ADA-MCP] dependency bootstrap start (scope=${label}, force=${plan.force})`);
|
|
9169
9513
|
for (const scope of plan.scopes) {
|
|
9170
9514
|
console.error(`[ADA-MCP] installing: ${scope}`);
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
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
|
+
}
|
|
9174
9524
|
}
|
|
9175
9525
|
console.error("[ADA-MCP] dependency bootstrap done");
|
|
9176
9526
|
}
|