@opentiny/webmcp-cli 0.0.2 → 0.0.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 +202 -117
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +202 -117
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +159 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +159 -101
- package/dist/index.js.map +1 -1
- package/dist/webmcp-tools/excalidraw.com.js +3 -1
- package/dist/webmcp-tools/juejin.cn.js +131 -62
- package/dist/webmcp-tools/my.oschina.net.js +4 -2
- package/dist/webmcp-tools/www.baidu.com.js +3 -1
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -184,21 +184,28 @@ ${hint}`);
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
function prepareRunArgsJson(args, fileContent, baseDir) {
|
|
187
|
-
let raw = "";
|
|
188
187
|
if (fileContent !== void 0) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (joined.startsWith("{") || looksLikeObjectBody(joined)) {
|
|
193
|
-
raw = joined;
|
|
194
|
-
} else if (args.every((arg) => arg.includes("="))) {
|
|
195
|
-
raw = buildArgsFromKeyValuePairs(args);
|
|
196
|
-
} else {
|
|
197
|
-
raw = joined;
|
|
188
|
+
const trimmed = fileContent.trim();
|
|
189
|
+
if (!trimmed) {
|
|
190
|
+
throw new Error("\u901A\u8FC7 -f/--file \u6307\u5B9A\u7684\u53C2\u6570\u6587\u4EF6\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
|
|
198
191
|
}
|
|
192
|
+
const expanded2 = expandFileRefs(trimmed, baseDir);
|
|
193
|
+
return parseArgsJson(expanded2);
|
|
194
|
+
}
|
|
195
|
+
if (args.length === 0) {
|
|
196
|
+
return "{}";
|
|
197
|
+
}
|
|
198
|
+
const joined = joinShellArgs(args);
|
|
199
|
+
let raw = "";
|
|
200
|
+
if (joined.startsWith("{") || looksLikeObjectBody(joined)) {
|
|
201
|
+
raw = joined;
|
|
202
|
+
} else if (args.every((arg) => arg.includes("="))) {
|
|
203
|
+
raw = buildArgsFromKeyValuePairs(args);
|
|
204
|
+
} else {
|
|
205
|
+
raw = joined;
|
|
199
206
|
}
|
|
200
|
-
if (!raw) {
|
|
201
|
-
throw new Error("\
|
|
207
|
+
if (!raw.trim()) {
|
|
208
|
+
throw new Error("\u672A\u63D0\u4F9B\u6709\u6548\u53C2\u6570");
|
|
202
209
|
}
|
|
203
210
|
const expanded = expandFileRefs(raw, baseDir);
|
|
204
211
|
return parseArgsJson(expanded);
|
|
@@ -218,6 +225,30 @@ var __filename = (0, import_url2.fileURLToPath)(import_meta.url);
|
|
|
218
225
|
var __dirname = import_path2.default.dirname(__filename);
|
|
219
226
|
var CDP_PORT = 9222;
|
|
220
227
|
var CDP_URL = `http://localhost:${CDP_PORT}`;
|
|
228
|
+
function getWorkspaceDir() {
|
|
229
|
+
return process.env.WEBMCP_WORKSPACE || import_path2.default.join(import_os.default.homedir(), ".webmcp_chrome_profile");
|
|
230
|
+
}
|
|
231
|
+
function getLastTabIdFilePath() {
|
|
232
|
+
return import_path2.default.join(getWorkspaceDir(), ".last-tab-id");
|
|
233
|
+
}
|
|
234
|
+
function setLastActiveTabId(tabid) {
|
|
235
|
+
try {
|
|
236
|
+
const dir = getWorkspaceDir();
|
|
237
|
+
if (!import_fs2.default.existsSync(dir)) {
|
|
238
|
+
import_fs2.default.mkdirSync(dir, { recursive: true });
|
|
239
|
+
}
|
|
240
|
+
import_fs2.default.writeFileSync(getLastTabIdFilePath(), tabid, "utf-8");
|
|
241
|
+
} catch {
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function getLastActiveTabId() {
|
|
245
|
+
try {
|
|
246
|
+
const tabid = import_fs2.default.readFileSync(getLastTabIdFilePath(), "utf-8").trim();
|
|
247
|
+
return tabid || null;
|
|
248
|
+
} catch {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
221
252
|
function httpGet(url, timeoutMs = 1500) {
|
|
222
253
|
return new Promise((resolve3, reject) => {
|
|
223
254
|
const req = import_http.default.get(url, { timeout: timeoutMs }, (res) => {
|
|
@@ -264,6 +295,31 @@ async function checkCdpReady(url, retries = 3) {
|
|
|
264
295
|
}
|
|
265
296
|
return false;
|
|
266
297
|
}
|
|
298
|
+
async function findAvailableCdpUrl(addresses, retries = 2) {
|
|
299
|
+
for (const addr of addresses) {
|
|
300
|
+
if (await checkCdpReady(addr, retries)) {
|
|
301
|
+
return addr.replace("/json/version", "");
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
async function connectPuppeteer(browserBaseUrl, attempt = 1, maxAttempts = 3) {
|
|
307
|
+
try {
|
|
308
|
+
return await promiseWithTimeout(
|
|
309
|
+
import_puppeteer_core.default.connect({ browserURL: browserBaseUrl, defaultViewport: null }),
|
|
310
|
+
1e4,
|
|
311
|
+
`puppeteer.connect to ${browserBaseUrl} timed out`
|
|
312
|
+
);
|
|
313
|
+
} catch (err) {
|
|
314
|
+
if (attempt >= maxAttempts) {
|
|
315
|
+
throw err;
|
|
316
|
+
}
|
|
317
|
+
const delayMs = 500 * attempt;
|
|
318
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u7B2C ${attempt} \u6B21\u8FDE\u63A5\u5931\u8D25\uFF0C${delayMs}ms \u540E\u91CD\u8BD5...`));
|
|
319
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
320
|
+
return connectPuppeteer(browserBaseUrl, attempt + 1, maxAttempts);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
267
323
|
function getDefaultBrowserPath() {
|
|
268
324
|
const platform = import_os.default.platform();
|
|
269
325
|
if (platform === "darwin") {
|
|
@@ -310,72 +366,56 @@ async function startBrowserInBackground() {
|
|
|
310
366
|
}
|
|
311
367
|
console.log(import_picocolors.default.yellow(`\u6B63\u5728\u542F\u52A8\u540E\u53F0 ${browserInfo.name} \u5B9E\u4F8B (\u7AEF\u53E3: ${CDP_PORT})...`));
|
|
312
368
|
const userDataDir = process.env.WEBMCP_WORKSPACE || import_path2.default.join(import_os.default.homedir(), ".webmcp_chrome_profile");
|
|
369
|
+
const launchArgs = [
|
|
370
|
+
`--remote-debugging-port=${CDP_PORT}`,
|
|
371
|
+
`--user-data-dir=${userDataDir}`,
|
|
372
|
+
"--no-first-run",
|
|
373
|
+
"--no-default-browser-check"
|
|
374
|
+
];
|
|
375
|
+
if (import_os.default.platform() === "win32") {
|
|
376
|
+
launchArgs.push("--remote-debugging-address=127.0.0.1");
|
|
377
|
+
}
|
|
313
378
|
const child = (0, import_child_process.spawn)(
|
|
314
379
|
browserInfo.path,
|
|
315
|
-
|
|
316
|
-
`--remote-debugging-port=${CDP_PORT}`,
|
|
317
|
-
`--user-data-dir=${userDataDir}`,
|
|
318
|
-
"--no-first-run",
|
|
319
|
-
"--no-default-browser-check"
|
|
320
|
-
],
|
|
380
|
+
launchArgs,
|
|
321
381
|
{
|
|
322
382
|
detached: true,
|
|
323
383
|
stdio: "ignore"
|
|
324
384
|
}
|
|
325
385
|
);
|
|
326
386
|
child.unref();
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
387
|
+
const pollUrls = [`http://127.0.0.1:${CDP_PORT}/json/version`, `http://localhost:${CDP_PORT}/json/version`];
|
|
388
|
+
for (let i = 0; i < 30; i++) {
|
|
389
|
+
for (const url of pollUrls) {
|
|
390
|
+
try {
|
|
391
|
+
await httpGet(url, 1e3);
|
|
392
|
+
console.log(import_picocolors.default.green(`${browserInfo.name} \u542F\u52A8\u5E76\u5C31\u7EEA\u3002`));
|
|
393
|
+
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
394
|
+
return;
|
|
395
|
+
} catch {
|
|
337
396
|
}
|
|
338
|
-
} catch (e) {
|
|
339
397
|
}
|
|
340
398
|
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
341
399
|
}
|
|
342
400
|
throw new Error(`${browserInfo.name} \u542F\u52A8\u8D85\u65F6\uFF0C\u65E0\u6CD5\u8FDE\u63A5\u5230 CDP \u7AEF\u53E3\u3002`);
|
|
343
401
|
}
|
|
344
402
|
async function connectBrowser() {
|
|
345
|
-
const
|
|
346
|
-
try {
|
|
347
|
-
const info = typeof target._getTargetInfo === "function" ? target._getTargetInfo() : target;
|
|
348
|
-
const type = info.type || "";
|
|
349
|
-
const url = info.url || "";
|
|
350
|
-
if (type === "service_worker" || type === "shared_worker" || type === "iframe" || type === "other" || type === "webview" || type === "background_page") {
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
|
-
if (url.startsWith("devtools://") || url.startsWith("chrome-extension://")) {
|
|
354
|
-
return false;
|
|
355
|
-
}
|
|
356
|
-
return true;
|
|
357
|
-
} catch (e) {
|
|
358
|
-
return false;
|
|
359
|
-
}
|
|
360
|
-
};
|
|
361
|
-
const portAddresses = [
|
|
403
|
+
const versionAddresses = [
|
|
362
404
|
`http://127.0.0.1:${CDP_PORT}/json/version`,
|
|
363
405
|
`http://localhost:${CDP_PORT}/json/version`
|
|
364
406
|
];
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const browserURL = addr.replace("/json/version", "");
|
|
407
|
+
const existingUrl = await findAvailableCdpUrl(versionAddresses, 2);
|
|
408
|
+
if (existingUrl) {
|
|
409
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u68C0\u6D4B\u5230\u7AEF\u53E3 ${CDP_PORT} \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u8FDE\u63A5 ${existingUrl}...`));
|
|
369
410
|
try {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
import_puppeteer_core.default.connect({ browserURL, defaultViewport: null, targetFilter }),
|
|
373
|
-
1e4,
|
|
374
|
-
`puppeteer.connect to ${browserURL} timed out`
|
|
375
|
-
);
|
|
376
|
-
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
411
|
+
const browser = await connectPuppeteer(existingUrl);
|
|
412
|
+
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${existingUrl}`));
|
|
377
413
|
return browser;
|
|
378
|
-
} catch {
|
|
414
|
+
} catch (err) {
|
|
415
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
416
|
+
throw new Error(
|
|
417
|
+
`\u65E0\u6CD5\u8FDE\u63A5\u5230\u5DF2\u5728\u8FD0\u884C\u7684\u6D4F\u89C8\u5668\uFF08${existingUrl}\uFF09\uFF1A${msg}\u3002CDP \u7AEF\u53E3\u53EF\u7528\uFF0C\u8BF7\u52FF\u91CD\u590D\u542F\u52A8\u6D4F\u89C8\u5668\uFF1B\u53EF\u5173\u95ED\u591A\u4F59\u7A97\u53E3\u540E\u91CD\u8BD5\u3002`
|
|
418
|
+
);
|
|
379
419
|
}
|
|
380
420
|
}
|
|
381
421
|
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...`));
|
|
@@ -386,23 +426,18 @@ async function connectBrowser() {
|
|
|
386
426
|
console.error(import_picocolors.default.red(`\u65E0\u6CD5\u542F\u52A8\u6D4F\u89C8\u5668: ${msg}`));
|
|
387
427
|
throw new Error("Browser launch failed.");
|
|
388
428
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
401
|
-
return browser;
|
|
402
|
-
} catch {
|
|
403
|
-
}
|
|
429
|
+
const launchedUrl = await findAvailableCdpUrl(versionAddresses, 5);
|
|
430
|
+
if (!launchedUrl) {
|
|
431
|
+
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`);
|
|
432
|
+
}
|
|
433
|
+
try {
|
|
434
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u6D4F\u89C8\u5668\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5 ${launchedUrl}...`));
|
|
435
|
+
const browser = await connectPuppeteer(launchedUrl);
|
|
436
|
+
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${launchedUrl}`));
|
|
437
|
+
return browser;
|
|
438
|
+
} catch {
|
|
439
|
+
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`);
|
|
404
440
|
}
|
|
405
|
-
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`);
|
|
406
441
|
}
|
|
407
442
|
async function getPageTargetId(page) {
|
|
408
443
|
const session = await page.target().createCDPSession();
|
|
@@ -472,33 +507,42 @@ async function getTargetPage(browser, tabid) {
|
|
|
472
507
|
}
|
|
473
508
|
targetPage = await target.page();
|
|
474
509
|
} else {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
510
|
+
const lastTabId = getLastActiveTabId();
|
|
511
|
+
if (lastTabId) {
|
|
512
|
+
const lastTarget = findPageTargetByTabId(browser, lastTabId);
|
|
513
|
+
if (lastTarget) {
|
|
514
|
+
targetPage = await lastTarget.page();
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (!targetPage) {
|
|
518
|
+
try {
|
|
519
|
+
const urls = [
|
|
520
|
+
`http://localhost:${CDP_PORT}/json/list`,
|
|
521
|
+
`http://127.0.0.1:${CDP_PORT}/json/list`
|
|
522
|
+
];
|
|
523
|
+
let activeTargetId = null;
|
|
524
|
+
for (const url of urls) {
|
|
525
|
+
try {
|
|
526
|
+
const body = await httpGet(url, 1e3);
|
|
527
|
+
const targetsData = JSON.parse(body);
|
|
528
|
+
const active = targetsData.find((t) => t.type === "page" && !t.url.startsWith("devtools://"));
|
|
529
|
+
if (active) {
|
|
530
|
+
activeTargetId = active.id;
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
} catch {
|
|
489
534
|
}
|
|
490
|
-
} catch {
|
|
491
535
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
536
|
+
if (activeTargetId) {
|
|
537
|
+
for (const target of pageTargets) {
|
|
538
|
+
if (getTargetIdFromTarget(target) === activeTargetId) {
|
|
539
|
+
targetPage = await target.page();
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
498
542
|
}
|
|
499
543
|
}
|
|
544
|
+
} catch {
|
|
500
545
|
}
|
|
501
|
-
} catch {
|
|
502
546
|
}
|
|
503
547
|
if (!targetPage) {
|
|
504
548
|
const lastTarget = pageTargets[pageTargets.length - 1];
|
|
@@ -579,6 +623,12 @@ async function injectDomainTools(page) {
|
|
|
579
623
|
if (!import_fs2.default.existsSync(toolBundlePath)) {
|
|
580
624
|
return;
|
|
581
625
|
}
|
|
626
|
+
const bundleKey = bundleName.replace(/^webmcp-tools\//, "").replace(/\.js$/, "");
|
|
627
|
+
const flagKey = `__webmcptools_${bundleKey.replace(/[^a-zA-Z0-9]/g, "")}`;
|
|
628
|
+
const alreadyInjected = await page.evaluate((key) => !!window[key], flagKey).catch(() => false);
|
|
629
|
+
if (alreadyInjected) {
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
582
632
|
console.log(import_picocolors.default.cyan(`\u68C0\u6D4B\u5230\u57DF\u540D ${hostname} \u6709\u9884\u7F6E\u5DE5\u5177\uFF0C\u6B63\u5728\u6CE8\u5165...`));
|
|
583
633
|
const toolScript = import_fs2.default.readFileSync(toolBundlePath, "utf-8");
|
|
584
634
|
try {
|
|
@@ -607,6 +657,7 @@ async function stateCommand({ tabid }) {
|
|
|
607
657
|
}
|
|
608
658
|
return { url, title, webmcpTools };
|
|
609
659
|
});
|
|
660
|
+
const activeTabid = await getPageTargetId(page).catch(() => null);
|
|
610
661
|
const pages = await browser.pages();
|
|
611
662
|
const tabs2 = await Promise.all(
|
|
612
663
|
pages.map(async (p) => {
|
|
@@ -626,6 +677,7 @@ async function stateCommand({ tabid }) {
|
|
|
626
677
|
);
|
|
627
678
|
return {
|
|
628
679
|
...state,
|
|
680
|
+
activeTabid,
|
|
629
681
|
tabs: tabs2.filter(Boolean)
|
|
630
682
|
};
|
|
631
683
|
} finally {
|
|
@@ -642,28 +694,51 @@ async function runCommand({
|
|
|
642
694
|
const browser = await connectBrowser();
|
|
643
695
|
try {
|
|
644
696
|
const page = await getTargetPage(browser, tabid);
|
|
697
|
+
const urlBefore = page.url();
|
|
645
698
|
const cleanedArgs = argsJson.trim();
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
699
|
+
let result;
|
|
700
|
+
try {
|
|
701
|
+
result = await page.evaluate(async (name, inputString) => {
|
|
702
|
+
const mcp = navigator.modelContextTesting || navigator.modelContext;
|
|
703
|
+
if (!mcp || typeof mcp.executeTool !== "function") {
|
|
704
|
+
throw new Error("\u5F53\u524D\u9875\u9762\u6CA1\u6709\u6CE8\u5165 WebMCP \u73AF\u5883 (navigator.modelContextTesting.executeTool \u672A\u627E\u5230)");
|
|
705
|
+
}
|
|
706
|
+
let res = await mcp.executeTool(name, inputString);
|
|
707
|
+
if (typeof res === "string") {
|
|
708
|
+
try {
|
|
709
|
+
res = JSON.parse(res);
|
|
710
|
+
} catch {
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (res === void 0 || res === null) {
|
|
714
|
+
throw new Error("\u5DE5\u5177 execute \u672A\u8FD4\u56DE\u7ED3\u679C\uFF0C\u8BF7\u68C0\u67E5\u5DE5\u5177\u5B9E\u73B0\u662F\u5426\u7F3A\u5C11 return");
|
|
715
|
+
}
|
|
716
|
+
if (typeof res === "object" && res.success === false) {
|
|
717
|
+
const failed = res;
|
|
718
|
+
throw new Error(failed.error || failed.message || "\u5DE5\u5177\u6267\u884C\u5931\u8D25");
|
|
719
|
+
}
|
|
720
|
+
return res;
|
|
721
|
+
}, toolName, cleanedArgs);
|
|
722
|
+
} catch (evalError) {
|
|
723
|
+
const errMsg = evalError instanceof Error ? evalError.message : String(evalError);
|
|
724
|
+
const isContextDestroyed = errMsg.includes("context was destroyed") || errMsg.includes("Execution context was destroyed") || errMsg.includes("Cannot read properties of null") && errMsg.includes("context");
|
|
725
|
+
if (isContextDestroyed) {
|
|
726
|
+
await new Promise((resolve3) => setTimeout(resolve3, 800));
|
|
727
|
+
let newUrl = "";
|
|
653
728
|
try {
|
|
654
|
-
|
|
729
|
+
newUrl = page.url();
|
|
655
730
|
} catch {
|
|
656
731
|
}
|
|
732
|
+
if (newUrl && newUrl !== urlBefore) {
|
|
733
|
+
return {
|
|
734
|
+
success: true,
|
|
735
|
+
message: `\u5DE5\u5177 ${toolName} \u6267\u884C\u5B8C\u6210\uFF0C\u9875\u9762\u5DF2\u5BFC\u822A\u81F3 ${newUrl}`,
|
|
736
|
+
navigatedTo: newUrl
|
|
737
|
+
};
|
|
738
|
+
}
|
|
657
739
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
}
|
|
661
|
-
if (typeof res === "object" && res.success === false) {
|
|
662
|
-
const failed = res;
|
|
663
|
-
throw new Error(failed.error || failed.message || "\u5DE5\u5177\u6267\u884C\u5931\u8D25");
|
|
664
|
-
}
|
|
665
|
-
return res;
|
|
666
|
-
}, toolName, cleanedArgs);
|
|
740
|
+
throw evalError;
|
|
741
|
+
}
|
|
667
742
|
return result;
|
|
668
743
|
} finally {
|
|
669
744
|
await browser.disconnect();
|
|
@@ -695,11 +770,19 @@ async function tabsOpenCommand(url) {
|
|
|
695
770
|
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
696
771
|
await injectIntoPage(page);
|
|
697
772
|
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
773
|
+
let tabid;
|
|
774
|
+
try {
|
|
775
|
+
tabid = await getPageTargetId(page);
|
|
776
|
+
await activateTabById(browser, tabid);
|
|
777
|
+
setLastActiveTabId(tabid);
|
|
778
|
+
} catch (e) {
|
|
779
|
+
console.warn("Best-effort tab activation failed:", e);
|
|
780
|
+
}
|
|
698
781
|
return {
|
|
699
782
|
success: true,
|
|
700
|
-
tabid
|
|
783
|
+
tabid,
|
|
701
784
|
url: page.url(),
|
|
702
|
-
title: await page.title()
|
|
785
|
+
title: await page.title().catch(() => "")
|
|
703
786
|
};
|
|
704
787
|
} finally {
|
|
705
788
|
await browser.disconnect();
|
|
@@ -731,9 +814,11 @@ async function tabsSwitchCommand(tabid) {
|
|
|
731
814
|
try {
|
|
732
815
|
await activateTabById(browser, tabid);
|
|
733
816
|
const page = await getTargetPage(browser, tabid);
|
|
817
|
+
const realTabid = await getPageTargetId(page);
|
|
818
|
+
setLastActiveTabId(realTabid);
|
|
734
819
|
return {
|
|
735
820
|
success: true,
|
|
736
|
-
tabid:
|
|
821
|
+
tabid: realTabid,
|
|
737
822
|
url: page.url(),
|
|
738
823
|
title: await page.title()
|
|
739
824
|
};
|
|
@@ -795,7 +880,7 @@ async function tabsForwardCommand(tabid) {
|
|
|
795
880
|
// package.json
|
|
796
881
|
var package_default = {
|
|
797
882
|
name: "@opentiny/webmcp-cli",
|
|
798
|
-
version: "0.0.
|
|
883
|
+
version: "0.0.4",
|
|
799
884
|
type: "module",
|
|
800
885
|
description: "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
|
|
801
886
|
main: "dist/index.js",
|