@ada-mcp/mcp-server 0.1.5 → 0.1.7
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 +20 -54
- package/dist/cli.cjs +78 -45
- package/package.json +4 -3
- package/scripts/playwright-probe.mjs +98 -0
- package/scripts/preinstall-probes.mjs +79 -0
- package/scripts/registry-probe.mjs +0 -2
- package/scripts/preinstall-registry.mjs +0 -70
package/README.md
CHANGED
|
@@ -6,24 +6,27 @@ ADA MCP server package that supports:
|
|
|
6
6
|
- Remote HTTP mode (`server`) with API key authentication
|
|
7
7
|
- MCP **Streamable HTTP** on `POST|GET|DELETE /mcp` (same port as legacy REST), with optional SSE per MCP spec (`@modelcontextprotocol/sdk` transport)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 标准安装(Cursor / MCP)
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
请使用 **`@ada-mcp/launcher@0.1.2`** 拉起本包(见 [launcher README](../ada-mcp-launcher/README.md)):
|
|
12
12
|
|
|
13
|
-
```
|
|
14
|
-
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"ada-mcp": {
|
|
17
|
+
"command": "pnpm",
|
|
18
|
+
"args": ["dlx", "@ada-mcp/launcher@0.1.2"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
15
22
|
```
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
本包版本:**`@ada-mcp/mcp-server@0.1.6`**(由 launcher 默认拉取)。
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
pnpm dlx @ada-mcp/mcp-server
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
也可用 npm:
|
|
26
|
+
直接调试本包(无 launcher 拉包前测速):
|
|
24
27
|
|
|
25
28
|
```bash
|
|
26
|
-
|
|
29
|
+
pnpm dlx @ada-mcp/mcp-server@0.1.6
|
|
27
30
|
```
|
|
28
31
|
|
|
29
32
|
## 启动时自动安装依赖(默认仅 Playwright)
|
|
@@ -55,9 +58,9 @@ npx -y @ada-mcp/mcp-server
|
|
|
55
58
|
|------|------------------|
|
|
56
59
|
| `pnpm dlx @ada-mcp/launcher` | **是** — 拉包前测速(推荐) |
|
|
57
60
|
| `pnpm dlx @ada-mcp/mcp-server` | tarball 仍走本机源;**同次安装的依赖**由 `preinstall` 测速(0.1.5+) |
|
|
58
|
-
| 启动后 `install-deps` | 是 —
|
|
61
|
+
| 启动后 `install-deps` | 是 — 内置国内镜像测速(**无需配置**) |
|
|
59
62
|
|
|
60
|
-
默认 npm 探测候选(按优先级,延迟相同取靠前):阿里云 npmmirror → 腾讯云 →
|
|
63
|
+
默认 npm 探测候选(按优先级,延迟相同取靠前):阿里云 npmmirror → 腾讯云 → 华为云 → npm 官方。
|
|
61
64
|
|
|
62
65
|
| 变量 | 说明 |
|
|
63
66
|
|------|------|
|
|
@@ -75,52 +78,15 @@ npx -y @ada-mcp/mcp-server
|
|
|
75
78
|
- `--install-deps-force`
|
|
76
79
|
- `--geckodriver-version=latest` `--chromedriver-version=match-chrome`
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
```json
|
|
81
|
-
{
|
|
82
|
-
"mcpServers": {
|
|
83
|
-
"ada-mcp": {
|
|
84
|
-
"command": "pnpm",
|
|
85
|
-
"args": ["dlx", "@ada-mcp/mcp-server", "--install-deps=all"]
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
仅 Playwright(默认,可省略 `env`):
|
|
81
|
+
在标准 `args` 后追加,例如安装全部依赖:
|
|
92
82
|
|
|
93
83
|
```json
|
|
94
|
-
|
|
95
|
-
"mcpServers": {
|
|
96
|
-
"ada-mcp": {
|
|
97
|
-
"command": "pnpm",
|
|
98
|
-
"args": ["dlx", "@ada-mcp/mcp-server"],
|
|
99
|
-
"env": {
|
|
100
|
-
"ADA_MCP_INSTALL_DEPS": "playwright"
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
84
|
+
"args": ["dlx", "@ada-mcp/launcher@0.1.2", "--install-deps=all"]
|
|
105
85
|
```
|
|
106
86
|
|
|
107
|
-
## Cursor MCP
|
|
87
|
+
## Cursor MCP 配置
|
|
108
88
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
```json
|
|
112
|
-
{
|
|
113
|
-
"mcpServers": {
|
|
114
|
-
"ada-mcp": {
|
|
115
|
-
"command": "pnpm",
|
|
116
|
-
"args": ["dlx", "@ada-mcp/launcher"]
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
或 `["dlx", "@ada-mcp/mcp-server@0.1.5"]`(依赖安装走 preinstall 探测,无需 `npm_config_registry`)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
```
|
|
89
|
+
与上文**标准配置**相同:`pnpm` + `dlx @ada-mcp/launcher@0.1.2`。
|
|
124
90
|
|
|
125
91
|
Windows 若找不到 `pnpm`,可写完整路径,例如 `C:\\Users\\<你>\\AppData\\Roaming\\npm\\pnpm.cmd`,或改用 npx:
|
|
126
92
|
|
package/dist/cli.cjs
CHANGED
|
@@ -23,6 +23,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
mod
|
|
24
24
|
));
|
|
25
25
|
|
|
26
|
+
// src/bootstrap-deps.ts
|
|
27
|
+
var import_node_fs2 = __toESM(require("node:fs"));
|
|
28
|
+
var import_node_path10 = __toESM(require("node:path"));
|
|
29
|
+
|
|
26
30
|
// ../ada-agent/dist/config.js
|
|
27
31
|
var import_promises2 = __toESM(require("node:fs/promises"), 1);
|
|
28
32
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
@@ -6514,6 +6518,26 @@ function resolveBootstrapInstallDeps(argv2) {
|
|
|
6514
6518
|
if (nativeDir) extras.nativeDriversDir = nativeDir;
|
|
6515
6519
|
return { skip: false, scopes, force, extras };
|
|
6516
6520
|
}
|
|
6521
|
+
function applyPreinstallPlaywrightHostFile() {
|
|
6522
|
+
if (process.env.PLAYWRIGHT_DOWNLOAD_HOST?.trim()) {
|
|
6523
|
+
return;
|
|
6524
|
+
}
|
|
6525
|
+
const roots = [process.env.INIT_CWD, process.cwd()].filter(
|
|
6526
|
+
(x) => typeof x === "string" && x.trim().length > 0
|
|
6527
|
+
);
|
|
6528
|
+
for (const root of roots) {
|
|
6529
|
+
const file = import_node_path10.default.join(root, ".ada-mcp-playwright-host");
|
|
6530
|
+
try {
|
|
6531
|
+
const host = import_node_fs2.default.readFileSync(file, "utf8").trim();
|
|
6532
|
+
if (host.length > 0) {
|
|
6533
|
+
process.env.PLAYWRIGHT_DOWNLOAD_HOST = host;
|
|
6534
|
+
console.error(`[ADA-MCP] using playwright CDN from ${file}: ${host}`);
|
|
6535
|
+
return;
|
|
6536
|
+
}
|
|
6537
|
+
} catch {
|
|
6538
|
+
}
|
|
6539
|
+
}
|
|
6540
|
+
}
|
|
6517
6541
|
function ensureDefaultInstallTimeouts() {
|
|
6518
6542
|
if (!process.env.ADA_INSTALL_STRATEGY_TIMEOUT_MS?.trim()) {
|
|
6519
6543
|
process.env.ADA_INSTALL_STRATEGY_TIMEOUT_MS = "120000";
|
|
@@ -6523,6 +6547,7 @@ function ensureDefaultInstallTimeouts() {
|
|
|
6523
6547
|
}
|
|
6524
6548
|
}
|
|
6525
6549
|
async function runBootstrapInstallDeps(argv2) {
|
|
6550
|
+
applyPreinstallPlaywrightHostFile();
|
|
6526
6551
|
ensureDefaultInstallTimeouts();
|
|
6527
6552
|
const plan = resolveBootstrapInstallDeps(argv2);
|
|
6528
6553
|
if (plan.skip) {
|
|
@@ -6542,9 +6567,9 @@ async function runBootstrapInstallDeps(argv2) {
|
|
|
6542
6567
|
|
|
6543
6568
|
// src/main.ts
|
|
6544
6569
|
var import_promises13 = __toESM(require("node:fs/promises"));
|
|
6545
|
-
var
|
|
6570
|
+
var import_node_fs4 = require("node:fs");
|
|
6546
6571
|
var import_node_net2 = __toESM(require("node:net"));
|
|
6547
|
-
var
|
|
6572
|
+
var import_node_path14 = __toESM(require("node:path"));
|
|
6548
6573
|
var import_node_child_process5 = require("node:child_process");
|
|
6549
6574
|
var import_node_url4 = require("node:url");
|
|
6550
6575
|
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
@@ -6552,8 +6577,8 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
|
6552
6577
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
6553
6578
|
|
|
6554
6579
|
// src/executor.ts
|
|
6555
|
-
var
|
|
6556
|
-
var
|
|
6580
|
+
var import_node_fs3 = require("node:fs");
|
|
6581
|
+
var import_node_path11 = __toESM(require("node:path"));
|
|
6557
6582
|
var import_node_url3 = require("node:url");
|
|
6558
6583
|
var import_meta = {};
|
|
6559
6584
|
function ensureBundledPluginDir() {
|
|
@@ -6562,16 +6587,16 @@ function ensureBundledPluginDir() {
|
|
|
6562
6587
|
}
|
|
6563
6588
|
const candidates = [];
|
|
6564
6589
|
try {
|
|
6565
|
-
const here =
|
|
6566
|
-
candidates.push(
|
|
6590
|
+
const here = import_node_path11.default.dirname((0, import_node_url3.fileURLToPath)(import_meta.url));
|
|
6591
|
+
candidates.push(import_node_path11.default.join(here, "..", "plugins"));
|
|
6567
6592
|
} catch {
|
|
6568
6593
|
}
|
|
6569
6594
|
const dirname = globalThis.__dirname;
|
|
6570
6595
|
if (typeof dirname === "string") {
|
|
6571
|
-
candidates.push(
|
|
6596
|
+
candidates.push(import_node_path11.default.join(dirname, "..", "plugins"));
|
|
6572
6597
|
}
|
|
6573
6598
|
for (const dir of candidates) {
|
|
6574
|
-
if ((0,
|
|
6599
|
+
if ((0, import_node_fs3.existsSync)(dir)) {
|
|
6575
6600
|
process.env.ADA_PLUGIN_DIR = dir;
|
|
6576
6601
|
return;
|
|
6577
6602
|
}
|
|
@@ -6607,30 +6632,30 @@ async function closeAllSessions() {
|
|
|
6607
6632
|
|
|
6608
6633
|
// src/config.ts
|
|
6609
6634
|
var import_promises11 = __toESM(require("node:fs/promises"));
|
|
6610
|
-
var
|
|
6635
|
+
var import_node_path12 = __toESM(require("node:path"));
|
|
6611
6636
|
|
|
6612
6637
|
// src/bundled-config.generated.ts
|
|
6613
|
-
var bundledDefaultConfigYaml2 = 'agent:\r\n id: "ada-agent-local"\r\n mode: "foreground"\r\n setupOnFirstRun: true\r\n\r\nbootstrapUI:\r\n enabled: true\r\n mode: "auto" # auto | cli | gui\r\n host: "127.0.0.1"\r\n port: 17650\r\n autoOpenBrowser: true\r\n sessionTtlSec: 600\r\n secretsProvider: "auto" # auto | keychain | credman | file\r\n native:\r\n enabled: false\r\n command: "" # e.g. ./bootstrap-ui / .\\bootstrap-ui.exe\r\n args: []\r\n timeoutMs: 120000\r\n fallbackToWeb: true\r\n\r\ntransport:\r\n mode: "auto"\r\n streamProtocol: "websocket"\r\n requestPath: "/api/v1/execute"\r\n healthPath: "/health"\r\n streamPath: "/ws"\r\n requestTimeoutMs: 15000\r\n\r\ngraphics:\r\n enabled: false\r\n fallbackOnSemanticFailure: false\r\n minConfidence: 0.8\r\n\r\nmonitoring:\r\n enabled: false\r\n platforms: ["web", "android", "ios", "harmony"] # \u53EF\u9009\u5B50\u96C6\r\n sampleEvery: 1 # \u6BCF N \u6761\u64CD\u4F5C\u91C7\u6837\u4E00\u6B21\uFF0C1 \u8868\u793A\u5168\u91CF\r\n outputDir: "artifacts/monitoring"\r\n onFailureOnly: false # true \u65F6\u4EC5\u5931\u8D25\u64CD\u4F5C\u6293\u56FE\uFF0C\u6027\u80FD\u66F4\u4F18\r\n groupBySession: true # \u6309 sessionId/requestId \u5206\u5C42\u5F52\u6863\r\n nonBlocking: true # true \u65F6\u76D1\u63A7\u5F02\u6B65\u6267\u884C\uFF0C\u4E0D\u963B\u585E\u4E3B\u94FE\u8DEF\r\n resolution:\r\n maxWidth: 1280\r\n maxHeight: 720\r\n keepAspectRatio: true # \u4FDD\u6301\u6BD4\u4F8B\uFF0C\u907F\u514D\u76D1\u63A7\u56FE\u50CF\u53D8\u5F62\r\n\r\nqueue:\r\n inboxDir: "tasks/inbox"\r\n processedDir: "tasks/processed"\r\n failedDir: "tasks/failed"\r\n pollIntervalMs: 3000\r\n maxFileRetryAttempts: 2\r\n\r\ndependencies:\r\n autoInstallOnStart: true\r\n playwrightBrowser: "chromium" # chromium | firefox | webkit | all\r\n playwrightInstallTargets: ["
|
|
6638
|
+
var bundledDefaultConfigYaml2 = 'agent:\r\n id: "ada-agent-local"\r\n mode: "foreground"\r\n setupOnFirstRun: true\r\n\r\nbootstrapUI:\r\n enabled: true\r\n mode: "auto" # auto | cli | gui\r\n host: "127.0.0.1"\r\n port: 17650\r\n autoOpenBrowser: true\r\n sessionTtlSec: 600\r\n secretsProvider: "auto" # auto | keychain | credman | file\r\n native:\r\n enabled: false\r\n command: "" # e.g. ./bootstrap-ui / .\\bootstrap-ui.exe\r\n args: []\r\n timeoutMs: 120000\r\n fallbackToWeb: true\r\n\r\ntransport:\r\n mode: "auto"\r\n streamProtocol: "websocket"\r\n requestPath: "/api/v1/execute"\r\n healthPath: "/health"\r\n streamPath: "/ws"\r\n requestTimeoutMs: 15000\r\n\r\ngraphics:\r\n enabled: false\r\n fallbackOnSemanticFailure: false\r\n minConfidence: 0.8\r\n\r\nmonitoring:\r\n enabled: false\r\n platforms: ["web", "android", "ios", "harmony"] # \u53EF\u9009\u5B50\u96C6\r\n sampleEvery: 1 # \u6BCF N \u6761\u64CD\u4F5C\u91C7\u6837\u4E00\u6B21\uFF0C1 \u8868\u793A\u5168\u91CF\r\n outputDir: "artifacts/monitoring"\r\n onFailureOnly: false # true \u65F6\u4EC5\u5931\u8D25\u64CD\u4F5C\u6293\u56FE\uFF0C\u6027\u80FD\u66F4\u4F18\r\n groupBySession: true # \u6309 sessionId/requestId \u5206\u5C42\u5F52\u6863\r\n nonBlocking: true # true \u65F6\u76D1\u63A7\u5F02\u6B65\u6267\u884C\uFF0C\u4E0D\u963B\u585E\u4E3B\u94FE\u8DEF\r\n resolution:\r\n maxWidth: 1280\r\n maxHeight: 720\r\n keepAspectRatio: true # \u4FDD\u6301\u6BD4\u4F8B\uFF0C\u907F\u514D\u76D1\u63A7\u56FE\u50CF\u53D8\u5F62\r\n\r\nqueue:\r\n inboxDir: "tasks/inbox"\r\n processedDir: "tasks/processed"\r\n failedDir: "tasks/failed"\r\n pollIntervalMs: 3000\r\n maxFileRetryAttempts: 2\r\n\r\ndependencies:\r\n autoInstallOnStart: true\r\n playwrightBrowser: "chromium" # chromium | firefox | webkit | all\r\n playwrightInstallTargets: ["chromium"] # chromium | chrome | msedge | firefox | webkit | all\r\n playwrightDownloadHost: "https://cdn.playwright.dev"\r\n # \u56FD\u5185 npm \u955C\u50CF\uFF08\u6309\u4F18\u5148\u7EA7\uFF1Binstall-deps \u542F\u52A8\u65F6\u6D4B\u901F\u9009\u6700\u5FEB\uFF0C\u65E0\u9700\u7528\u6237\u914D\u7F6E\uFF09\r\n npmRegistryCandidates:\r\n - "https://registry.npmmirror.com" # \u963F\u91CC\u4E91 / npmmirror\uFF08\u63A8\u8350\uFF09\r\n - "https://mirrors.cloud.tencent.com/npm" # \u817E\u8BAF\u4E91\r\n - "https://repo.huaweicloud.com/repository/npm" # \u534E\u4E3A\u4E91\r\n - "https://registry.npmjs.org" # \u5B98\u65B9\u515C\u5E95\r\n playwrightHostCandidates:\r\n - "https://cdn.playwright.dev"\r\n - "https://playwright.azureedge.net"\r\n - "https://npmmirror.com/mirrors/playwright"\r\n - "https://cdn.npmmirror.com/binaries/playwright"\r\n # \u539F\u751F WebDriver\uFF08geckodriver / chromedriver\uFF09\u7EDF\u4E00\u653E\u5728\u9879\u76EE dirver \u76EE\u5F55\r\n nativeDriversDir: "dirver"\r\n geckodriverVersion: "latest" # \u5982 0.36.0\uFF1Binstall-deps --only=selenium \u65F6\u4E0B\u8F7D\u5230\u6B64\u76EE\u5F55\r\n chromedriverVersion: "latest" # \u5982 137\u3001135\u3001match-chrome\uFF08\u5339\u914D\u672C\u673A Chrome \u4E3B\u7248\u672C\uFF09\r\n\r\nappium:\r\n serverUrl: "http://127.0.0.1:4723"\r\n requiredDrivers: ["uiautomator2", "xcuitest", "harmonyos"]\r\n';
|
|
6614
6639
|
|
|
6615
6640
|
// src/config.ts
|
|
6616
|
-
var DEFAULT_CONFIG_RELATIVE2 =
|
|
6617
|
-
var LOCAL_DATA_DIR2 =
|
|
6618
|
-
var EFFECTIVE_CONFIG_FILE2 =
|
|
6641
|
+
var DEFAULT_CONFIG_RELATIVE2 = import_node_path12.default.join("config", "default.yaml");
|
|
6642
|
+
var LOCAL_DATA_DIR2 = import_node_path12.default.join(".ada-agent");
|
|
6643
|
+
var EFFECTIVE_CONFIG_FILE2 = import_node_path12.default.join(LOCAL_DATA_DIR2, "agent.config.yaml");
|
|
6619
6644
|
async function resolveWorkspaceRoot4(startDir = process.cwd()) {
|
|
6620
6645
|
return resolveWorkspaceRoot(DEFAULT_CONFIG_RELATIVE2, startDir);
|
|
6621
6646
|
}
|
|
6622
6647
|
async function loadAgentConfig(cwd = process.cwd()) {
|
|
6623
6648
|
let root = await resolveWorkspaceRoot4(cwd);
|
|
6624
|
-
const defaultPath =
|
|
6649
|
+
const defaultPath = import_node_path12.default.join(root, DEFAULT_CONFIG_RELATIVE2);
|
|
6625
6650
|
let defaultRaw;
|
|
6626
6651
|
try {
|
|
6627
6652
|
defaultRaw = await import_promises11.default.readFile(defaultPath, "utf8");
|
|
6628
6653
|
} catch {
|
|
6629
6654
|
defaultRaw = bundledDefaultConfigYaml2;
|
|
6630
|
-
root =
|
|
6655
|
+
root = import_node_path12.default.dirname(process.execPath);
|
|
6631
6656
|
}
|
|
6632
6657
|
const defaultConfig2 = jsYaml.load(defaultRaw) ?? {};
|
|
6633
|
-
const effectivePath =
|
|
6658
|
+
const effectivePath = import_node_path12.default.join(root, EFFECTIVE_CONFIG_FILE2);
|
|
6634
6659
|
try {
|
|
6635
6660
|
const effectiveFile = await import_promises11.default.readFile(effectivePath, "utf8");
|
|
6636
6661
|
const effectiveConfig = jsYaml.load(effectiveFile) ?? {};
|
|
@@ -6642,7 +6667,7 @@ async function loadAgentConfig(cwd = process.cwd()) {
|
|
|
6642
6667
|
|
|
6643
6668
|
// src/monitoring.ts
|
|
6644
6669
|
var import_promises12 = __toESM(require("node:fs/promises"));
|
|
6645
|
-
var
|
|
6670
|
+
var import_node_path13 = __toESM(require("node:path"));
|
|
6646
6671
|
var import_jimp2 = require("jimp");
|
|
6647
6672
|
function getScreenshotPath2(result) {
|
|
6648
6673
|
const value = result.data?.screenshot;
|
|
@@ -6650,9 +6675,9 @@ function getScreenshotPath2(result) {
|
|
|
6650
6675
|
}
|
|
6651
6676
|
function buildOutputPath(options, command) {
|
|
6652
6677
|
if (options.groupBySession) {
|
|
6653
|
-
return
|
|
6678
|
+
return import_node_path13.default.join(options.outputDir, command.sessionId, `${command.requestId}.png`);
|
|
6654
6679
|
}
|
|
6655
|
-
return
|
|
6680
|
+
return import_node_path13.default.join(options.outputDir, `${command.requestId}.png`);
|
|
6656
6681
|
}
|
|
6657
6682
|
async function captureMcpMonitor(command, result, options, runCommand4) {
|
|
6658
6683
|
if (!options.enabled) {
|
|
@@ -6682,7 +6707,7 @@ async function captureMcpMonitor(command, result, options, runCommand4) {
|
|
|
6682
6707
|
return null;
|
|
6683
6708
|
}
|
|
6684
6709
|
const targetPath = buildOutputPath(options, command);
|
|
6685
|
-
await import_promises12.default.mkdir(
|
|
6710
|
+
await import_promises12.default.mkdir(import_node_path13.default.dirname(targetPath), { recursive: true });
|
|
6686
6711
|
const image = await import_jimp2.Jimp.read(sourcePath);
|
|
6687
6712
|
if (options.keepAspectRatio) {
|
|
6688
6713
|
image.scaleToFit({ w: options.maxWidth, h: options.maxHeight });
|
|
@@ -6726,8 +6751,8 @@ function parseServerEndpoint(serverUrl) {
|
|
|
6726
6751
|
return { host, port };
|
|
6727
6752
|
}
|
|
6728
6753
|
function commandAvailable(command) {
|
|
6729
|
-
if (
|
|
6730
|
-
return (0,
|
|
6754
|
+
if (import_node_path14.default.isAbsolute(command)) {
|
|
6755
|
+
return (0, import_node_fs4.existsSync)(command);
|
|
6731
6756
|
}
|
|
6732
6757
|
const checker = process.platform === "win32" ? "where.exe" : "which";
|
|
6733
6758
|
const checked = (0, import_node_child_process5.spawnSync)(checker, [command], {
|
|
@@ -6766,12 +6791,12 @@ function spawnDetachedChecked(cmd, args, env) {
|
|
|
6766
6791
|
}
|
|
6767
6792
|
function resolveAppiumNodeEntrypoint() {
|
|
6768
6793
|
const candidates = [
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6794
|
+
import_node_path14.default.join(process.cwd(), "node_modules", "appium", "build", "lib", "main.js"),
|
|
6795
|
+
import_node_path14.default.join(process.cwd(), "..", "node_modules", "appium", "build", "lib", "main.js"),
|
|
6796
|
+
import_node_path14.default.join(process.cwd(), "..", "..", "node_modules", "appium", "build", "lib", "main.js")
|
|
6772
6797
|
];
|
|
6773
6798
|
for (const p of candidates) {
|
|
6774
|
-
if ((0,
|
|
6799
|
+
if ((0, import_node_fs4.existsSync)(p)) {
|
|
6775
6800
|
return p;
|
|
6776
6801
|
}
|
|
6777
6802
|
}
|
|
@@ -6786,15 +6811,15 @@ function loadPersistedHomes() {
|
|
|
6786
6811
|
return persistedHomesCache;
|
|
6787
6812
|
}
|
|
6788
6813
|
const candidates = [
|
|
6789
|
-
|
|
6790
|
-
|
|
6814
|
+
import_node_path14.default.join(process.cwd(), ".ada-agent", "deps-install-state.json"),
|
|
6815
|
+
import_node_path14.default.join(process.cwd(), "..", ".ada-agent", "deps-install-state.json")
|
|
6791
6816
|
];
|
|
6792
6817
|
for (const file of candidates) {
|
|
6793
|
-
if (!(0,
|
|
6818
|
+
if (!(0, import_node_fs4.existsSync)(file)) {
|
|
6794
6819
|
continue;
|
|
6795
6820
|
}
|
|
6796
6821
|
try {
|
|
6797
|
-
const raw = (0,
|
|
6822
|
+
const raw = (0, import_node_fs4.readFileSync)(file, "utf8");
|
|
6798
6823
|
const parsed = JSON.parse(raw);
|
|
6799
6824
|
const androidHome = typeof parsed.androidHome === "string" ? parsed.androidHome.trim() : "";
|
|
6800
6825
|
const appiumHome = typeof parsed.appiumHome === "string" ? parsed.appiumHome.trim() : "";
|
|
@@ -6817,36 +6842,36 @@ function resolveAndroidSdkRoot() {
|
|
|
6817
6842
|
shell: false
|
|
6818
6843
|
});
|
|
6819
6844
|
const adbPath = (adbLookup.stdout ?? "").split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
6820
|
-
const adbSdkRoot = adbPath ?
|
|
6845
|
+
const adbSdkRoot = adbPath ? import_node_path14.default.dirname(import_node_path14.default.dirname(adbPath)) : null;
|
|
6821
6846
|
const candidates = [
|
|
6822
6847
|
process.env.ANDROID_SDK_ROOT,
|
|
6823
6848
|
process.env.ANDROID_HOME,
|
|
6824
6849
|
persisted.androidHome,
|
|
6825
6850
|
adbSdkRoot,
|
|
6826
|
-
process.env.LOCALAPPDATA ?
|
|
6827
|
-
process.env.USERPROFILE ?
|
|
6851
|
+
process.env.LOCALAPPDATA ? import_node_path14.default.join(process.env.LOCALAPPDATA, "Android", "Sdk") : null,
|
|
6852
|
+
process.env.USERPROFILE ? import_node_path14.default.join(process.env.USERPROFILE, "AppData", "Local", "Android", "Sdk") : null
|
|
6828
6853
|
].map((v) => typeof v === "string" ? v.trim() : "").filter(Boolean);
|
|
6829
6854
|
for (const sdkRoot of candidates) {
|
|
6830
|
-
if (persisted.androidHome && sdkRoot === persisted.androidHome && (0,
|
|
6855
|
+
if (persisted.androidHome && sdkRoot === persisted.androidHome && (0, import_node_fs4.existsSync)(sdkRoot)) {
|
|
6831
6856
|
return sdkRoot;
|
|
6832
6857
|
}
|
|
6833
|
-
const platformTools =
|
|
6834
|
-
if ((0,
|
|
6858
|
+
const platformTools = import_node_path14.default.join(sdkRoot, "platform-tools");
|
|
6859
|
+
if ((0, import_node_fs4.existsSync)(platformTools)) {
|
|
6835
6860
|
return sdkRoot;
|
|
6836
6861
|
}
|
|
6837
6862
|
}
|
|
6838
6863
|
return null;
|
|
6839
6864
|
}
|
|
6840
6865
|
function getAppiumExtensionsFile(homeDir) {
|
|
6841
|
-
return
|
|
6866
|
+
return import_node_path14.default.join(homeDir, "node_modules", ".cache", "appium", "extensions.yaml");
|
|
6842
6867
|
}
|
|
6843
6868
|
function hasAppiumDriver(homeDir, driverName) {
|
|
6844
6869
|
const file = getAppiumExtensionsFile(homeDir);
|
|
6845
|
-
if (!(0,
|
|
6870
|
+
if (!(0, import_node_fs4.existsSync)(file)) {
|
|
6846
6871
|
return false;
|
|
6847
6872
|
}
|
|
6848
6873
|
try {
|
|
6849
|
-
const text = (0,
|
|
6874
|
+
const text = (0, import_node_fs4.readFileSync)(file, "utf8");
|
|
6850
6875
|
return text.toLowerCase().includes(driverName.toLowerCase());
|
|
6851
6876
|
} catch {
|
|
6852
6877
|
return false;
|
|
@@ -6859,7 +6884,7 @@ function resolveAppiumHome(platform) {
|
|
|
6859
6884
|
persisted.appiumHome,
|
|
6860
6885
|
process.cwd(),
|
|
6861
6886
|
process.env.USERPROFILE,
|
|
6862
|
-
process.env.USERPROFILE ?
|
|
6887
|
+
process.env.USERPROFILE ? import_node_path14.default.join(process.env.USERPROFILE, ".appium") : null
|
|
6863
6888
|
].map((v) => typeof v === "string" ? v.trim() : "").filter(Boolean);
|
|
6864
6889
|
const uniq = Array.from(new Set(candidates));
|
|
6865
6890
|
const targetDriver = platform === "android" ? "uiautomator2" : platform === "ios" ? "xcuitest" : "harmonyos";
|
|
@@ -6869,7 +6894,7 @@ function resolveAppiumHome(platform) {
|
|
|
6869
6894
|
}
|
|
6870
6895
|
}
|
|
6871
6896
|
for (const candidate of uniq) {
|
|
6872
|
-
if ((0,
|
|
6897
|
+
if ((0, import_node_fs4.existsSync)(getAppiumExtensionsFile(candidate))) {
|
|
6873
6898
|
return candidate;
|
|
6874
6899
|
}
|
|
6875
6900
|
}
|
|
@@ -8206,7 +8231,7 @@ function wireAdaMcpProtocolServer(mcp) {
|
|
|
8206
8231
|
if (!file) {
|
|
8207
8232
|
throw new Error("file is required");
|
|
8208
8233
|
}
|
|
8209
|
-
const taskPath =
|
|
8234
|
+
const taskPath = import_node_path14.default.isAbsolute(file) ? file : import_node_path14.default.resolve(process.cwd(), file);
|
|
8210
8235
|
const tasks = await loadTaskFile2(taskPath);
|
|
8211
8236
|
const results = await runTaskset2(tasks);
|
|
8212
8237
|
const monitor = parseMonitorOptions(args);
|
|
@@ -8330,6 +8355,14 @@ async function startMcpServer() {
|
|
|
8330
8355
|
console.error('[ADA-MCP] warning: standalone ada-mcp binary does not require "mcp" arg; it is safe to remove.');
|
|
8331
8356
|
}
|
|
8332
8357
|
const configHint = {
|
|
8358
|
+
mcpServers: {
|
|
8359
|
+
"ada-mcp": {
|
|
8360
|
+
command: "pnpm",
|
|
8361
|
+
args: ["dlx", "@ada-mcp/launcher@0.1.2"]
|
|
8362
|
+
}
|
|
8363
|
+
}
|
|
8364
|
+
};
|
|
8365
|
+
const binaryHint = {
|
|
8333
8366
|
mcpServers: {
|
|
8334
8367
|
"ada-mcp": {
|
|
8335
8368
|
command: binaryCommand,
|
|
@@ -8338,8 +8371,6 @@ async function startMcpServer() {
|
|
|
8338
8371
|
env: {
|
|
8339
8372
|
ADA_PLAYWRIGHT_HEADLESS: "true",
|
|
8340
8373
|
ADA_MCP_INSTALL_DEPS: "playwright",
|
|
8341
|
-
ADA_NPM_PROXY_REGISTRY: "https://registry.npmmirror.com",
|
|
8342
|
-
ADA_PNPM_PROXY_REGISTRY: "https://registry.npmmirror.com",
|
|
8343
8374
|
ADA_INSTALL_STRATEGY_TIMEOUT_MS: "120000",
|
|
8344
8375
|
ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS: "900000"
|
|
8345
8376
|
}
|
|
@@ -8354,8 +8385,10 @@ async function startMcpServer() {
|
|
|
8354
8385
|
}
|
|
8355
8386
|
}
|
|
8356
8387
|
};
|
|
8357
|
-
console.error("[ADA-MCP] config hint (
|
|
8388
|
+
console.error("[ADA-MCP] config hint (npm standard):");
|
|
8358
8389
|
console.error(JSON.stringify(configHint, null, 2));
|
|
8390
|
+
console.error("[ADA-MCP] config hint (local binary):");
|
|
8391
|
+
console.error(JSON.stringify(binaryHint, null, 2));
|
|
8359
8392
|
console.error("[ADA-MCP] note: MCP tool names use ada_snake_case (e.g. ada_install_deps, ada_invoke, ada_web_action)");
|
|
8360
8393
|
console.error("[ADA-MCP] config hint (npm dev):");
|
|
8361
8394
|
console.error(JSON.stringify(npmDevHint, null, 2));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ada-mcp/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "ADA MCP server for web/mobile automation (stdio + remote HTTP)",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "commonjs",
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"dist/cli.cjs",
|
|
14
14
|
"plugins",
|
|
15
|
-
"scripts/preinstall-
|
|
15
|
+
"scripts/preinstall-probes.mjs",
|
|
16
16
|
"scripts/registry-probe.mjs",
|
|
17
|
+
"scripts/playwright-probe.mjs",
|
|
17
18
|
"README.md"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
|
-
"preinstall": "node scripts/preinstall-
|
|
21
|
+
"preinstall": "node scripts/preinstall-probes.mjs",
|
|
21
22
|
"dev": "tsx src/cli.ts",
|
|
22
23
|
"prebuild": "node ../../scripts/generate-bundled-config.mjs",
|
|
23
24
|
"build": "tsc -p tsconfig.json",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright 浏览器 CDN 测速(零依赖,与 dependency-installer 逻辑对齐)
|
|
3
|
+
*/
|
|
4
|
+
export const DEFAULT_PLAYWRIGHT_HOST_CANDIDATES = [
|
|
5
|
+
"https://cdn.playwright.dev",
|
|
6
|
+
"https://playwright.azureedge.net",
|
|
7
|
+
"https://npmmirror.com/mirrors/playwright",
|
|
8
|
+
"https://cdn.npmmirror.com/binaries/playwright"
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
function normalizeHostUrl(url) {
|
|
12
|
+
return String(url).replace(/\/$/, "");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** 每个候选可尝试多个探测 URL(npmmirror 根路径常探测失败) */
|
|
16
|
+
export function playwrightProbeUrls(host) {
|
|
17
|
+
const h = normalizeHostUrl(host);
|
|
18
|
+
if (h.includes("npmmirror.com/mirrors/playwright")) {
|
|
19
|
+
return [h, "https://cdn.npmmirror.com/binaries/playwright"];
|
|
20
|
+
}
|
|
21
|
+
return [h];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function playwrightHostCandidateList() {
|
|
25
|
+
const configured = normalizeHostUrl(
|
|
26
|
+
process.env.PLAYWRIGHT_DOWNLOAD_HOST?.trim() || DEFAULT_PLAYWRIGHT_HOST_CANDIDATES[0]
|
|
27
|
+
);
|
|
28
|
+
const extra = process.env.ADA_PLAYWRIGHT_HOST_CANDIDATES?.trim()
|
|
29
|
+
? process.env.ADA_PLAYWRIGHT_HOST_CANDIDATES.split(",").map((x) => normalizeHostUrl(x.trim())).filter(Boolean)
|
|
30
|
+
: [];
|
|
31
|
+
const ordered = [configured, ...DEFAULT_PLAYWRIGHT_HOST_CANDIDATES, ...extra];
|
|
32
|
+
const seen = new Set();
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const url of ordered) {
|
|
35
|
+
const n = normalizeHostUrl(url);
|
|
36
|
+
if (!seen.has(n)) {
|
|
37
|
+
seen.add(n);
|
|
38
|
+
out.push(n);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function probeUrlLatency(url) {
|
|
45
|
+
const started = Date.now();
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
const timer = setTimeout(() => controller.abort(), 5000);
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch(url, {
|
|
50
|
+
method: "GET",
|
|
51
|
+
redirect: "manual",
|
|
52
|
+
signal: controller.signal
|
|
53
|
+
});
|
|
54
|
+
if (response.status >= 200 && response.status < 500) {
|
|
55
|
+
return Date.now() - started;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
} finally {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function probePlaywrightHostLatency(host) {
|
|
66
|
+
const urls = playwrightProbeUrls(host);
|
|
67
|
+
let best = null;
|
|
68
|
+
for (const url of urls) {
|
|
69
|
+
const latency = await probeUrlLatency(url);
|
|
70
|
+
if (latency !== null && (best === null || latency < best)) {
|
|
71
|
+
best = latency;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return best;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function detectBestPlaywrightHost(candidates = playwrightHostCandidateList()) {
|
|
78
|
+
const probeResults = await Promise.all(
|
|
79
|
+
candidates.map(async (candidate) => ({
|
|
80
|
+
candidate,
|
|
81
|
+
latency: await probePlaywrightHostLatency(candidate)
|
|
82
|
+
}))
|
|
83
|
+
);
|
|
84
|
+
let best = candidates[0] ?? DEFAULT_PLAYWRIGHT_HOST_CANDIDATES[0];
|
|
85
|
+
let bestLatency = Number.POSITIVE_INFINITY;
|
|
86
|
+
let bestPriority = Number.POSITIVE_INFINITY;
|
|
87
|
+
for (const { candidate, latency } of probeResults) {
|
|
88
|
+
if (latency === null) continue;
|
|
89
|
+
const priority = candidates.indexOf(candidate);
|
|
90
|
+
const prio = priority >= 0 ? priority : Number.POSITIVE_INFINITY;
|
|
91
|
+
if (latency < bestLatency || (latency === bestLatency && prio < bestPriority)) {
|
|
92
|
+
best = candidate;
|
|
93
|
+
bestLatency = latency;
|
|
94
|
+
bestPriority = prio;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { best: normalizeHostUrl(best), candidates, probeResults };
|
|
98
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* pnpm dlx 安装本包时:preinstall 测速 registry + Playwright CDN,写入 .npmrc 与 .ada-mcp-playwright-host
|
|
4
|
+
*/
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { detectBestRegistry, registryCandidateList } from "./registry-probe.mjs";
|
|
8
|
+
import { detectBestPlaywrightHost, playwrightHostCandidateList } from "./playwright-probe.mjs";
|
|
9
|
+
|
|
10
|
+
function installRoot() {
|
|
11
|
+
const init = process.env.INIT_CWD?.trim();
|
|
12
|
+
if (init && fs.existsSync(init)) {
|
|
13
|
+
return init;
|
|
14
|
+
}
|
|
15
|
+
return process.cwd();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function shouldRunProbe() {
|
|
19
|
+
if (process.env.ADA_MCP_SKIP_REGISTRY_PROBE === "1") {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (process.env.ADA_MCP_FORCE_PREINSTALL_PROBE === "1") {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
const init = (process.env.INIT_CWD || "").replace(/\\/g, "/");
|
|
26
|
+
if (/[\\/]dlx[\\/]/.test(init) || init.includes("__npx")) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (init) {
|
|
30
|
+
try {
|
|
31
|
+
if (fs.existsSync(path.join(init, "pnpm-workspace.yaml"))) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
// ignore
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return init.length > 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function main() {
|
|
42
|
+
if (!shouldRunProbe()) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const root = installRoot();
|
|
46
|
+
|
|
47
|
+
const regCandidates = registryCandidateList();
|
|
48
|
+
const reg = await detectBestRegistry(regCandidates);
|
|
49
|
+
const npmrcPath = path.join(root, ".npmrc");
|
|
50
|
+
const regLine = `registry=${reg.best}\n`;
|
|
51
|
+
let npmrc = "";
|
|
52
|
+
try {
|
|
53
|
+
npmrc = fs.readFileSync(npmrcPath, "utf8");
|
|
54
|
+
} catch {
|
|
55
|
+
// new
|
|
56
|
+
}
|
|
57
|
+
if (!npmrc.includes(`registry=${reg.best}`)) {
|
|
58
|
+
fs.writeFileSync(npmrcPath, `${npmrc}${regLine}`, "utf8");
|
|
59
|
+
}
|
|
60
|
+
console.error(`[ada-mcp preinstall] registry: ${reg.best}`);
|
|
61
|
+
for (const { candidate, latency } of reg.probeResults) {
|
|
62
|
+
console.error(`[ada-mcp preinstall] registry ${candidate} -> ${latency === null ? "fail" : `${latency}ms`}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const pwCandidates = playwrightHostCandidateList();
|
|
66
|
+
const pw = await detectBestPlaywrightHost(pwCandidates);
|
|
67
|
+
const hostFile = path.join(root, ".ada-mcp-playwright-host");
|
|
68
|
+
fs.writeFileSync(hostFile, `${pw.best}\n`, "utf8");
|
|
69
|
+
process.env.PLAYWRIGHT_DOWNLOAD_HOST = pw.best;
|
|
70
|
+
console.error(`[ada-mcp preinstall] playwright CDN: ${pw.best} (wrote ${hostFile})`);
|
|
71
|
+
for (const { candidate, latency } of pw.probeResults) {
|
|
72
|
+
console.error(`[ada-mcp preinstall] playwright ${candidate} -> ${latency === null ? "fail" : `${latency}ms`}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
main().catch((error) => {
|
|
77
|
+
console.error("[ada-mcp preinstall] probe failed:", error);
|
|
78
|
+
process.exit(0);
|
|
79
|
+
});
|
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
export const DEFAULT_NPM_REGISTRY_CANDIDATES = [
|
|
5
5
|
"https://registry.npmmirror.com",
|
|
6
6
|
"https://mirrors.cloud.tencent.com/npm",
|
|
7
|
-
"https://mirrors.tuna.tsinghua.edu.cn/npm",
|
|
8
7
|
"https://repo.huaweicloud.com/repository/npm",
|
|
9
|
-
"https://mirrors.163.com/npm",
|
|
10
8
|
"https://registry.npmjs.org"
|
|
11
9
|
];
|
|
12
10
|
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* pnpm dlx / npm install 本包时:在安装 dependencies 之前测速并写入 .npmrc,
|
|
4
|
-
* 使同一次安装中的 playwright 等依赖走最快 registry。
|
|
5
|
-
*/
|
|
6
|
-
import fs from "node:fs";
|
|
7
|
-
import path from "node:path";
|
|
8
|
-
import { detectBestRegistry, registryCandidateList } from "./registry-probe.mjs";
|
|
9
|
-
|
|
10
|
-
function installRoot() {
|
|
11
|
-
const init = process.env.INIT_CWD?.trim();
|
|
12
|
-
if (init && fs.existsSync(init)) {
|
|
13
|
-
return init;
|
|
14
|
-
}
|
|
15
|
-
return process.cwd();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function shouldRunProbe() {
|
|
19
|
-
if (process.env.ADA_MCP_SKIP_REGISTRY_PROBE === "1") {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
if (process.env.ADA_MCP_FORCE_PREINSTALL_PROBE === "1") {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
const init = (process.env.INIT_CWD || "").replace(/\\/g, "/");
|
|
26
|
-
if (/[\\/]dlx[\\/]/.test(init) || init.includes("__npx")) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
if (init) {
|
|
30
|
-
try {
|
|
31
|
-
if (fs.existsSync(path.join(init, "pnpm-workspace.yaml"))) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
} catch {
|
|
35
|
-
// ignore
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return init.length > 0;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function main() {
|
|
42
|
-
if (!shouldRunProbe()) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const root = installRoot();
|
|
46
|
-
const candidates = registryCandidateList();
|
|
47
|
-
const { best, probeResults } = await detectBestRegistry(candidates);
|
|
48
|
-
const npmrcPath = path.join(root, ".npmrc");
|
|
49
|
-
const line = `registry=${best}\n`;
|
|
50
|
-
let existing = "";
|
|
51
|
-
try {
|
|
52
|
-
existing = fs.readFileSync(npmrcPath, "utf8");
|
|
53
|
-
} catch {
|
|
54
|
-
// new file
|
|
55
|
-
}
|
|
56
|
-
if (!existing.includes(`registry=${best}`)) {
|
|
57
|
-
fs.writeFileSync(npmrcPath, `${existing}${line}`, "utf8");
|
|
58
|
-
}
|
|
59
|
-
console.error(
|
|
60
|
-
`[ada-mcp preinstall] registry probe: selected ${best} (candidates: ${candidates.join(", ")})`
|
|
61
|
-
);
|
|
62
|
-
for (const { candidate, latency } of probeResults) {
|
|
63
|
-
console.error(`[ada-mcp preinstall] ${candidate} -> ${latency === null ? "fail" : `${latency}ms`}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
main().catch((error) => {
|
|
68
|
-
console.error("[ada-mcp preinstall] registry probe failed:", error);
|
|
69
|
-
process.exit(0);
|
|
70
|
-
});
|