@opentiny/webmcp-cli 0.0.1-alpha.6 → 0.0.3
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 -7
- package/dist/bin.cjs +337 -268
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +333 -264
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +104 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +104 -105
- package/dist/index.js.map +1 -1
- package/dist/inject-bundle.js +2083 -226
- package/dist/webmcp-tools/creator.xiaohongshu.com.js +315 -0
- package/dist/webmcp-tools/editor.csdn.net.js +155 -0
- package/dist/webmcp-tools/juejin.cn.js +151 -6
- package/dist/webmcp-tools/my.oschina.net.js +94 -0
- package/dist/webmcp-tools/xiaohongshu.com.js +278 -0
- package/package.json +2 -2
package/dist/bin.cjs
CHANGED
|
@@ -24,10 +24,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/bin.ts
|
|
27
|
+
var import_fs3 = __toESM(require("fs"), 1);
|
|
28
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
29
|
+
var import_os2 = __toESM(require("os"), 1);
|
|
27
30
|
var import_commander = require("commander");
|
|
28
31
|
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
29
|
-
var
|
|
30
|
-
var
|
|
32
|
+
var import_fs4 = require("fs");
|
|
33
|
+
var import_path4 = require("path");
|
|
31
34
|
|
|
32
35
|
// src/expand-file-refs.ts
|
|
33
36
|
var import_fs = require("fs");
|
|
@@ -261,6 +264,31 @@ async function checkCdpReady(url, retries = 3) {
|
|
|
261
264
|
}
|
|
262
265
|
return false;
|
|
263
266
|
}
|
|
267
|
+
async function findAvailableCdpUrl(addresses, retries = 2) {
|
|
268
|
+
for (const addr of addresses) {
|
|
269
|
+
if (await checkCdpReady(addr, retries)) {
|
|
270
|
+
return addr.replace("/json/version", "");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
async function connectPuppeteer(browserBaseUrl, attempt = 1, maxAttempts = 3) {
|
|
276
|
+
try {
|
|
277
|
+
return await promiseWithTimeout(
|
|
278
|
+
import_puppeteer_core.default.connect({ browserURL: browserBaseUrl, defaultViewport: null }),
|
|
279
|
+
1e4,
|
|
280
|
+
`puppeteer.connect to ${browserBaseUrl} timed out`
|
|
281
|
+
);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
if (attempt >= maxAttempts) {
|
|
284
|
+
throw err;
|
|
285
|
+
}
|
|
286
|
+
const delayMs = 500 * attempt;
|
|
287
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u7B2C ${attempt} \u6B21\u8FDE\u63A5\u5931\u8D25\uFF0C${delayMs}ms \u540E\u91CD\u8BD5...`));
|
|
288
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
289
|
+
return connectPuppeteer(browserBaseUrl, attempt + 1, maxAttempts);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
264
292
|
function getDefaultBrowserPath() {
|
|
265
293
|
const platform = import_os.default.platform();
|
|
266
294
|
if (platform === "darwin") {
|
|
@@ -307,72 +335,56 @@ async function startBrowserInBackground() {
|
|
|
307
335
|
}
|
|
308
336
|
console.log(import_picocolors.default.yellow(`\u6B63\u5728\u542F\u52A8\u540E\u53F0 ${browserInfo.name} \u5B9E\u4F8B (\u7AEF\u53E3: ${CDP_PORT})...`));
|
|
309
337
|
const userDataDir = process.env.WEBMCP_WORKSPACE || import_path2.default.join(import_os.default.homedir(), ".webmcp_chrome_profile");
|
|
338
|
+
const launchArgs = [
|
|
339
|
+
`--remote-debugging-port=${CDP_PORT}`,
|
|
340
|
+
`--user-data-dir=${userDataDir}`,
|
|
341
|
+
"--no-first-run",
|
|
342
|
+
"--no-default-browser-check"
|
|
343
|
+
];
|
|
344
|
+
if (import_os.default.platform() === "win32") {
|
|
345
|
+
launchArgs.push("--remote-debugging-address=127.0.0.1");
|
|
346
|
+
}
|
|
310
347
|
const child = (0, import_child_process.spawn)(
|
|
311
348
|
browserInfo.path,
|
|
312
|
-
|
|
313
|
-
`--remote-debugging-port=${CDP_PORT}`,
|
|
314
|
-
`--user-data-dir=${userDataDir}`,
|
|
315
|
-
"--no-first-run",
|
|
316
|
-
"--no-default-browser-check"
|
|
317
|
-
],
|
|
349
|
+
launchArgs,
|
|
318
350
|
{
|
|
319
351
|
detached: true,
|
|
320
352
|
stdio: "ignore"
|
|
321
353
|
}
|
|
322
354
|
);
|
|
323
355
|
child.unref();
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
356
|
+
const pollUrls = [`http://127.0.0.1:${CDP_PORT}/json/version`, `http://localhost:${CDP_PORT}/json/version`];
|
|
357
|
+
for (let i = 0; i < 30; i++) {
|
|
358
|
+
for (const url of pollUrls) {
|
|
359
|
+
try {
|
|
360
|
+
await httpGet(url, 1e3);
|
|
361
|
+
console.log(import_picocolors.default.green(`${browserInfo.name} \u542F\u52A8\u5E76\u5C31\u7EEA\u3002`));
|
|
362
|
+
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
363
|
+
return;
|
|
364
|
+
} catch {
|
|
334
365
|
}
|
|
335
|
-
} catch (e) {
|
|
336
366
|
}
|
|
337
367
|
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
338
368
|
}
|
|
339
369
|
throw new Error(`${browserInfo.name} \u542F\u52A8\u8D85\u65F6\uFF0C\u65E0\u6CD5\u8FDE\u63A5\u5230 CDP \u7AEF\u53E3\u3002`);
|
|
340
370
|
}
|
|
341
371
|
async function connectBrowser() {
|
|
342
|
-
const
|
|
343
|
-
try {
|
|
344
|
-
const info = typeof target._getTargetInfo === "function" ? target._getTargetInfo() : target;
|
|
345
|
-
const type = info.type || "";
|
|
346
|
-
const url = info.url || "";
|
|
347
|
-
if (type === "service_worker" || type === "shared_worker" || type === "iframe" || type === "other" || type === "webview" || type === "background_page") {
|
|
348
|
-
return false;
|
|
349
|
-
}
|
|
350
|
-
if (url.startsWith("devtools://") || url.startsWith("chrome-extension://")) {
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
|
-
return true;
|
|
354
|
-
} catch (e) {
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
const portAddresses = [
|
|
372
|
+
const versionAddresses = [
|
|
359
373
|
`http://127.0.0.1:${CDP_PORT}/json/version`,
|
|
360
374
|
`http://localhost:${CDP_PORT}/json/version`
|
|
361
375
|
];
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const browserURL = addr.replace("/json/version", "");
|
|
376
|
+
const existingUrl = await findAvailableCdpUrl(versionAddresses, 2);
|
|
377
|
+
if (existingUrl) {
|
|
378
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u68C0\u6D4B\u5230\u7AEF\u53E3 ${CDP_PORT} \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u8FDE\u63A5 ${existingUrl}...`));
|
|
366
379
|
try {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
380
|
+
const browser = await connectPuppeteer(existingUrl);
|
|
381
|
+
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${existingUrl}`));
|
|
382
|
+
return browser;
|
|
383
|
+
} catch (err) {
|
|
384
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
385
|
+
throw new Error(
|
|
386
|
+
`\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`
|
|
372
387
|
);
|
|
373
|
-
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
374
|
-
return browser2;
|
|
375
|
-
} catch {
|
|
376
388
|
}
|
|
377
389
|
}
|
|
378
390
|
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...`));
|
|
@@ -383,26 +395,21 @@ async function connectBrowser() {
|
|
|
383
395
|
console.error(import_picocolors.default.red(`\u65E0\u6CD5\u542F\u52A8\u6D4F\u89C8\u5668: ${msg}`));
|
|
384
396
|
throw new Error("Browser launch failed.");
|
|
385
397
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
398
|
-
return browser2;
|
|
399
|
-
} catch {
|
|
400
|
-
}
|
|
398
|
+
const launchedUrl = await findAvailableCdpUrl(versionAddresses, 5);
|
|
399
|
+
if (!launchedUrl) {
|
|
400
|
+
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`);
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
console.log(import_picocolors.default.yellow(`connectBrowser: \u6D4F\u89C8\u5668\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5 ${launchedUrl}...`));
|
|
404
|
+
const browser = await connectPuppeteer(launchedUrl);
|
|
405
|
+
console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${launchedUrl}`));
|
|
406
|
+
return browser;
|
|
407
|
+
} catch {
|
|
408
|
+
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`);
|
|
401
409
|
}
|
|
402
|
-
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`);
|
|
403
410
|
}
|
|
404
|
-
async function getPageTargetId(
|
|
405
|
-
const session = await
|
|
411
|
+
async function getPageTargetId(page) {
|
|
412
|
+
const session = await page.target().createCDPSession();
|
|
406
413
|
try {
|
|
407
414
|
const { targetInfo } = await session.send("Target.getTargetInfo");
|
|
408
415
|
return targetInfo.targetId;
|
|
@@ -411,8 +418,8 @@ async function getPageTargetId(page2) {
|
|
|
411
418
|
});
|
|
412
419
|
}
|
|
413
420
|
}
|
|
414
|
-
function getPageTargets(
|
|
415
|
-
return
|
|
421
|
+
function getPageTargets(browser) {
|
|
422
|
+
return browser.targets().filter((t) => {
|
|
416
423
|
try {
|
|
417
424
|
const type = (typeof t.type === "function" ? t.type() : t.type) || "";
|
|
418
425
|
const url = (typeof t.url === "function" ? t.url() : t.url) || "";
|
|
@@ -425,26 +432,26 @@ function getPageTargets(browser2) {
|
|
|
425
432
|
function getTargetIdFromTarget(target) {
|
|
426
433
|
return typeof target._getTargetInfo === "function" ? target._getTargetInfo().targetId : target._targetId || target.targetId || "";
|
|
427
434
|
}
|
|
428
|
-
function findPageTargetByTabId(
|
|
429
|
-
const pageTargets = getPageTargets(
|
|
435
|
+
function findPageTargetByTabId(browser, tabid) {
|
|
436
|
+
const pageTargets = getPageTargets(browser);
|
|
430
437
|
return pageTargets.find((t) => {
|
|
431
438
|
const tid = getTargetIdFromTarget(t);
|
|
432
|
-
return tid ===
|
|
439
|
+
return tid === tabid || tid.includes(tabid);
|
|
433
440
|
}) ?? null;
|
|
434
441
|
}
|
|
435
|
-
async function activateTabById(
|
|
436
|
-
const target = findPageTargetByTabId(
|
|
442
|
+
async function activateTabById(browser, tabid) {
|
|
443
|
+
const target = findPageTargetByTabId(browser, tabid);
|
|
437
444
|
if (!target) {
|
|
438
|
-
throw new Error(`Tab with targetId "${
|
|
445
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
439
446
|
}
|
|
440
447
|
const realTabId = getTargetIdFromTarget(target);
|
|
441
|
-
const pages = await
|
|
448
|
+
const pages = await browser.pages();
|
|
442
449
|
let sessionPage = pages.find((p) => !p.url().startsWith("devtools://"));
|
|
443
450
|
if (!sessionPage && pages.length > 0) {
|
|
444
451
|
sessionPage = pages[0];
|
|
445
452
|
}
|
|
446
453
|
if (!sessionPage) {
|
|
447
|
-
sessionPage = await
|
|
454
|
+
sessionPage = await browser.newPage();
|
|
448
455
|
}
|
|
449
456
|
const session = await sessionPage.createCDPSession();
|
|
450
457
|
try {
|
|
@@ -454,18 +461,18 @@ async function activateTabById(browser2, tabid2) {
|
|
|
454
461
|
});
|
|
455
462
|
}
|
|
456
463
|
}
|
|
457
|
-
async function getTargetPage(
|
|
458
|
-
const pageTargets = getPageTargets(
|
|
464
|
+
async function getTargetPage(browser, tabid) {
|
|
465
|
+
const pageTargets = getPageTargets(browser);
|
|
459
466
|
if (pageTargets.length === 0) {
|
|
460
|
-
const newPage = await
|
|
467
|
+
const newPage = await browser.newPage();
|
|
461
468
|
await injectWebMCPPolyfillAndTools(newPage);
|
|
462
469
|
return newPage;
|
|
463
470
|
}
|
|
464
471
|
let targetPage = null;
|
|
465
|
-
if (
|
|
466
|
-
const target = findPageTargetByTabId(
|
|
472
|
+
if (tabid !== void 0) {
|
|
473
|
+
const target = findPageTargetByTabId(browser, tabid);
|
|
467
474
|
if (!target) {
|
|
468
|
-
throw new Error(`Tab with targetId "${
|
|
475
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
469
476
|
}
|
|
470
477
|
targetPage = await target.page();
|
|
471
478
|
} else {
|
|
@@ -508,11 +515,11 @@ async function getTargetPage(browser2, tabid2) {
|
|
|
508
515
|
await injectWebMCPPolyfillAndTools(targetPage);
|
|
509
516
|
return targetPage;
|
|
510
517
|
}
|
|
511
|
-
async function injectIntoPage(
|
|
512
|
-
await injectWebMCPPolyfillAndTools(
|
|
518
|
+
async function injectIntoPage(page) {
|
|
519
|
+
await injectWebMCPPolyfillAndTools(page, true);
|
|
513
520
|
}
|
|
514
|
-
async function injectWebMCPPolyfillAndTools(
|
|
515
|
-
const polyfillReady = !force && await
|
|
521
|
+
async function injectWebMCPPolyfillAndTools(page, force = false) {
|
|
522
|
+
const polyfillReady = !force && await page.evaluate(() => {
|
|
516
523
|
return !!window.__webmcpcli_init;
|
|
517
524
|
}).catch(() => false);
|
|
518
525
|
if (!polyfillReady) {
|
|
@@ -523,31 +530,63 @@ async function injectWebMCPPolyfillAndTools(page2, force = false) {
|
|
|
523
530
|
}
|
|
524
531
|
const scriptContent = import_fs2.default.readFileSync(injectScriptPath, "utf-8");
|
|
525
532
|
try {
|
|
526
|
-
await
|
|
533
|
+
await page.evaluate(scriptContent);
|
|
527
534
|
} catch (err) {
|
|
528
535
|
const msg = err instanceof Error ? err.message : String(err);
|
|
529
536
|
throw new Error("\u81EA\u52A8\u6CE8\u5165\u811A\u672C\u6267\u884C\u5931\u8D25: " + msg);
|
|
530
537
|
}
|
|
531
|
-
await
|
|
538
|
+
await page.waitForFunction(() => {
|
|
539
|
+
const mcp = navigator.modelContext;
|
|
540
|
+
return mcp && typeof mcp.registerTool === "function";
|
|
541
|
+
}, { timeout: 1e4 }).catch(() => {
|
|
542
|
+
console.warn("\u7B49\u5F85 WebMCP registerTool \u63A5\u53E3\u5C31\u7EEA\u8D85\u65F6\uFF0C\u6B63\u5728\u7EE7\u7EED\u6CE8\u5165...");
|
|
543
|
+
});
|
|
532
544
|
}
|
|
533
|
-
await injectDomainTools(
|
|
545
|
+
await injectDomainTools(page);
|
|
534
546
|
}
|
|
535
|
-
|
|
547
|
+
function getToolsBundleName(hostname) {
|
|
548
|
+
const normalized = hostname.split(":")[0].toLowerCase();
|
|
549
|
+
const toolsDir = import_path2.default.resolve(__dirname, "webmcp-tools");
|
|
550
|
+
if (!import_fs2.default.existsSync(toolsDir)) {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
let files = [];
|
|
554
|
+
try {
|
|
555
|
+
files = import_fs2.default.readdirSync(toolsDir);
|
|
556
|
+
} catch {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
const supportedDomains = files.filter((f) => f.endsWith(".js")).map((f) => f.slice(0, -3));
|
|
560
|
+
if (supportedDomains.includes(normalized)) {
|
|
561
|
+
return `webmcp-tools/${normalized}.js`;
|
|
562
|
+
}
|
|
563
|
+
for (const domain of supportedDomains) {
|
|
564
|
+
if (normalized.endsWith("." + domain)) {
|
|
565
|
+
return `webmcp-tools/${domain}.js`;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
async function injectDomainTools(page) {
|
|
536
571
|
let hostname;
|
|
537
572
|
try {
|
|
538
|
-
const url = new URL(
|
|
573
|
+
const url = new URL(page.url());
|
|
539
574
|
hostname = url.hostname;
|
|
540
575
|
} catch {
|
|
541
576
|
return;
|
|
542
577
|
}
|
|
543
|
-
const
|
|
578
|
+
const bundleName = getToolsBundleName(hostname);
|
|
579
|
+
if (!bundleName) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const toolBundlePath = import_path2.default.resolve(__dirname, bundleName);
|
|
544
583
|
if (!import_fs2.default.existsSync(toolBundlePath)) {
|
|
545
584
|
return;
|
|
546
585
|
}
|
|
547
586
|
console.log(import_picocolors.default.cyan(`\u68C0\u6D4B\u5230\u57DF\u540D ${hostname} \u6709\u9884\u7F6E\u5DE5\u5177\uFF0C\u6B63\u5728\u6CE8\u5165...`));
|
|
548
587
|
const toolScript = import_fs2.default.readFileSync(toolBundlePath, "utf-8");
|
|
549
588
|
try {
|
|
550
|
-
await
|
|
589
|
+
await page.evaluate(toolScript);
|
|
551
590
|
console.log(import_picocolors.default.green(`\u5DF2\u4E3A ${hostname} \u6CE8\u5165\u9884\u7F6E\u5DE5\u5177`));
|
|
552
591
|
} catch (err) {
|
|
553
592
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -556,60 +595,23 @@ async function injectDomainTools(page2) {
|
|
|
556
595
|
}
|
|
557
596
|
|
|
558
597
|
// src/commands/state.ts
|
|
559
|
-
async function stateCommand({ tabid
|
|
560
|
-
const
|
|
598
|
+
async function stateCommand({ tabid }) {
|
|
599
|
+
const browser = await connectBrowser();
|
|
561
600
|
try {
|
|
562
|
-
const
|
|
563
|
-
await injectIntoPage(
|
|
564
|
-
const state = await
|
|
601
|
+
const page = await getTargetPage(browser, tabid);
|
|
602
|
+
await injectIntoPage(page);
|
|
603
|
+
const state = await page.evaluate(async () => {
|
|
565
604
|
const url = document.URL;
|
|
566
605
|
const title = document.title;
|
|
567
606
|
const mcp = navigator.modelContextTesting || navigator.modelContext;
|
|
568
607
|
let webmcpTools = [];
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const toolsResult = await mcp.listTools();
|
|
573
|
-
webmcpTools = toolsResult?.tools || toolsResult || [];
|
|
574
|
-
}
|
|
575
|
-
if (typeof mcp.executeTool === "function") {
|
|
576
|
-
try {
|
|
577
|
-
const argsString = JSON.stringify({ action: "browserState" });
|
|
578
|
-
let stateRes = await mcp.executeTool("page-agent-tool", argsString);
|
|
579
|
-
if (typeof stateRes === "string") {
|
|
580
|
-
try {
|
|
581
|
-
stateRes = JSON.parse(stateRes);
|
|
582
|
-
} catch (e) {
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
if (stateRes && stateRes.content && stateRes.content.length > 0) {
|
|
586
|
-
const textContent = stateRes.content.map((c) => c.text).join("\\n");
|
|
587
|
-
const prefix = "\u6D4F\u89C8\u5668\u72B6\u6001: ";
|
|
588
|
-
if (textContent.startsWith(prefix)) {
|
|
589
|
-
try {
|
|
590
|
-
const jsonStr = textContent.substring(prefix.length);
|
|
591
|
-
const parsedState = JSON.parse(jsonStr);
|
|
592
|
-
contentData = parsedState.content;
|
|
593
|
-
} catch (e) {
|
|
594
|
-
contentData = textContent;
|
|
595
|
-
}
|
|
596
|
-
} else {
|
|
597
|
-
contentData = textContent;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
} catch (e) {
|
|
601
|
-
console.error("Snapshot error:", e.message);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
608
|
+
if (mcp && typeof mcp.listTools === "function") {
|
|
609
|
+
const toolsResult = await mcp.listTools();
|
|
610
|
+
webmcpTools = toolsResult?.tools || toolsResult || [];
|
|
604
611
|
}
|
|
605
|
-
return {
|
|
606
|
-
content: contentData,
|
|
607
|
-
url,
|
|
608
|
-
title,
|
|
609
|
-
webmcpTools
|
|
610
|
-
};
|
|
612
|
+
return { url, title, webmcpTools };
|
|
611
613
|
});
|
|
612
|
-
const pages = await
|
|
614
|
+
const pages = await browser.pages();
|
|
613
615
|
const tabs2 = await Promise.all(
|
|
614
616
|
pages.map(async (p) => {
|
|
615
617
|
const pUrl = p.url();
|
|
@@ -631,7 +633,7 @@ async function stateCommand({ tabid: tabid2 }) {
|
|
|
631
633
|
tabs: tabs2.filter(Boolean)
|
|
632
634
|
};
|
|
633
635
|
} finally {
|
|
634
|
-
await
|
|
636
|
+
await browser.disconnect();
|
|
635
637
|
}
|
|
636
638
|
}
|
|
637
639
|
|
|
@@ -639,13 +641,13 @@ async function stateCommand({ tabid: tabid2 }) {
|
|
|
639
641
|
async function runCommand({
|
|
640
642
|
toolName,
|
|
641
643
|
argsJson,
|
|
642
|
-
tabid
|
|
644
|
+
tabid
|
|
643
645
|
}) {
|
|
644
|
-
const
|
|
646
|
+
const browser = await connectBrowser();
|
|
645
647
|
try {
|
|
646
|
-
const
|
|
648
|
+
const page = await getTargetPage(browser, tabid);
|
|
647
649
|
const cleanedArgs = argsJson.trim();
|
|
648
|
-
const
|
|
650
|
+
const result = await page.evaluate(async (name, inputString) => {
|
|
649
651
|
const mcp = navigator.modelContextTesting || navigator.modelContext;
|
|
650
652
|
if (!mcp || typeof mcp.executeTool !== "function") {
|
|
651
653
|
throw new Error("\u5F53\u524D\u9875\u9762\u6CA1\u6709\u6CE8\u5165 WebMCP \u73AF\u5883 (navigator.modelContextTesting.executeTool \u672A\u627E\u5230)");
|
|
@@ -666,35 +668,6 @@ async function runCommand({
|
|
|
666
668
|
}
|
|
667
669
|
return res;
|
|
668
670
|
}, toolName, cleanedArgs);
|
|
669
|
-
return result2;
|
|
670
|
-
} finally {
|
|
671
|
-
await browser2.disconnect();
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// src/commands/evaluate.ts
|
|
676
|
-
async function evaluateCommand({
|
|
677
|
-
jsScript,
|
|
678
|
-
tabid
|
|
679
|
-
}) {
|
|
680
|
-
const browser = await connectBrowser();
|
|
681
|
-
try {
|
|
682
|
-
const page = await getTargetPage(browser, tabid);
|
|
683
|
-
const result = await page.evaluate(async (script) => {
|
|
684
|
-
try {
|
|
685
|
-
const result = eval(script);
|
|
686
|
-
if (result instanceof Promise) {
|
|
687
|
-
return await result;
|
|
688
|
-
}
|
|
689
|
-
return result;
|
|
690
|
-
} catch (error) {
|
|
691
|
-
return {
|
|
692
|
-
error: true,
|
|
693
|
-
message: error.message,
|
|
694
|
-
stack: error.stack
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
|
-
}, jsScript);
|
|
698
671
|
return result;
|
|
699
672
|
} finally {
|
|
700
673
|
await browser.disconnect();
|
|
@@ -719,114 +692,114 @@ function normalizeUrl(url) {
|
|
|
719
692
|
return url;
|
|
720
693
|
}
|
|
721
694
|
async function tabsOpenCommand(url) {
|
|
722
|
-
const
|
|
695
|
+
const browser = await connectBrowser();
|
|
723
696
|
try {
|
|
724
|
-
const
|
|
697
|
+
const page = await browser.newPage();
|
|
725
698
|
url = normalizeUrl(url);
|
|
726
|
-
await
|
|
727
|
-
await injectIntoPage(
|
|
699
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
700
|
+
await injectIntoPage(page);
|
|
728
701
|
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
729
702
|
return {
|
|
730
703
|
success: true,
|
|
731
|
-
tabid: await getPageTargetId(
|
|
732
|
-
url:
|
|
733
|
-
title: await
|
|
704
|
+
tabid: await getPageTargetId(page),
|
|
705
|
+
url: page.url(),
|
|
706
|
+
title: await page.title()
|
|
734
707
|
};
|
|
735
708
|
} finally {
|
|
736
|
-
await
|
|
709
|
+
await browser.disconnect();
|
|
737
710
|
}
|
|
738
711
|
}
|
|
739
|
-
async function tabsCloseCommand(
|
|
740
|
-
const
|
|
712
|
+
async function tabsCloseCommand(tabid) {
|
|
713
|
+
const browser = await connectBrowser();
|
|
741
714
|
try {
|
|
742
|
-
const target = findPageTargetByTabId(
|
|
715
|
+
const target = findPageTargetByTabId(browser, tabid);
|
|
743
716
|
if (!target) {
|
|
744
|
-
throw new Error(`Tab with targetId "${
|
|
717
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
745
718
|
}
|
|
746
|
-
const
|
|
747
|
-
if (!
|
|
748
|
-
throw new Error(`Tab with targetId "${
|
|
719
|
+
const page = await target.page();
|
|
720
|
+
if (!page) {
|
|
721
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
749
722
|
}
|
|
750
|
-
const closedTabid = await getPageTargetId(
|
|
751
|
-
await
|
|
723
|
+
const closedTabid = await getPageTargetId(page).catch(() => tabid);
|
|
724
|
+
await page.close();
|
|
752
725
|
return {
|
|
753
726
|
success: true,
|
|
754
727
|
tabid: closedTabid
|
|
755
728
|
};
|
|
756
729
|
} finally {
|
|
757
|
-
await
|
|
730
|
+
await browser.disconnect();
|
|
758
731
|
}
|
|
759
732
|
}
|
|
760
|
-
async function tabsSwitchCommand(
|
|
761
|
-
const
|
|
733
|
+
async function tabsSwitchCommand(tabid) {
|
|
734
|
+
const browser = await connectBrowser();
|
|
762
735
|
try {
|
|
763
|
-
await activateTabById(
|
|
764
|
-
const
|
|
736
|
+
await activateTabById(browser, tabid);
|
|
737
|
+
const page = await getTargetPage(browser, tabid);
|
|
765
738
|
return {
|
|
766
739
|
success: true,
|
|
767
|
-
tabid: await getPageTargetId(
|
|
768
|
-
url:
|
|
769
|
-
title: await
|
|
740
|
+
tabid: await getPageTargetId(page),
|
|
741
|
+
url: page.url(),
|
|
742
|
+
title: await page.title()
|
|
770
743
|
};
|
|
771
744
|
} finally {
|
|
772
|
-
await
|
|
745
|
+
await browser.disconnect();
|
|
773
746
|
}
|
|
774
747
|
}
|
|
775
|
-
async function tabsBackCommand(
|
|
776
|
-
const
|
|
748
|
+
async function tabsBackCommand(tabid) {
|
|
749
|
+
const browser = await connectBrowser();
|
|
777
750
|
try {
|
|
778
|
-
const
|
|
779
|
-
const response = await
|
|
751
|
+
const page = await getTargetPage(browser, tabid);
|
|
752
|
+
const response = await page.goBack();
|
|
780
753
|
if (!response) {
|
|
781
754
|
return {
|
|
782
755
|
success: false,
|
|
783
756
|
error: "\u65E0\u6CD5\u540E\u9000\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u8D77\u70B9",
|
|
784
|
-
tabid: await getPageTargetId(
|
|
785
|
-
url:
|
|
786
|
-
title: await
|
|
757
|
+
tabid: await getPageTargetId(page).catch(() => tabid),
|
|
758
|
+
url: page.url(),
|
|
759
|
+
title: await page.title()
|
|
787
760
|
};
|
|
788
761
|
}
|
|
789
|
-
await injectIntoPage(
|
|
762
|
+
await injectIntoPage(page);
|
|
790
763
|
return {
|
|
791
764
|
success: true,
|
|
792
|
-
tabid: await getPageTargetId(
|
|
793
|
-
url:
|
|
794
|
-
title: await
|
|
765
|
+
tabid: await getPageTargetId(page),
|
|
766
|
+
url: page.url(),
|
|
767
|
+
title: await page.title()
|
|
795
768
|
};
|
|
796
769
|
} finally {
|
|
797
|
-
await
|
|
770
|
+
await browser.disconnect();
|
|
798
771
|
}
|
|
799
772
|
}
|
|
800
|
-
async function tabsForwardCommand(
|
|
801
|
-
const
|
|
773
|
+
async function tabsForwardCommand(tabid) {
|
|
774
|
+
const browser = await connectBrowser();
|
|
802
775
|
try {
|
|
803
|
-
const
|
|
804
|
-
const response = await
|
|
776
|
+
const page = await getTargetPage(browser, tabid);
|
|
777
|
+
const response = await page.goForward();
|
|
805
778
|
if (!response) {
|
|
806
779
|
return {
|
|
807
780
|
success: false,
|
|
808
781
|
error: "\u65E0\u6CD5\u524D\u8FDB\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u672B\u5C3E",
|
|
809
|
-
tabid: await getPageTargetId(
|
|
810
|
-
url:
|
|
811
|
-
title: await
|
|
782
|
+
tabid: await getPageTargetId(page).catch(() => tabid),
|
|
783
|
+
url: page.url(),
|
|
784
|
+
title: await page.title()
|
|
812
785
|
};
|
|
813
786
|
}
|
|
814
|
-
await injectIntoPage(
|
|
787
|
+
await injectIntoPage(page);
|
|
815
788
|
return {
|
|
816
789
|
success: true,
|
|
817
|
-
tabid: await getPageTargetId(
|
|
818
|
-
url:
|
|
819
|
-
title: await
|
|
790
|
+
tabid: await getPageTargetId(page),
|
|
791
|
+
url: page.url(),
|
|
792
|
+
title: await page.title()
|
|
820
793
|
};
|
|
821
794
|
} finally {
|
|
822
|
-
await
|
|
795
|
+
await browser.disconnect();
|
|
823
796
|
}
|
|
824
797
|
}
|
|
825
798
|
|
|
826
799
|
// package.json
|
|
827
800
|
var package_default = {
|
|
828
801
|
name: "@opentiny/webmcp-cli",
|
|
829
|
-
version: "0.0.
|
|
802
|
+
version: "0.0.3",
|
|
830
803
|
type: "module",
|
|
831
804
|
description: "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
|
|
832
805
|
main: "dist/index.js",
|
|
@@ -884,8 +857,97 @@ function parseTabId(id) {
|
|
|
884
857
|
if (!id) return void 0;
|
|
885
858
|
return id;
|
|
886
859
|
}
|
|
887
|
-
function
|
|
860
|
+
function cleanOldLogs(baseDir, logDir) {
|
|
861
|
+
try {
|
|
862
|
+
const oldLogFile = import_path3.default.join(baseDir, "webmcp-cli.log");
|
|
863
|
+
if (import_fs3.default.existsSync(oldLogFile)) {
|
|
864
|
+
try {
|
|
865
|
+
import_fs3.default.unlinkSync(oldLogFile);
|
|
866
|
+
} catch {
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
if (import_fs3.default.existsSync(baseDir)) {
|
|
870
|
+
const baseFiles = import_fs3.default.readdirSync(baseDir);
|
|
871
|
+
for (const file of baseFiles) {
|
|
872
|
+
if (/^webmcp-cli-\d{4}-\d{2}-\d{2}\.log$/.test(file)) {
|
|
873
|
+
try {
|
|
874
|
+
import_fs3.default.unlinkSync(import_path3.default.join(baseDir, file));
|
|
875
|
+
} catch {
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (!import_fs3.default.existsSync(logDir)) return;
|
|
881
|
+
const files = import_fs3.default.readdirSync(logDir);
|
|
882
|
+
const logFilePattern = /^webmcp-cli-(\d{4}-\d{2}-\d{2})\.log$/;
|
|
883
|
+
const now = Date.now();
|
|
884
|
+
const maxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
885
|
+
for (const file of files) {
|
|
886
|
+
const match = file.match(logFilePattern);
|
|
887
|
+
if (match) {
|
|
888
|
+
const fileDateStr = match[1];
|
|
889
|
+
const fileDate = new Date(fileDateStr).getTime();
|
|
890
|
+
if (isNaN(fileDate)) continue;
|
|
891
|
+
if (now - fileDate > maxAgeMs) {
|
|
892
|
+
try {
|
|
893
|
+
import_fs3.default.unlinkSync(import_path3.default.join(logDir, file));
|
|
894
|
+
} catch {
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
} catch (e) {
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
function writeLog(commandName, args, result, error) {
|
|
903
|
+
try {
|
|
904
|
+
const baseDir = process.env.WEBMCP_WORKSPACE || import_path3.default.join(import_os2.default.homedir(), ".webmcp_chrome_profile");
|
|
905
|
+
const logDir = import_path3.default.join(baseDir, "logs");
|
|
906
|
+
if (!import_fs3.default.existsSync(logDir)) {
|
|
907
|
+
import_fs3.default.mkdirSync(logDir, { recursive: true });
|
|
908
|
+
}
|
|
909
|
+
const todayStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
910
|
+
const logFile = import_path3.default.join(logDir, `webmcp-cli-${todayStr}.log`);
|
|
911
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
912
|
+
let logText = `========================================
|
|
913
|
+
`;
|
|
914
|
+
logText += `[${timestamp}] COMMAND: ${commandName}
|
|
915
|
+
`;
|
|
916
|
+
logText += `ARGS:
|
|
917
|
+
${JSON.stringify(args, null, 2)}
|
|
918
|
+
|
|
919
|
+
`;
|
|
920
|
+
if (error) {
|
|
921
|
+
logText += `ERROR:
|
|
922
|
+
${error instanceof Error ? error.stack : String(error)}
|
|
923
|
+
`;
|
|
924
|
+
} else if (result) {
|
|
925
|
+
logText += `RESULT:
|
|
926
|
+
`;
|
|
927
|
+
try {
|
|
928
|
+
if (result && typeof result === "object") {
|
|
929
|
+
logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
|
|
930
|
+
} else {
|
|
931
|
+
logText += String(result).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
|
|
932
|
+
}
|
|
933
|
+
} catch {
|
|
934
|
+
logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
|
|
935
|
+
}
|
|
936
|
+
} else {
|
|
937
|
+
logText += `RESULT: null
|
|
938
|
+
`;
|
|
939
|
+
}
|
|
940
|
+
logText += `========================================
|
|
941
|
+
|
|
942
|
+
`;
|
|
943
|
+
import_fs3.default.appendFileSync(logFile, logText, "utf-8");
|
|
944
|
+
cleanOldLogs(baseDir, logDir);
|
|
945
|
+
} catch (e) {
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function handleCommandError(error, commandName, args) {
|
|
888
949
|
const msg = error instanceof Error ? error.message : String(error);
|
|
950
|
+
writeLog(commandName, args, null, error);
|
|
889
951
|
console.error(import_picocolors2.default.red(`Error executing ${commandName} command: ${msg}`));
|
|
890
952
|
process.exit(1);
|
|
891
953
|
}
|
|
@@ -895,12 +957,14 @@ program.name("webmcp-cli").description("WebMCP CLI for interacting with browser
|
|
|
895
957
|
process.env.WEBMCP_WORKSPACE = opts.workspace;
|
|
896
958
|
}
|
|
897
959
|
});
|
|
898
|
-
program.command("state").description("\u83B7\u53D6\u6D4F\u89C8\u5668\u5F53\u524D\u9875\u7B7E\u6216\u6307\u5B9A\u9875\u7B7E\u7684\
|
|
960
|
+
program.command("state").description("\u83B7\u53D6\u6D4F\u89C8\u5668\u5F53\u524D\u9875\u7B7E\u6216\u6307\u5B9A\u9875\u7B7E\u7684\u5BFC\u822A\u5143\u6570\u636E\uFF08url\u3001title\u3001webmcpTools\u3001\u6240\u6709\u9875\u7B7E\u5217\u8868\uFF09").option("-t, --tabid <id>", "\u6307\u5B9A\u9875\u7B7E\u7684 ID").action(async (options) => {
|
|
961
|
+
const args = { tabid: parseTabId(options.tabid) };
|
|
899
962
|
try {
|
|
900
|
-
const
|
|
901
|
-
|
|
963
|
+
const result = await stateCommand(args);
|
|
964
|
+
writeLog("state", args, result);
|
|
965
|
+
console.log(JSON.stringify(result, null, 2));
|
|
902
966
|
} catch (error) {
|
|
903
|
-
handleCommandError(error, "state");
|
|
967
|
+
handleCommandError(error, "state", args);
|
|
904
968
|
}
|
|
905
969
|
});
|
|
906
970
|
program.command("run <toolName> [args...]").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(
|
|
@@ -911,87 +975,92 @@ program.command("run <toolName> [args...]").description("\u5411\u6307\u5B9A\u987
|
|
|
911
975
|
@base64file:<path> \u8BFB\u53D6\u6587\u4EF6\u5E76 Base64 \u7F16\u7801
|
|
912
976
|
\u793A\u4F8B\uFF1Awebmcp-cli run mytool '{"content":"@base64file:./doc.md"}'`
|
|
913
977
|
).action(async (toolName, args, options) => {
|
|
978
|
+
let finalArgsJson = "";
|
|
979
|
+
const rawArgs = { toolName, args, file: options.file, tabid: options.tabid };
|
|
914
980
|
try {
|
|
915
981
|
let fileContent;
|
|
916
982
|
let fileBaseDir = process.cwd();
|
|
917
983
|
if (options.file) {
|
|
918
|
-
const filePath = (0,
|
|
984
|
+
const filePath = (0, import_path4.resolve)(process.cwd(), options.file);
|
|
919
985
|
fileBaseDir = getFileBaseDir(options.file);
|
|
920
986
|
try {
|
|
921
|
-
fileContent = (0,
|
|
987
|
+
fileContent = (0, import_fs4.readFileSync)(filePath, "utf-8");
|
|
922
988
|
} catch (e) {
|
|
923
989
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 "${filePath}": ${e.message}`);
|
|
924
990
|
}
|
|
925
991
|
}
|
|
926
|
-
|
|
927
|
-
const
|
|
992
|
+
finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir);
|
|
993
|
+
const result = await runCommand({
|
|
928
994
|
toolName,
|
|
929
995
|
argsJson: finalArgsJson,
|
|
930
996
|
tabid: parseTabId(options.tabid)
|
|
931
997
|
});
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
handleCommandError(error, "run");
|
|
935
|
-
}
|
|
936
|
-
});
|
|
937
|
-
program.command("evaluate <jsScript>").description("\u5411\u5F53\u524D\u7F51\u9875\u6216\u6307\u5B9A\u9875\u7B7E\u6CE8\u5165\u5E76\u6267\u884C JavaScript \u4EE3\u7801").option("-t, --tabid <id>", "\u6307\u5B9A\u9875\u7B7E\u7684 ID").action(async (jsScript2, options) => {
|
|
938
|
-
try {
|
|
939
|
-
const result2 = await evaluateCommand({
|
|
940
|
-
jsScript: jsScript2,
|
|
941
|
-
tabid: parseTabId(options.tabid)
|
|
942
|
-
});
|
|
943
|
-
console.log(JSON.stringify(result2, null, 2));
|
|
998
|
+
writeLog("run", { ...rawArgs, finalArgsJson }, result);
|
|
999
|
+
console.log(JSON.stringify(result, null, 2));
|
|
944
1000
|
} catch (error) {
|
|
945
|
-
handleCommandError(error, "
|
|
1001
|
+
handleCommandError(error, "run", { ...rawArgs, finalArgsJson });
|
|
946
1002
|
}
|
|
947
1003
|
});
|
|
948
1004
|
program.command("clipboard <content>").description("\u5C06\u5185\u5BB9\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F").action(async (content) => {
|
|
1005
|
+
const args = { content };
|
|
949
1006
|
try {
|
|
950
1007
|
await setClipboard(content);
|
|
951
|
-
|
|
1008
|
+
const result = { success: true, message: "\u5185\u5BB9\u5DF2\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F" };
|
|
1009
|
+
writeLog("clipboard", args, result);
|
|
1010
|
+
console.log(JSON.stringify(result, null, 2));
|
|
952
1011
|
} catch (error) {
|
|
953
|
-
handleCommandError(error, "clipboard");
|
|
1012
|
+
handleCommandError(error, "clipboard", args);
|
|
954
1013
|
}
|
|
955
1014
|
});
|
|
956
1015
|
var tabs = program.command("tabs").description("\u7BA1\u7406\u6D4F\u89C8\u5668\u6807\u7B7E\u9875");
|
|
957
1016
|
tabs.command("open <url>").description("\u6253\u5F00\u65B0\u7F51\u9875").action(async (url) => {
|
|
1017
|
+
const args = { url };
|
|
958
1018
|
try {
|
|
959
|
-
const
|
|
960
|
-
|
|
1019
|
+
const result = await tabsOpenCommand(url);
|
|
1020
|
+
writeLog("tabs open", args, result);
|
|
1021
|
+
console.log(JSON.stringify(result, null, 2));
|
|
961
1022
|
} catch (error) {
|
|
962
|
-
handleCommandError(error, "tabs open");
|
|
1023
|
+
handleCommandError(error, "tabs open", args);
|
|
963
1024
|
}
|
|
964
1025
|
});
|
|
965
|
-
tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (
|
|
1026
|
+
tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
|
|
1027
|
+
const args = { tabid };
|
|
966
1028
|
try {
|
|
967
|
-
const
|
|
968
|
-
|
|
1029
|
+
const result = await tabsCloseCommand(tabid);
|
|
1030
|
+
writeLog("tabs close", args, result);
|
|
1031
|
+
console.log(JSON.stringify(result, null, 2));
|
|
969
1032
|
} catch (error) {
|
|
970
|
-
handleCommandError(error, "tabs close");
|
|
1033
|
+
handleCommandError(error, "tabs close", args);
|
|
971
1034
|
}
|
|
972
1035
|
});
|
|
973
|
-
tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (
|
|
1036
|
+
tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
|
|
1037
|
+
const args = { tabid };
|
|
974
1038
|
try {
|
|
975
|
-
const
|
|
976
|
-
|
|
1039
|
+
const result = await tabsSwitchCommand(tabid);
|
|
1040
|
+
writeLog("tabs switch", args, result);
|
|
1041
|
+
console.log(JSON.stringify(result, null, 2));
|
|
977
1042
|
} catch (error) {
|
|
978
|
-
handleCommandError(error, "tabs switch");
|
|
1043
|
+
handleCommandError(error, "tabs switch", args);
|
|
979
1044
|
}
|
|
980
1045
|
});
|
|
981
|
-
tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (
|
|
1046
|
+
tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (tabid) => {
|
|
1047
|
+
const args = { tabid: parseTabId(tabid) };
|
|
982
1048
|
try {
|
|
983
|
-
const
|
|
984
|
-
|
|
1049
|
+
const result = await tabsBackCommand(args.tabid);
|
|
1050
|
+
writeLog("tabs back", args, result);
|
|
1051
|
+
console.log(JSON.stringify(result, null, 2));
|
|
985
1052
|
} catch (error) {
|
|
986
|
-
handleCommandError(error, "tabs back");
|
|
1053
|
+
handleCommandError(error, "tabs back", args);
|
|
987
1054
|
}
|
|
988
1055
|
});
|
|
989
|
-
tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (
|
|
1056
|
+
tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (tabid) => {
|
|
1057
|
+
const args = { tabid: parseTabId(tabid) };
|
|
990
1058
|
try {
|
|
991
|
-
const
|
|
992
|
-
|
|
1059
|
+
const result = await tabsForwardCommand(args.tabid);
|
|
1060
|
+
writeLog("tabs forward", args, result);
|
|
1061
|
+
console.log(JSON.stringify(result, null, 2));
|
|
993
1062
|
} catch (error) {
|
|
994
|
-
handleCommandError(error, "tabs forward");
|
|
1063
|
+
handleCommandError(error, "tabs forward", args);
|
|
995
1064
|
}
|
|
996
1065
|
});
|
|
997
1066
|
program.parse(process.argv);
|