@opentiny/webmcp-cli 0.0.1-alpha.3 → 0.0.1-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.cjs +113 -146
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +113 -152
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +71 -139
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +71 -146
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -26,6 +26,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
// src/bin.ts
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
29
|
+
var import_fs2 = require("fs");
|
|
30
|
+
var import_path2 = require("path");
|
|
29
31
|
|
|
30
32
|
// src/browser.ts
|
|
31
33
|
var import_puppeteer_core = __toESM(require("puppeteer-core"), 1);
|
|
@@ -33,6 +35,7 @@ var import_picocolors = __toESM(require("picocolors"), 1);
|
|
|
33
35
|
var import_fs = __toESM(require("fs"), 1);
|
|
34
36
|
var import_os = __toESM(require("os"), 1);
|
|
35
37
|
var import_path = __toESM(require("path"), 1);
|
|
38
|
+
var import_http = __toESM(require("http"), 1);
|
|
36
39
|
var import_child_process = require("child_process");
|
|
37
40
|
var import_url = require("url");
|
|
38
41
|
var import_meta = {};
|
|
@@ -40,14 +43,27 @@ var __filename = (0, import_url.fileURLToPath)(import_meta.url);
|
|
|
40
43
|
var __dirname = import_path.default.dirname(__filename);
|
|
41
44
|
var CDP_PORT = 9222;
|
|
42
45
|
var CDP_URL = `http://localhost:${CDP_PORT}`;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
function httpGet(url, timeoutMs = 1500) {
|
|
47
|
+
return new Promise((resolve2, reject) => {
|
|
48
|
+
const req = import_http.default.get(url, { timeout: timeoutMs }, (res) => {
|
|
49
|
+
let data = "";
|
|
50
|
+
res.on("data", (chunk) => {
|
|
51
|
+
data += chunk.toString();
|
|
52
|
+
});
|
|
53
|
+
res.on("end", () => {
|
|
54
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
55
|
+
resolve2(data);
|
|
56
|
+
} else {
|
|
57
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
req.on("error", reject);
|
|
62
|
+
req.on("timeout", () => {
|
|
63
|
+
req.destroy();
|
|
64
|
+
reject(new Error("request timeout"));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
51
67
|
}
|
|
52
68
|
function promiseWithTimeout(promise, timeoutMs = 5e3, errorMsg = "Operation timed out") {
|
|
53
69
|
let timeoutId;
|
|
@@ -63,8 +79,8 @@ function promiseWithTimeout(promise, timeoutMs = 5e3, errorMsg = "Operation time
|
|
|
63
79
|
async function checkCdpReady(url, retries = 3) {
|
|
64
80
|
for (let i = 0; i < retries; i++) {
|
|
65
81
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
await httpGet(url, 1500);
|
|
83
|
+
return true;
|
|
68
84
|
} catch {
|
|
69
85
|
}
|
|
70
86
|
if (i < retries - 1) {
|
|
@@ -73,45 +89,6 @@ async function checkCdpReady(url, retries = 3) {
|
|
|
73
89
|
}
|
|
74
90
|
return false;
|
|
75
91
|
}
|
|
76
|
-
async function killProcessOnPortIfZombie(port) {
|
|
77
|
-
const isResponding = await checkCdpReady(`http://127.0.0.1:${port}/json/version`, 1);
|
|
78
|
-
if (isResponding) {
|
|
79
|
-
console.log(import_picocolors.default.green(`connectBrowser: \u7AEF\u53E3 ${port} \u4E0A\u7684\u6D4F\u89C8\u5668\u5B9E\u4F8B\u4ECD\u5728\u6B63\u5E38\u54CD\u5E94\uFF0C\u8DF3\u8FC7\u5F3A\u6740\uFF0C\u5C1D\u8BD5\u76F4\u63A5\u63A5\u7BA1\u3002`));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
try {
|
|
83
|
-
const platform = import_os.default.platform();
|
|
84
|
-
const { execSync } = require("child_process");
|
|
85
|
-
if (platform === "darwin" || platform === "linux") {
|
|
86
|
-
console.log(import_picocolors.default.yellow(`\u6B63\u5728\u68C0\u6D4B\u5E76\u6E05\u7406\u5360\u7528 ${port} \u7AEF\u53E3\u7684\u6B8B\u7559\u50F5\u5C38\u8FDB\u7A0B...`));
|
|
87
|
-
const pids = execSync(`lsof -t -i :${port}`).toString().trim();
|
|
88
|
-
if (pids) {
|
|
89
|
-
console.log(import_picocolors.default.yellow(`\u53D1\u73B0\u50F5\u5C38 PID: ${pids.split("\n").join(", ")}\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`));
|
|
90
|
-
execSync(`kill -9 ${pids.split("\n").join(" ")}`);
|
|
91
|
-
console.log(import_picocolors.default.green(`\u6210\u529F\u6E05\u7406\u6B8B\u7559\u50F5\u5C38\u8FDB\u7A0B`));
|
|
92
|
-
}
|
|
93
|
-
} else if (platform === "win32") {
|
|
94
|
-
console.log(import_picocolors.default.yellow(`\u6B63\u5728\u68C0\u6D4B\u5E76\u6E05\u7406 Windows \u4E0A\u5360\u7528 ${port} \u7AEF\u53E3\u7684\u6B8B\u7559\u50F5\u5C38\u8FDB\u7A0B...`));
|
|
95
|
-
const output = execSync(`netstat -ano | findstr :${port}`).toString().trim();
|
|
96
|
-
if (output) {
|
|
97
|
-
const lines = output.split("\n");
|
|
98
|
-
const pids = /* @__PURE__ */ new Set();
|
|
99
|
-
lines.forEach((line) => {
|
|
100
|
-
const parts = line.trim().split(/\s+/);
|
|
101
|
-
const pid = parts[parts.length - 1];
|
|
102
|
-
if (pid && /^\d+$/.test(pid) && pid !== "0") {
|
|
103
|
-
pids.add(pid);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
pids.forEach((pid) => {
|
|
107
|
-
console.log(import_picocolors.default.yellow(`\u53D1\u73B0 Windows \u6B8B\u7559\u50F5\u5C38 PID: ${pid}\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`));
|
|
108
|
-
execSync(`taskkill /F /PID ${pid}`);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch (e) {
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
92
|
function getDefaultBrowserPath() {
|
|
116
93
|
const platform = import_os.default.platform();
|
|
117
94
|
if (platform === "darwin") {
|
|
@@ -174,20 +151,18 @@ async function startBrowserInBackground() {
|
|
|
174
151
|
child.unref();
|
|
175
152
|
for (let i = 0; i < 20; i++) {
|
|
176
153
|
try {
|
|
177
|
-
const urls = [`http://
|
|
154
|
+
const urls = [`http://127.0.0.1:${CDP_PORT}/json/version`, `http://localhost:${CDP_PORT}/json/version`];
|
|
178
155
|
for (const url of urls) {
|
|
179
156
|
try {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
157
|
+
await httpGet(url, 1e3);
|
|
158
|
+
console.log(import_picocolors.default.green(`${browserInfo.name} \u542F\u52A8\u5E76\u5C31\u7EEA\u3002`));
|
|
159
|
+
return;
|
|
185
160
|
} catch (err) {
|
|
186
161
|
}
|
|
187
162
|
}
|
|
188
163
|
} catch (e) {
|
|
189
164
|
}
|
|
190
|
-
await new Promise((
|
|
165
|
+
await new Promise((resolve2) => setTimeout(resolve2, 500));
|
|
191
166
|
}
|
|
192
167
|
throw new Error(`${browserInfo.name} \u542F\u52A8\u8D85\u65F6\uFF0C\u65E0\u6CD5\u8FDE\u63A5\u5230 CDP \u7AEF\u53E3\u3002`);
|
|
193
168
|
}
|
|
@@ -208,90 +183,51 @@ async function connectBrowser() {
|
|
|
208
183
|
return false;
|
|
209
184
|
}
|
|
210
185
|
};
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
186
|
+
const portAddresses = [
|
|
187
|
+
`http://127.0.0.1:${CDP_PORT}/json/version`,
|
|
188
|
+
`http://localhost:${CDP_PORT}/json/version`
|
|
189
|
+
];
|
|
190
|
+
for (const addr of portAddresses) {
|
|
191
|
+
const isReady = await checkCdpReady(addr, 2);
|
|
192
|
+
if (!isReady) continue;
|
|
193
|
+
const browserURL = addr.replace("/json/version", "");
|
|
194
|
+
try {
|
|
195
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u68C0\u6D4B\u5230\u7AEF\u53E3 ${CDP_PORT} \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u8FDE\u63A5 ${browserURL}...`));
|
|
196
|
+
const browser2 = await promiseWithTimeout(
|
|
197
|
+
import_puppeteer_core.default.connect({ browserURL, defaultViewport: null, targetFilter }),
|
|
198
|
+
1e4,
|
|
199
|
+
`puppeteer.connect to ${browserURL} timed out`
|
|
200
|
+
);
|
|
201
|
+
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
202
|
+
return browser2;
|
|
203
|
+
} catch {
|
|
215
204
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
205
|
+
}
|
|
206
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u7AEF\u53E3 ${CDP_PORT} \u65E0\u54CD\u5E94\uFF0C\u6B63\u5728\u542F\u52A8\u65B0\u7684\u6D4F\u89C8\u5668\u5B9E\u4F8B...`));
|
|
207
|
+
try {
|
|
208
|
+
await startBrowserInBackground();
|
|
209
|
+
} catch (launchError) {
|
|
210
|
+
const msg = launchError instanceof Error ? launchError.message : String(launchError);
|
|
211
|
+
console.error(import_picocolors.default.red(`\u65E0\u6CD5\u542F\u52A8\u6D4F\u89C8\u5668: ${msg}`));
|
|
212
|
+
throw new Error("Browser launch failed.");
|
|
213
|
+
}
|
|
214
|
+
for (const addr of portAddresses) {
|
|
215
|
+
const isReady = await checkCdpReady(addr, 3);
|
|
216
|
+
if (!isReady) continue;
|
|
217
|
+
const browserURL = addr.replace("/json/version", "");
|
|
229
218
|
try {
|
|
230
|
-
|
|
231
|
-
if (!isLocalhostReady) {
|
|
232
|
-
throw new Error("localhost CDP port not responding");
|
|
233
|
-
}
|
|
234
|
-
console.log(import_picocolors.default.yellow("connectBrowser: \u6B63\u5728\u5C1D\u8BD5\u8FDE\u63A5 localhost:9222..."));
|
|
219
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u6D4F\u89C8\u5668\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5 ${browserURL}...`));
|
|
235
220
|
const browser2 = await promiseWithTimeout(
|
|
236
|
-
import_puppeteer_core.default.connect({
|
|
237
|
-
browserURL: `http://localhost:${CDP_PORT}`,
|
|
238
|
-
defaultViewport: null,
|
|
239
|
-
targetFilter
|
|
240
|
-
}),
|
|
221
|
+
import_puppeteer_core.default.connect({ browserURL, defaultViewport: null, targetFilter }),
|
|
241
222
|
1e4,
|
|
242
|
-
|
|
223
|
+
`puppeteer.connect to ${browserURL} after launch timed out`
|
|
243
224
|
);
|
|
244
|
-
console.log(import_picocolors.default.green(
|
|
225
|
+
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
245
226
|
return browser2;
|
|
246
|
-
} catch
|
|
247
|
-
console.log(import_picocolors.default.yellow(`connectBrowser: \u8FDE\u63A5\u5931\u8D25\uFF0C\u5C06\u5C1D\u8BD5\u5524\u8D77\u6D4F\u89C8\u5668\u3002\u9519\u8BEF\u539F\u56E0: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
248
|
-
try {
|
|
249
|
-
await killProcessOnPortIfZombie(CDP_PORT);
|
|
250
|
-
await startBrowserInBackground();
|
|
251
|
-
try {
|
|
252
|
-
const is127Ready = await checkCdpReady(`http://127.0.0.1:${CDP_PORT}/json/version`, 3);
|
|
253
|
-
if (!is127Ready) {
|
|
254
|
-
throw new Error("127.0.0.1 CDP port not responding after launch");
|
|
255
|
-
}
|
|
256
|
-
console.log(import_picocolors.default.yellow("connectBrowser: \u6D4F\u89C8\u5668\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u5C1D\u8BD5\u8FDE\u63A5 127.0.0.1:9222..."));
|
|
257
|
-
const browser2 = await promiseWithTimeout(
|
|
258
|
-
import_puppeteer_core.default.connect({
|
|
259
|
-
browserURL: `http://127.0.0.1:${CDP_PORT}`,
|
|
260
|
-
defaultViewport: null,
|
|
261
|
-
targetFilter
|
|
262
|
-
}),
|
|
263
|
-
1e4,
|
|
264
|
-
"puppeteer.connect to 127.0.0.1 after launch timed out"
|
|
265
|
-
);
|
|
266
|
-
console.log(import_picocolors.default.green("connectBrowser: \u6210\u529F\u8FDE\u63A5 127.0.0.1:9222"));
|
|
267
|
-
return browser2;
|
|
268
|
-
} catch (e) {
|
|
269
|
-
const isLocalhostReady = await checkCdpReady(`http://localhost:${CDP_PORT}/json/version`, 3);
|
|
270
|
-
if (!isLocalhostReady) {
|
|
271
|
-
throw new Error("localhost CDP port not responding after launch");
|
|
272
|
-
}
|
|
273
|
-
console.log(import_picocolors.default.yellow("connectBrowser: \u6B63\u5728\u5C1D\u8BD5\u8FDE\u63A5 localhost:9222..."));
|
|
274
|
-
const browser2 = await promiseWithTimeout(
|
|
275
|
-
import_puppeteer_core.default.connect({
|
|
276
|
-
browserURL: `http://localhost:${CDP_PORT}`,
|
|
277
|
-
defaultViewport: null,
|
|
278
|
-
targetFilter
|
|
279
|
-
}),
|
|
280
|
-
1e4,
|
|
281
|
-
"puppeteer.connect to localhost after launch timed out"
|
|
282
|
-
);
|
|
283
|
-
console.log(import_picocolors.default.green("connectBrowser: \u6210\u529F\u8FDE\u63A5 localhost:9222"));
|
|
284
|
-
return browser2;
|
|
285
|
-
}
|
|
286
|
-
} catch (launchError) {
|
|
287
|
-
const msg = launchError instanceof Error ? launchError.message : String(launchError);
|
|
288
|
-
console.error(import_picocolors.default.red(`\u65E0\u6CD5\u8FDE\u63A5\u6216\u542F\u52A8\u6D4F\u89C8\u5668: ${msg}`));
|
|
289
|
-
console.error(import_picocolors.default.yellow(`\u{1F4A1} \u63D0\u793A\uFF1A\u7531\u4E8E\u6211\u4EEC\u8981\u4F7F\u7528\u4F60\u65E5\u5E38\u7684\u9ED8\u8BA4\u6D4F\u89C8\u5668\uFF08\u5305\u542B\u4F60\u7684\u4E66\u7B7E\u548C\u767B\u5F55\u6001\uFF09\uFF0C\u5982\u679C\u4F60\u7684 Chrome/Edge \u76EE\u524D\u6B63\u5904\u4E8E\u6253\u5F00\u72B6\u6001\uFF0C\u5B83\u4F1A\u62D2\u7EDD\u4F7F\u7528\u5E26\u6709\u8C03\u8BD5\u7AEF\u53E3\u7684\u65B0\u53C2\u6570\u542F\u52A8\u3002`));
|
|
290
|
-
console.error(import_picocolors.default.yellow(`\u{1F449} \u89E3\u51B3\u529E\u6CD5\uFF1A\u8BF7\u5148\u5B8C\u5168\u9000\u51FA\u5F53\u524D\u7684 Chrome \u6216 Edge \u6D4F\u89C8\u5668\uFF08\u5728 Mac \u4E0A\u6309 Cmd+Q\uFF0CWindows \u4E0A\u53F3\u952E\u4EFB\u52A1\u680F\u56FE\u6807\u9000\u51FA\uFF09\uFF0C\u7136\u540E\u518D\u91CD\u65B0\u8FD0\u884C\u547D\u4EE4\u3002`));
|
|
291
|
-
throw new Error("Browser connection failed.");
|
|
292
|
-
}
|
|
227
|
+
} catch {
|
|
293
228
|
}
|
|
294
229
|
}
|
|
230
|
+
throw new Error(`\u65E0\u6CD5\u8FDE\u63A5\u5230\u6D4F\u89C8\u5668\uFF08\u7AEF\u53E3 ${CDP_PORT}\uFF09\uFF0C\u8BF7\u68C0\u67E5 Chrome/Edge \u662F\u5426\u5DF2\u5B89\u88C5\u3002`);
|
|
295
231
|
}
|
|
296
232
|
async function getPageTargetId(page2) {
|
|
297
233
|
const session = await page2.target().createCDPSession();
|
|
@@ -369,14 +305,12 @@ async function getTargetPage(browser2, tabid2) {
|
|
|
369
305
|
let activeTargetId = null;
|
|
370
306
|
for (const url of urls) {
|
|
371
307
|
try {
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
break;
|
|
379
|
-
}
|
|
308
|
+
const body = await httpGet(url, 1e3);
|
|
309
|
+
const targetsData = JSON.parse(body);
|
|
310
|
+
const active = targetsData.find((t) => t.type === "page" && !t.url.startsWith("devtools://"));
|
|
311
|
+
if (active) {
|
|
312
|
+
activeTargetId = active.id;
|
|
313
|
+
break;
|
|
380
314
|
}
|
|
381
315
|
} catch {
|
|
382
316
|
}
|
|
@@ -422,7 +356,7 @@ async function injectWebMCPPolyfillAndTools(page2, force = false) {
|
|
|
422
356
|
const msg = err instanceof Error ? err.message : String(err);
|
|
423
357
|
throw new Error("\u81EA\u52A8\u6CE8\u5165\u811A\u672C\u6267\u884C\u5931\u8D25: " + msg);
|
|
424
358
|
}
|
|
425
|
-
await new Promise((
|
|
359
|
+
await new Promise((resolve2) => setTimeout(resolve2, 300));
|
|
426
360
|
}
|
|
427
361
|
await injectDomainTools(page2);
|
|
428
362
|
}
|
|
@@ -510,7 +444,7 @@ async function stateCommand({ tabid: tabid2 }) {
|
|
|
510
444
|
if (pUrl.startsWith("devtools://")) return null;
|
|
511
445
|
const pTitle = await Promise.race([
|
|
512
446
|
p.title().catch(() => "Unknown"),
|
|
513
|
-
new Promise((
|
|
447
|
+
new Promise((resolve2) => setTimeout(() => resolve2("Unknown"), 500))
|
|
514
448
|
]);
|
|
515
449
|
return {
|
|
516
450
|
// 使用真实的 Chrome target ID,而非数组下标
|
|
@@ -616,7 +550,7 @@ async function tabsOpenCommand(url) {
|
|
|
616
550
|
url = normalizeUrl(url);
|
|
617
551
|
await page2.goto(url, { waitUntil: "domcontentloaded" });
|
|
618
552
|
await injectIntoPage(page2);
|
|
619
|
-
await new Promise((
|
|
553
|
+
await new Promise((resolve2) => setTimeout(resolve2, 500));
|
|
620
554
|
return {
|
|
621
555
|
success: true,
|
|
622
556
|
tabid: await getPageTargetId(page2),
|
|
@@ -717,7 +651,7 @@ async function tabsForwardCommand(tabid2) {
|
|
|
717
651
|
// package.json
|
|
718
652
|
var package_default = {
|
|
719
653
|
name: "@opentiny/webmcp-cli",
|
|
720
|
-
version: "0.0.1-alpha.
|
|
654
|
+
version: "0.0.1-alpha.4",
|
|
721
655
|
type: "module",
|
|
722
656
|
description: "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
|
|
723
657
|
main: "dist/index.js",
|
|
@@ -779,6 +713,19 @@ function handleCommandError(error, commandName) {
|
|
|
779
713
|
console.error(import_picocolors2.default.red(`Error executing ${commandName} command: ${msg}`));
|
|
780
714
|
process.exit(1);
|
|
781
715
|
}
|
|
716
|
+
function expandFileRefs(argsJson) {
|
|
717
|
+
return argsJson.replace(/"@(base64)?file:([^"]+)"/g, (_match, base64Flag, filePath) => {
|
|
718
|
+
const absPath = (0, import_path2.resolve)(process.cwd(), filePath);
|
|
719
|
+
let content;
|
|
720
|
+
try {
|
|
721
|
+
content = (0, import_fs2.readFileSync)(absPath, "utf-8");
|
|
722
|
+
} catch (e) {
|
|
723
|
+
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6\u5F15\u7528 "${filePath}": ${e.message}`);
|
|
724
|
+
}
|
|
725
|
+
const value = base64Flag ? Buffer.from(content, "utf-8").toString("base64") : content;
|
|
726
|
+
return JSON.stringify(value);
|
|
727
|
+
});
|
|
728
|
+
}
|
|
782
729
|
program.name("webmcp-cli").description("WebMCP CLI for interacting with browser via CDP").version(package_default.version).option("-w, --workspace <path>", "\u6307\u5B9A\u81EA\u5B9A\u4E49\u7684\u6D4F\u89C8\u5668\u5DE5\u4F5C\u7A7A\u95F4\uFF08\u7528\u6237\u914D\u7F6E\u76EE\u5F55\uFF09\u8DEF\u5F84").hook("preAction", (thisCommand) => {
|
|
783
730
|
const opts = thisCommand.opts();
|
|
784
731
|
if (opts.workspace) {
|
|
@@ -793,11 +740,31 @@ program.command("state").description("\u83B7\u53D6\u6D4F\u89C8\u5668\u5F53\u524D
|
|
|
793
740
|
handleCommandError(error, "state");
|
|
794
741
|
}
|
|
795
742
|
});
|
|
796
|
-
program.command("run <toolName>
|
|
743
|
+
program.command("run <toolName> [argsJson]").description("\u5411\u6307\u5B9A\u9875\u7B7E\u8C03\u7528\u6307\u5B9A\u7684 WebMCP \u5DE5\u5177\u6267\u884C\u64CD\u4F5C").option("-t, --tabid <id>", "\u6307\u5B9A\u9875\u7B7E\u7684 ID").option(
|
|
744
|
+
"-f, --file <path>",
|
|
745
|
+
`\u4ECE\u6307\u5B9A .json \u6587\u4EF6\u8BFB\u53D6\u6574\u4E2A argsJson\uFF08\u6587\u4EF6\u5185\u5BB9\u5373\u4E3A\u53C2\u6570 JSON\uFF09\u3002
|
|
746
|
+
\u5982\u9700\u5728 argsJson \u4E2D\u5185\u8054\u5F15\u7528\u6587\u4EF6\uFF0C\u4F7F\u7528\u5360\u4F4D\u7B26\u8BED\u6CD5\uFF1A
|
|
747
|
+
@file:<path> \u8BFB\u53D6\u6587\u4EF6\u539F\u59CB\u6587\u672C
|
|
748
|
+
@base64file:<path> \u8BFB\u53D6\u6587\u4EF6\u5E76 Base64 \u7F16\u7801
|
|
749
|
+
\u793A\u4F8B\uFF1Awebmcp-cli run mytool '{"content":"@base64file:./doc.md"}'`
|
|
750
|
+
).action(async (toolName, argsJson, options) => {
|
|
797
751
|
try {
|
|
752
|
+
let finalArgsJson = argsJson;
|
|
753
|
+
if (options.file) {
|
|
754
|
+
const filePath = (0, import_path2.resolve)(process.cwd(), options.file);
|
|
755
|
+
try {
|
|
756
|
+
finalArgsJson = (0, import_fs2.readFileSync)(filePath, "utf-8").trim();
|
|
757
|
+
} catch (e) {
|
|
758
|
+
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 "${filePath}": ${e.message}`);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (!finalArgsJson) {
|
|
762
|
+
throw new Error("\u5FC5\u987B\u63D0\u4F9B argsJson \u53C2\u6570\u6216\u901A\u8FC7 -f/--file \u6307\u5B9A\u53C2\u6570\u6587\u4EF6");
|
|
763
|
+
}
|
|
764
|
+
finalArgsJson = expandFileRefs(finalArgsJson);
|
|
798
765
|
const result2 = await runCommand({
|
|
799
766
|
toolName,
|
|
800
|
-
argsJson,
|
|
767
|
+
argsJson: finalArgsJson,
|
|
801
768
|
tabid: parseTabId(options.tabid)
|
|
802
769
|
});
|
|
803
770
|
console.log(JSON.stringify(result2, null, 2));
|