@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.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/bin.ts
|
|
4
|
+
import fs2 from "fs";
|
|
5
|
+
import path2 from "path";
|
|
6
|
+
import os2 from "os";
|
|
4
7
|
import { Command } from "commander";
|
|
5
8
|
import pc2 from "picocolors";
|
|
6
9
|
import { readFileSync as readFileSync2 } from "fs";
|
|
@@ -237,6 +240,31 @@ async function checkCdpReady(url, retries = 3) {
|
|
|
237
240
|
}
|
|
238
241
|
return false;
|
|
239
242
|
}
|
|
243
|
+
async function findAvailableCdpUrl(addresses, retries = 2) {
|
|
244
|
+
for (const addr of addresses) {
|
|
245
|
+
if (await checkCdpReady(addr, retries)) {
|
|
246
|
+
return addr.replace("/json/version", "");
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
async function connectPuppeteer(browserBaseUrl, attempt = 1, maxAttempts = 3) {
|
|
252
|
+
try {
|
|
253
|
+
return await promiseWithTimeout(
|
|
254
|
+
puppeteer.connect({ browserURL: browserBaseUrl, defaultViewport: null }),
|
|
255
|
+
1e4,
|
|
256
|
+
`puppeteer.connect to ${browserBaseUrl} timed out`
|
|
257
|
+
);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
if (attempt >= maxAttempts) {
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
const delayMs = 500 * attempt;
|
|
263
|
+
console.log(pc.yellow(`connectBrowser: \u7B2C ${attempt} \u6B21\u8FDE\u63A5\u5931\u8D25\uFF0C${delayMs}ms \u540E\u91CD\u8BD5...`));
|
|
264
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
265
|
+
return connectPuppeteer(browserBaseUrl, attempt + 1, maxAttempts);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
240
268
|
function getDefaultBrowserPath() {
|
|
241
269
|
const platform = os.platform();
|
|
242
270
|
if (platform === "darwin") {
|
|
@@ -283,72 +311,56 @@ async function startBrowserInBackground() {
|
|
|
283
311
|
}
|
|
284
312
|
console.log(pc.yellow(`\u6B63\u5728\u542F\u52A8\u540E\u53F0 ${browserInfo.name} \u5B9E\u4F8B (\u7AEF\u53E3: ${CDP_PORT})...`));
|
|
285
313
|
const userDataDir = process.env.WEBMCP_WORKSPACE || path.join(os.homedir(), ".webmcp_chrome_profile");
|
|
314
|
+
const launchArgs = [
|
|
315
|
+
`--remote-debugging-port=${CDP_PORT}`,
|
|
316
|
+
`--user-data-dir=${userDataDir}`,
|
|
317
|
+
"--no-first-run",
|
|
318
|
+
"--no-default-browser-check"
|
|
319
|
+
];
|
|
320
|
+
if (os.platform() === "win32") {
|
|
321
|
+
launchArgs.push("--remote-debugging-address=127.0.0.1");
|
|
322
|
+
}
|
|
286
323
|
const child = spawn(
|
|
287
324
|
browserInfo.path,
|
|
288
|
-
|
|
289
|
-
`--remote-debugging-port=${CDP_PORT}`,
|
|
290
|
-
`--user-data-dir=${userDataDir}`,
|
|
291
|
-
"--no-first-run",
|
|
292
|
-
"--no-default-browser-check"
|
|
293
|
-
],
|
|
325
|
+
launchArgs,
|
|
294
326
|
{
|
|
295
327
|
detached: true,
|
|
296
328
|
stdio: "ignore"
|
|
297
329
|
}
|
|
298
330
|
);
|
|
299
331
|
child.unref();
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
332
|
+
const pollUrls = [`http://127.0.0.1:${CDP_PORT}/json/version`, `http://localhost:${CDP_PORT}/json/version`];
|
|
333
|
+
for (let i = 0; i < 30; i++) {
|
|
334
|
+
for (const url of pollUrls) {
|
|
335
|
+
try {
|
|
336
|
+
await httpGet(url, 1e3);
|
|
337
|
+
console.log(pc.green(`${browserInfo.name} \u542F\u52A8\u5E76\u5C31\u7EEA\u3002`));
|
|
338
|
+
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
339
|
+
return;
|
|
340
|
+
} catch {
|
|
310
341
|
}
|
|
311
|
-
} catch (e) {
|
|
312
342
|
}
|
|
313
343
|
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
314
344
|
}
|
|
315
345
|
throw new Error(`${browserInfo.name} \u542F\u52A8\u8D85\u65F6\uFF0C\u65E0\u6CD5\u8FDE\u63A5\u5230 CDP \u7AEF\u53E3\u3002`);
|
|
316
346
|
}
|
|
317
347
|
async function connectBrowser() {
|
|
318
|
-
const
|
|
319
|
-
try {
|
|
320
|
-
const info = typeof target._getTargetInfo === "function" ? target._getTargetInfo() : target;
|
|
321
|
-
const type = info.type || "";
|
|
322
|
-
const url = info.url || "";
|
|
323
|
-
if (type === "service_worker" || type === "shared_worker" || type === "iframe" || type === "other" || type === "webview" || type === "background_page") {
|
|
324
|
-
return false;
|
|
325
|
-
}
|
|
326
|
-
if (url.startsWith("devtools://") || url.startsWith("chrome-extension://")) {
|
|
327
|
-
return false;
|
|
328
|
-
}
|
|
329
|
-
return true;
|
|
330
|
-
} catch (e) {
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
const portAddresses = [
|
|
348
|
+
const versionAddresses = [
|
|
335
349
|
`http://127.0.0.1:${CDP_PORT}/json/version`,
|
|
336
350
|
`http://localhost:${CDP_PORT}/json/version`
|
|
337
351
|
];
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const browserURL = addr.replace("/json/version", "");
|
|
352
|
+
const existingUrl = await findAvailableCdpUrl(versionAddresses, 2);
|
|
353
|
+
if (existingUrl) {
|
|
354
|
+
console.log(pc.yellow(`connectBrowser: \u68C0\u6D4B\u5230\u7AEF\u53E3 ${CDP_PORT} \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u8FDE\u63A5 ${existingUrl}...`));
|
|
342
355
|
try {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
356
|
+
const browser = await connectPuppeteer(existingUrl);
|
|
357
|
+
console.log(pc.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${existingUrl}`));
|
|
358
|
+
return browser;
|
|
359
|
+
} catch (err) {
|
|
360
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
361
|
+
throw new Error(
|
|
362
|
+
`\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`
|
|
348
363
|
);
|
|
349
|
-
console.log(pc.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
350
|
-
return browser2;
|
|
351
|
-
} catch {
|
|
352
364
|
}
|
|
353
365
|
}
|
|
354
366
|
console.log(pc.yellow(`connectBrowser: \u7AEF\u53E3 ${CDP_PORT} \u65E0\u54CD\u5E94\uFF0C\u6B63\u5728\u542F\u52A8\u65B0\u7684\u6D4F\u89C8\u5668\u5B9E\u4F8B...`));
|
|
@@ -359,26 +371,21 @@ async function connectBrowser() {
|
|
|
359
371
|
console.error(pc.red(`\u65E0\u6CD5\u542F\u52A8\u6D4F\u89C8\u5668: ${msg}`));
|
|
360
372
|
throw new Error("Browser launch failed.");
|
|
361
373
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
console.log(pc.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
|
|
374
|
-
return browser2;
|
|
375
|
-
} catch {
|
|
376
|
-
}
|
|
374
|
+
const launchedUrl = await findAvailableCdpUrl(versionAddresses, 5);
|
|
375
|
+
if (!launchedUrl) {
|
|
376
|
+
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`);
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
console.log(pc.yellow(`connectBrowser: \u6D4F\u89C8\u5668\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5 ${launchedUrl}...`));
|
|
380
|
+
const browser = await connectPuppeteer(launchedUrl);
|
|
381
|
+
console.log(pc.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${launchedUrl}`));
|
|
382
|
+
return browser;
|
|
383
|
+
} catch {
|
|
384
|
+
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`);
|
|
377
385
|
}
|
|
378
|
-
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`);
|
|
379
386
|
}
|
|
380
|
-
async function getPageTargetId(
|
|
381
|
-
const session = await
|
|
387
|
+
async function getPageTargetId(page) {
|
|
388
|
+
const session = await page.target().createCDPSession();
|
|
382
389
|
try {
|
|
383
390
|
const { targetInfo } = await session.send("Target.getTargetInfo");
|
|
384
391
|
return targetInfo.targetId;
|
|
@@ -387,8 +394,8 @@ async function getPageTargetId(page2) {
|
|
|
387
394
|
});
|
|
388
395
|
}
|
|
389
396
|
}
|
|
390
|
-
function getPageTargets(
|
|
391
|
-
return
|
|
397
|
+
function getPageTargets(browser) {
|
|
398
|
+
return browser.targets().filter((t) => {
|
|
392
399
|
try {
|
|
393
400
|
const type = (typeof t.type === "function" ? t.type() : t.type) || "";
|
|
394
401
|
const url = (typeof t.url === "function" ? t.url() : t.url) || "";
|
|
@@ -401,26 +408,26 @@ function getPageTargets(browser2) {
|
|
|
401
408
|
function getTargetIdFromTarget(target) {
|
|
402
409
|
return typeof target._getTargetInfo === "function" ? target._getTargetInfo().targetId : target._targetId || target.targetId || "";
|
|
403
410
|
}
|
|
404
|
-
function findPageTargetByTabId(
|
|
405
|
-
const pageTargets = getPageTargets(
|
|
411
|
+
function findPageTargetByTabId(browser, tabid) {
|
|
412
|
+
const pageTargets = getPageTargets(browser);
|
|
406
413
|
return pageTargets.find((t) => {
|
|
407
414
|
const tid = getTargetIdFromTarget(t);
|
|
408
|
-
return tid ===
|
|
415
|
+
return tid === tabid || tid.includes(tabid);
|
|
409
416
|
}) ?? null;
|
|
410
417
|
}
|
|
411
|
-
async function activateTabById(
|
|
412
|
-
const target = findPageTargetByTabId(
|
|
418
|
+
async function activateTabById(browser, tabid) {
|
|
419
|
+
const target = findPageTargetByTabId(browser, tabid);
|
|
413
420
|
if (!target) {
|
|
414
|
-
throw new Error(`Tab with targetId "${
|
|
421
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
415
422
|
}
|
|
416
423
|
const realTabId = getTargetIdFromTarget(target);
|
|
417
|
-
const pages = await
|
|
424
|
+
const pages = await browser.pages();
|
|
418
425
|
let sessionPage = pages.find((p) => !p.url().startsWith("devtools://"));
|
|
419
426
|
if (!sessionPage && pages.length > 0) {
|
|
420
427
|
sessionPage = pages[0];
|
|
421
428
|
}
|
|
422
429
|
if (!sessionPage) {
|
|
423
|
-
sessionPage = await
|
|
430
|
+
sessionPage = await browser.newPage();
|
|
424
431
|
}
|
|
425
432
|
const session = await sessionPage.createCDPSession();
|
|
426
433
|
try {
|
|
@@ -430,18 +437,18 @@ async function activateTabById(browser2, tabid2) {
|
|
|
430
437
|
});
|
|
431
438
|
}
|
|
432
439
|
}
|
|
433
|
-
async function getTargetPage(
|
|
434
|
-
const pageTargets = getPageTargets(
|
|
440
|
+
async function getTargetPage(browser, tabid) {
|
|
441
|
+
const pageTargets = getPageTargets(browser);
|
|
435
442
|
if (pageTargets.length === 0) {
|
|
436
|
-
const newPage = await
|
|
443
|
+
const newPage = await browser.newPage();
|
|
437
444
|
await injectWebMCPPolyfillAndTools(newPage);
|
|
438
445
|
return newPage;
|
|
439
446
|
}
|
|
440
447
|
let targetPage = null;
|
|
441
|
-
if (
|
|
442
|
-
const target = findPageTargetByTabId(
|
|
448
|
+
if (tabid !== void 0) {
|
|
449
|
+
const target = findPageTargetByTabId(browser, tabid);
|
|
443
450
|
if (!target) {
|
|
444
|
-
throw new Error(`Tab with targetId "${
|
|
451
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
445
452
|
}
|
|
446
453
|
targetPage = await target.page();
|
|
447
454
|
} else {
|
|
@@ -484,11 +491,11 @@ async function getTargetPage(browser2, tabid2) {
|
|
|
484
491
|
await injectWebMCPPolyfillAndTools(targetPage);
|
|
485
492
|
return targetPage;
|
|
486
493
|
}
|
|
487
|
-
async function injectIntoPage(
|
|
488
|
-
await injectWebMCPPolyfillAndTools(
|
|
494
|
+
async function injectIntoPage(page) {
|
|
495
|
+
await injectWebMCPPolyfillAndTools(page, true);
|
|
489
496
|
}
|
|
490
|
-
async function injectWebMCPPolyfillAndTools(
|
|
491
|
-
const polyfillReady = !force && await
|
|
497
|
+
async function injectWebMCPPolyfillAndTools(page, force = false) {
|
|
498
|
+
const polyfillReady = !force && await page.evaluate(() => {
|
|
492
499
|
return !!window.__webmcpcli_init;
|
|
493
500
|
}).catch(() => false);
|
|
494
501
|
if (!polyfillReady) {
|
|
@@ -499,31 +506,63 @@ async function injectWebMCPPolyfillAndTools(page2, force = false) {
|
|
|
499
506
|
}
|
|
500
507
|
const scriptContent = fs.readFileSync(injectScriptPath, "utf-8");
|
|
501
508
|
try {
|
|
502
|
-
await
|
|
509
|
+
await page.evaluate(scriptContent);
|
|
503
510
|
} catch (err) {
|
|
504
511
|
const msg = err instanceof Error ? err.message : String(err);
|
|
505
512
|
throw new Error("\u81EA\u52A8\u6CE8\u5165\u811A\u672C\u6267\u884C\u5931\u8D25: " + msg);
|
|
506
513
|
}
|
|
507
|
-
await
|
|
514
|
+
await page.waitForFunction(() => {
|
|
515
|
+
const mcp = navigator.modelContext;
|
|
516
|
+
return mcp && typeof mcp.registerTool === "function";
|
|
517
|
+
}, { timeout: 1e4 }).catch(() => {
|
|
518
|
+
console.warn("\u7B49\u5F85 WebMCP registerTool \u63A5\u53E3\u5C31\u7EEA\u8D85\u65F6\uFF0C\u6B63\u5728\u7EE7\u7EED\u6CE8\u5165...");
|
|
519
|
+
});
|
|
508
520
|
}
|
|
509
|
-
await injectDomainTools(
|
|
521
|
+
await injectDomainTools(page);
|
|
510
522
|
}
|
|
511
|
-
|
|
523
|
+
function getToolsBundleName(hostname) {
|
|
524
|
+
const normalized = hostname.split(":")[0].toLowerCase();
|
|
525
|
+
const toolsDir = path.resolve(__dirname, "webmcp-tools");
|
|
526
|
+
if (!fs.existsSync(toolsDir)) {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
let files = [];
|
|
530
|
+
try {
|
|
531
|
+
files = fs.readdirSync(toolsDir);
|
|
532
|
+
} catch {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
const supportedDomains = files.filter((f) => f.endsWith(".js")).map((f) => f.slice(0, -3));
|
|
536
|
+
if (supportedDomains.includes(normalized)) {
|
|
537
|
+
return `webmcp-tools/${normalized}.js`;
|
|
538
|
+
}
|
|
539
|
+
for (const domain of supportedDomains) {
|
|
540
|
+
if (normalized.endsWith("." + domain)) {
|
|
541
|
+
return `webmcp-tools/${domain}.js`;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
async function injectDomainTools(page) {
|
|
512
547
|
let hostname;
|
|
513
548
|
try {
|
|
514
|
-
const url = new URL(
|
|
549
|
+
const url = new URL(page.url());
|
|
515
550
|
hostname = url.hostname;
|
|
516
551
|
} catch {
|
|
517
552
|
return;
|
|
518
553
|
}
|
|
519
|
-
const
|
|
554
|
+
const bundleName = getToolsBundleName(hostname);
|
|
555
|
+
if (!bundleName) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const toolBundlePath = path.resolve(__dirname, bundleName);
|
|
520
559
|
if (!fs.existsSync(toolBundlePath)) {
|
|
521
560
|
return;
|
|
522
561
|
}
|
|
523
562
|
console.log(pc.cyan(`\u68C0\u6D4B\u5230\u57DF\u540D ${hostname} \u6709\u9884\u7F6E\u5DE5\u5177\uFF0C\u6B63\u5728\u6CE8\u5165...`));
|
|
524
563
|
const toolScript = fs.readFileSync(toolBundlePath, "utf-8");
|
|
525
564
|
try {
|
|
526
|
-
await
|
|
565
|
+
await page.evaluate(toolScript);
|
|
527
566
|
console.log(pc.green(`\u5DF2\u4E3A ${hostname} \u6CE8\u5165\u9884\u7F6E\u5DE5\u5177`));
|
|
528
567
|
} catch (err) {
|
|
529
568
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -532,60 +571,23 @@ async function injectDomainTools(page2) {
|
|
|
532
571
|
}
|
|
533
572
|
|
|
534
573
|
// src/commands/state.ts
|
|
535
|
-
async function stateCommand({ tabid
|
|
536
|
-
const
|
|
574
|
+
async function stateCommand({ tabid }) {
|
|
575
|
+
const browser = await connectBrowser();
|
|
537
576
|
try {
|
|
538
|
-
const
|
|
539
|
-
await injectIntoPage(
|
|
540
|
-
const state = await
|
|
577
|
+
const page = await getTargetPage(browser, tabid);
|
|
578
|
+
await injectIntoPage(page);
|
|
579
|
+
const state = await page.evaluate(async () => {
|
|
541
580
|
const url = document.URL;
|
|
542
581
|
const title = document.title;
|
|
543
582
|
const mcp = navigator.modelContextTesting || navigator.modelContext;
|
|
544
583
|
let webmcpTools = [];
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
const toolsResult = await mcp.listTools();
|
|
549
|
-
webmcpTools = toolsResult?.tools || toolsResult || [];
|
|
550
|
-
}
|
|
551
|
-
if (typeof mcp.executeTool === "function") {
|
|
552
|
-
try {
|
|
553
|
-
const argsString = JSON.stringify({ action: "browserState" });
|
|
554
|
-
let stateRes = await mcp.executeTool("page-agent-tool", argsString);
|
|
555
|
-
if (typeof stateRes === "string") {
|
|
556
|
-
try {
|
|
557
|
-
stateRes = JSON.parse(stateRes);
|
|
558
|
-
} catch (e) {
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
if (stateRes && stateRes.content && stateRes.content.length > 0) {
|
|
562
|
-
const textContent = stateRes.content.map((c) => c.text).join("\\n");
|
|
563
|
-
const prefix = "\u6D4F\u89C8\u5668\u72B6\u6001: ";
|
|
564
|
-
if (textContent.startsWith(prefix)) {
|
|
565
|
-
try {
|
|
566
|
-
const jsonStr = textContent.substring(prefix.length);
|
|
567
|
-
const parsedState = JSON.parse(jsonStr);
|
|
568
|
-
contentData = parsedState.content;
|
|
569
|
-
} catch (e) {
|
|
570
|
-
contentData = textContent;
|
|
571
|
-
}
|
|
572
|
-
} else {
|
|
573
|
-
contentData = textContent;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
} catch (e) {
|
|
577
|
-
console.error("Snapshot error:", e.message);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
584
|
+
if (mcp && typeof mcp.listTools === "function") {
|
|
585
|
+
const toolsResult = await mcp.listTools();
|
|
586
|
+
webmcpTools = toolsResult?.tools || toolsResult || [];
|
|
580
587
|
}
|
|
581
|
-
return {
|
|
582
|
-
content: contentData,
|
|
583
|
-
url,
|
|
584
|
-
title,
|
|
585
|
-
webmcpTools
|
|
586
|
-
};
|
|
588
|
+
return { url, title, webmcpTools };
|
|
587
589
|
});
|
|
588
|
-
const pages = await
|
|
590
|
+
const pages = await browser.pages();
|
|
589
591
|
const tabs2 = await Promise.all(
|
|
590
592
|
pages.map(async (p) => {
|
|
591
593
|
const pUrl = p.url();
|
|
@@ -607,7 +609,7 @@ async function stateCommand({ tabid: tabid2 }) {
|
|
|
607
609
|
tabs: tabs2.filter(Boolean)
|
|
608
610
|
};
|
|
609
611
|
} finally {
|
|
610
|
-
await
|
|
612
|
+
await browser.disconnect();
|
|
611
613
|
}
|
|
612
614
|
}
|
|
613
615
|
|
|
@@ -615,13 +617,13 @@ async function stateCommand({ tabid: tabid2 }) {
|
|
|
615
617
|
async function runCommand({
|
|
616
618
|
toolName,
|
|
617
619
|
argsJson,
|
|
618
|
-
tabid
|
|
620
|
+
tabid
|
|
619
621
|
}) {
|
|
620
|
-
const
|
|
622
|
+
const browser = await connectBrowser();
|
|
621
623
|
try {
|
|
622
|
-
const
|
|
624
|
+
const page = await getTargetPage(browser, tabid);
|
|
623
625
|
const cleanedArgs = argsJson.trim();
|
|
624
|
-
const
|
|
626
|
+
const result = await page.evaluate(async (name, inputString) => {
|
|
625
627
|
const mcp = navigator.modelContextTesting || navigator.modelContext;
|
|
626
628
|
if (!mcp || typeof mcp.executeTool !== "function") {
|
|
627
629
|
throw new Error("\u5F53\u524D\u9875\u9762\u6CA1\u6709\u6CE8\u5165 WebMCP \u73AF\u5883 (navigator.modelContextTesting.executeTool \u672A\u627E\u5230)");
|
|
@@ -642,35 +644,6 @@ async function runCommand({
|
|
|
642
644
|
}
|
|
643
645
|
return res;
|
|
644
646
|
}, toolName, cleanedArgs);
|
|
645
|
-
return result2;
|
|
646
|
-
} finally {
|
|
647
|
-
await browser2.disconnect();
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// src/commands/evaluate.ts
|
|
652
|
-
async function evaluateCommand({
|
|
653
|
-
jsScript,
|
|
654
|
-
tabid
|
|
655
|
-
}) {
|
|
656
|
-
const browser = await connectBrowser();
|
|
657
|
-
try {
|
|
658
|
-
const page = await getTargetPage(browser, tabid);
|
|
659
|
-
const result = await page.evaluate(async (script) => {
|
|
660
|
-
try {
|
|
661
|
-
const result = eval(script);
|
|
662
|
-
if (result instanceof Promise) {
|
|
663
|
-
return await result;
|
|
664
|
-
}
|
|
665
|
-
return result;
|
|
666
|
-
} catch (error) {
|
|
667
|
-
return {
|
|
668
|
-
error: true,
|
|
669
|
-
message: error.message,
|
|
670
|
-
stack: error.stack
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
}, jsScript);
|
|
674
647
|
return result;
|
|
675
648
|
} finally {
|
|
676
649
|
await browser.disconnect();
|
|
@@ -695,114 +668,114 @@ function normalizeUrl(url) {
|
|
|
695
668
|
return url;
|
|
696
669
|
}
|
|
697
670
|
async function tabsOpenCommand(url) {
|
|
698
|
-
const
|
|
671
|
+
const browser = await connectBrowser();
|
|
699
672
|
try {
|
|
700
|
-
const
|
|
673
|
+
const page = await browser.newPage();
|
|
701
674
|
url = normalizeUrl(url);
|
|
702
|
-
await
|
|
703
|
-
await injectIntoPage(
|
|
675
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
676
|
+
await injectIntoPage(page);
|
|
704
677
|
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
705
678
|
return {
|
|
706
679
|
success: true,
|
|
707
|
-
tabid: await getPageTargetId(
|
|
708
|
-
url:
|
|
709
|
-
title: await
|
|
680
|
+
tabid: await getPageTargetId(page),
|
|
681
|
+
url: page.url(),
|
|
682
|
+
title: await page.title()
|
|
710
683
|
};
|
|
711
684
|
} finally {
|
|
712
|
-
await
|
|
685
|
+
await browser.disconnect();
|
|
713
686
|
}
|
|
714
687
|
}
|
|
715
|
-
async function tabsCloseCommand(
|
|
716
|
-
const
|
|
688
|
+
async function tabsCloseCommand(tabid) {
|
|
689
|
+
const browser = await connectBrowser();
|
|
717
690
|
try {
|
|
718
|
-
const target = findPageTargetByTabId(
|
|
691
|
+
const target = findPageTargetByTabId(browser, tabid);
|
|
719
692
|
if (!target) {
|
|
720
|
-
throw new Error(`Tab with targetId "${
|
|
693
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
721
694
|
}
|
|
722
|
-
const
|
|
723
|
-
if (!
|
|
724
|
-
throw new Error(`Tab with targetId "${
|
|
695
|
+
const page = await target.page();
|
|
696
|
+
if (!page) {
|
|
697
|
+
throw new Error(`Tab with targetId "${tabid}" not found.`);
|
|
725
698
|
}
|
|
726
|
-
const closedTabid = await getPageTargetId(
|
|
727
|
-
await
|
|
699
|
+
const closedTabid = await getPageTargetId(page).catch(() => tabid);
|
|
700
|
+
await page.close();
|
|
728
701
|
return {
|
|
729
702
|
success: true,
|
|
730
703
|
tabid: closedTabid
|
|
731
704
|
};
|
|
732
705
|
} finally {
|
|
733
|
-
await
|
|
706
|
+
await browser.disconnect();
|
|
734
707
|
}
|
|
735
708
|
}
|
|
736
|
-
async function tabsSwitchCommand(
|
|
737
|
-
const
|
|
709
|
+
async function tabsSwitchCommand(tabid) {
|
|
710
|
+
const browser = await connectBrowser();
|
|
738
711
|
try {
|
|
739
|
-
await activateTabById(
|
|
740
|
-
const
|
|
712
|
+
await activateTabById(browser, tabid);
|
|
713
|
+
const page = await getTargetPage(browser, tabid);
|
|
741
714
|
return {
|
|
742
715
|
success: true,
|
|
743
|
-
tabid: await getPageTargetId(
|
|
744
|
-
url:
|
|
745
|
-
title: await
|
|
716
|
+
tabid: await getPageTargetId(page),
|
|
717
|
+
url: page.url(),
|
|
718
|
+
title: await page.title()
|
|
746
719
|
};
|
|
747
720
|
} finally {
|
|
748
|
-
await
|
|
721
|
+
await browser.disconnect();
|
|
749
722
|
}
|
|
750
723
|
}
|
|
751
|
-
async function tabsBackCommand(
|
|
752
|
-
const
|
|
724
|
+
async function tabsBackCommand(tabid) {
|
|
725
|
+
const browser = await connectBrowser();
|
|
753
726
|
try {
|
|
754
|
-
const
|
|
755
|
-
const response = await
|
|
727
|
+
const page = await getTargetPage(browser, tabid);
|
|
728
|
+
const response = await page.goBack();
|
|
756
729
|
if (!response) {
|
|
757
730
|
return {
|
|
758
731
|
success: false,
|
|
759
732
|
error: "\u65E0\u6CD5\u540E\u9000\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u8D77\u70B9",
|
|
760
|
-
tabid: await getPageTargetId(
|
|
761
|
-
url:
|
|
762
|
-
title: await
|
|
733
|
+
tabid: await getPageTargetId(page).catch(() => tabid),
|
|
734
|
+
url: page.url(),
|
|
735
|
+
title: await page.title()
|
|
763
736
|
};
|
|
764
737
|
}
|
|
765
|
-
await injectIntoPage(
|
|
738
|
+
await injectIntoPage(page);
|
|
766
739
|
return {
|
|
767
740
|
success: true,
|
|
768
|
-
tabid: await getPageTargetId(
|
|
769
|
-
url:
|
|
770
|
-
title: await
|
|
741
|
+
tabid: await getPageTargetId(page),
|
|
742
|
+
url: page.url(),
|
|
743
|
+
title: await page.title()
|
|
771
744
|
};
|
|
772
745
|
} finally {
|
|
773
|
-
await
|
|
746
|
+
await browser.disconnect();
|
|
774
747
|
}
|
|
775
748
|
}
|
|
776
|
-
async function tabsForwardCommand(
|
|
777
|
-
const
|
|
749
|
+
async function tabsForwardCommand(tabid) {
|
|
750
|
+
const browser = await connectBrowser();
|
|
778
751
|
try {
|
|
779
|
-
const
|
|
780
|
-
const response = await
|
|
752
|
+
const page = await getTargetPage(browser, tabid);
|
|
753
|
+
const response = await page.goForward();
|
|
781
754
|
if (!response) {
|
|
782
755
|
return {
|
|
783
756
|
success: false,
|
|
784
757
|
error: "\u65E0\u6CD5\u524D\u8FDB\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u672B\u5C3E",
|
|
785
|
-
tabid: await getPageTargetId(
|
|
786
|
-
url:
|
|
787
|
-
title: await
|
|
758
|
+
tabid: await getPageTargetId(page).catch(() => tabid),
|
|
759
|
+
url: page.url(),
|
|
760
|
+
title: await page.title()
|
|
788
761
|
};
|
|
789
762
|
}
|
|
790
|
-
await injectIntoPage(
|
|
763
|
+
await injectIntoPage(page);
|
|
791
764
|
return {
|
|
792
765
|
success: true,
|
|
793
|
-
tabid: await getPageTargetId(
|
|
794
|
-
url:
|
|
795
|
-
title: await
|
|
766
|
+
tabid: await getPageTargetId(page),
|
|
767
|
+
url: page.url(),
|
|
768
|
+
title: await page.title()
|
|
796
769
|
};
|
|
797
770
|
} finally {
|
|
798
|
-
await
|
|
771
|
+
await browser.disconnect();
|
|
799
772
|
}
|
|
800
773
|
}
|
|
801
774
|
|
|
802
775
|
// package.json
|
|
803
776
|
var package_default = {
|
|
804
777
|
name: "@opentiny/webmcp-cli",
|
|
805
|
-
version: "0.0.
|
|
778
|
+
version: "0.0.3",
|
|
806
779
|
type: "module",
|
|
807
780
|
description: "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
|
|
808
781
|
main: "dist/index.js",
|
|
@@ -860,8 +833,97 @@ function parseTabId(id) {
|
|
|
860
833
|
if (!id) return void 0;
|
|
861
834
|
return id;
|
|
862
835
|
}
|
|
863
|
-
function
|
|
836
|
+
function cleanOldLogs(baseDir, logDir) {
|
|
837
|
+
try {
|
|
838
|
+
const oldLogFile = path2.join(baseDir, "webmcp-cli.log");
|
|
839
|
+
if (fs2.existsSync(oldLogFile)) {
|
|
840
|
+
try {
|
|
841
|
+
fs2.unlinkSync(oldLogFile);
|
|
842
|
+
} catch {
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
if (fs2.existsSync(baseDir)) {
|
|
846
|
+
const baseFiles = fs2.readdirSync(baseDir);
|
|
847
|
+
for (const file of baseFiles) {
|
|
848
|
+
if (/^webmcp-cli-\d{4}-\d{2}-\d{2}\.log$/.test(file)) {
|
|
849
|
+
try {
|
|
850
|
+
fs2.unlinkSync(path2.join(baseDir, file));
|
|
851
|
+
} catch {
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (!fs2.existsSync(logDir)) return;
|
|
857
|
+
const files = fs2.readdirSync(logDir);
|
|
858
|
+
const logFilePattern = /^webmcp-cli-(\d{4}-\d{2}-\d{2})\.log$/;
|
|
859
|
+
const now = Date.now();
|
|
860
|
+
const maxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
861
|
+
for (const file of files) {
|
|
862
|
+
const match = file.match(logFilePattern);
|
|
863
|
+
if (match) {
|
|
864
|
+
const fileDateStr = match[1];
|
|
865
|
+
const fileDate = new Date(fileDateStr).getTime();
|
|
866
|
+
if (isNaN(fileDate)) continue;
|
|
867
|
+
if (now - fileDate > maxAgeMs) {
|
|
868
|
+
try {
|
|
869
|
+
fs2.unlinkSync(path2.join(logDir, file));
|
|
870
|
+
} catch {
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
} catch (e) {
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
function writeLog(commandName, args, result, error) {
|
|
879
|
+
try {
|
|
880
|
+
const baseDir = process.env.WEBMCP_WORKSPACE || path2.join(os2.homedir(), ".webmcp_chrome_profile");
|
|
881
|
+
const logDir = path2.join(baseDir, "logs");
|
|
882
|
+
if (!fs2.existsSync(logDir)) {
|
|
883
|
+
fs2.mkdirSync(logDir, { recursive: true });
|
|
884
|
+
}
|
|
885
|
+
const todayStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
886
|
+
const logFile = path2.join(logDir, `webmcp-cli-${todayStr}.log`);
|
|
887
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
888
|
+
let logText = `========================================
|
|
889
|
+
`;
|
|
890
|
+
logText += `[${timestamp}] COMMAND: ${commandName}
|
|
891
|
+
`;
|
|
892
|
+
logText += `ARGS:
|
|
893
|
+
${JSON.stringify(args, null, 2)}
|
|
894
|
+
|
|
895
|
+
`;
|
|
896
|
+
if (error) {
|
|
897
|
+
logText += `ERROR:
|
|
898
|
+
${error instanceof Error ? error.stack : String(error)}
|
|
899
|
+
`;
|
|
900
|
+
} else if (result) {
|
|
901
|
+
logText += `RESULT:
|
|
902
|
+
`;
|
|
903
|
+
try {
|
|
904
|
+
if (result && typeof result === "object") {
|
|
905
|
+
logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
|
|
906
|
+
} else {
|
|
907
|
+
logText += String(result).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
|
|
908
|
+
}
|
|
909
|
+
} catch {
|
|
910
|
+
logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
|
|
911
|
+
}
|
|
912
|
+
} else {
|
|
913
|
+
logText += `RESULT: null
|
|
914
|
+
`;
|
|
915
|
+
}
|
|
916
|
+
logText += `========================================
|
|
917
|
+
|
|
918
|
+
`;
|
|
919
|
+
fs2.appendFileSync(logFile, logText, "utf-8");
|
|
920
|
+
cleanOldLogs(baseDir, logDir);
|
|
921
|
+
} catch (e) {
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
function handleCommandError(error, commandName, args) {
|
|
864
925
|
const msg = error instanceof Error ? error.message : String(error);
|
|
926
|
+
writeLog(commandName, args, null, error);
|
|
865
927
|
console.error(pc2.red(`Error executing ${commandName} command: ${msg}`));
|
|
866
928
|
process.exit(1);
|
|
867
929
|
}
|
|
@@ -871,12 +933,14 @@ program.name("webmcp-cli").description("WebMCP CLI for interacting with browser
|
|
|
871
933
|
process.env.WEBMCP_WORKSPACE = opts.workspace;
|
|
872
934
|
}
|
|
873
935
|
});
|
|
874
|
-
program.command("state").description("\u83B7\u53D6\u6D4F\u89C8\u5668\u5F53\u524D\u9875\u7B7E\u6216\u6307\u5B9A\u9875\u7B7E\u7684\
|
|
936
|
+
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) => {
|
|
937
|
+
const args = { tabid: parseTabId(options.tabid) };
|
|
875
938
|
try {
|
|
876
|
-
const
|
|
877
|
-
|
|
939
|
+
const result = await stateCommand(args);
|
|
940
|
+
writeLog("state", args, result);
|
|
941
|
+
console.log(JSON.stringify(result, null, 2));
|
|
878
942
|
} catch (error) {
|
|
879
|
-
handleCommandError(error, "state");
|
|
943
|
+
handleCommandError(error, "state", args);
|
|
880
944
|
}
|
|
881
945
|
});
|
|
882
946
|
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(
|
|
@@ -887,6 +951,8 @@ program.command("run <toolName> [args...]").description("\u5411\u6307\u5B9A\u987
|
|
|
887
951
|
@base64file:<path> \u8BFB\u53D6\u6587\u4EF6\u5E76 Base64 \u7F16\u7801
|
|
888
952
|
\u793A\u4F8B\uFF1Awebmcp-cli run mytool '{"content":"@base64file:./doc.md"}'`
|
|
889
953
|
).action(async (toolName, args, options) => {
|
|
954
|
+
let finalArgsJson = "";
|
|
955
|
+
const rawArgs = { toolName, args, file: options.file, tabid: options.tabid };
|
|
890
956
|
try {
|
|
891
957
|
let fileContent;
|
|
892
958
|
let fileBaseDir = process.cwd();
|
|
@@ -899,75 +965,78 @@ program.command("run <toolName> [args...]").description("\u5411\u6307\u5B9A\u987
|
|
|
899
965
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 "${filePath}": ${e.message}`);
|
|
900
966
|
}
|
|
901
967
|
}
|
|
902
|
-
|
|
903
|
-
const
|
|
968
|
+
finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir);
|
|
969
|
+
const result = await runCommand({
|
|
904
970
|
toolName,
|
|
905
971
|
argsJson: finalArgsJson,
|
|
906
972
|
tabid: parseTabId(options.tabid)
|
|
907
973
|
});
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
handleCommandError(error, "run");
|
|
911
|
-
}
|
|
912
|
-
});
|
|
913
|
-
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) => {
|
|
914
|
-
try {
|
|
915
|
-
const result2 = await evaluateCommand({
|
|
916
|
-
jsScript: jsScript2,
|
|
917
|
-
tabid: parseTabId(options.tabid)
|
|
918
|
-
});
|
|
919
|
-
console.log(JSON.stringify(result2, null, 2));
|
|
974
|
+
writeLog("run", { ...rawArgs, finalArgsJson }, result);
|
|
975
|
+
console.log(JSON.stringify(result, null, 2));
|
|
920
976
|
} catch (error) {
|
|
921
|
-
handleCommandError(error, "
|
|
977
|
+
handleCommandError(error, "run", { ...rawArgs, finalArgsJson });
|
|
922
978
|
}
|
|
923
979
|
});
|
|
924
980
|
program.command("clipboard <content>").description("\u5C06\u5185\u5BB9\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F").action(async (content) => {
|
|
981
|
+
const args = { content };
|
|
925
982
|
try {
|
|
926
983
|
await setClipboard(content);
|
|
927
|
-
|
|
984
|
+
const result = { success: true, message: "\u5185\u5BB9\u5DF2\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F" };
|
|
985
|
+
writeLog("clipboard", args, result);
|
|
986
|
+
console.log(JSON.stringify(result, null, 2));
|
|
928
987
|
} catch (error) {
|
|
929
|
-
handleCommandError(error, "clipboard");
|
|
988
|
+
handleCommandError(error, "clipboard", args);
|
|
930
989
|
}
|
|
931
990
|
});
|
|
932
991
|
var tabs = program.command("tabs").description("\u7BA1\u7406\u6D4F\u89C8\u5668\u6807\u7B7E\u9875");
|
|
933
992
|
tabs.command("open <url>").description("\u6253\u5F00\u65B0\u7F51\u9875").action(async (url) => {
|
|
993
|
+
const args = { url };
|
|
934
994
|
try {
|
|
935
|
-
const
|
|
936
|
-
|
|
995
|
+
const result = await tabsOpenCommand(url);
|
|
996
|
+
writeLog("tabs open", args, result);
|
|
997
|
+
console.log(JSON.stringify(result, null, 2));
|
|
937
998
|
} catch (error) {
|
|
938
|
-
handleCommandError(error, "tabs open");
|
|
999
|
+
handleCommandError(error, "tabs open", args);
|
|
939
1000
|
}
|
|
940
1001
|
});
|
|
941
|
-
tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (
|
|
1002
|
+
tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
|
|
1003
|
+
const args = { tabid };
|
|
942
1004
|
try {
|
|
943
|
-
const
|
|
944
|
-
|
|
1005
|
+
const result = await tabsCloseCommand(tabid);
|
|
1006
|
+
writeLog("tabs close", args, result);
|
|
1007
|
+
console.log(JSON.stringify(result, null, 2));
|
|
945
1008
|
} catch (error) {
|
|
946
|
-
handleCommandError(error, "tabs close");
|
|
1009
|
+
handleCommandError(error, "tabs close", args);
|
|
947
1010
|
}
|
|
948
1011
|
});
|
|
949
|
-
tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (
|
|
1012
|
+
tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
|
|
1013
|
+
const args = { tabid };
|
|
950
1014
|
try {
|
|
951
|
-
const
|
|
952
|
-
|
|
1015
|
+
const result = await tabsSwitchCommand(tabid);
|
|
1016
|
+
writeLog("tabs switch", args, result);
|
|
1017
|
+
console.log(JSON.stringify(result, null, 2));
|
|
953
1018
|
} catch (error) {
|
|
954
|
-
handleCommandError(error, "tabs switch");
|
|
1019
|
+
handleCommandError(error, "tabs switch", args);
|
|
955
1020
|
}
|
|
956
1021
|
});
|
|
957
|
-
tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (
|
|
1022
|
+
tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (tabid) => {
|
|
1023
|
+
const args = { tabid: parseTabId(tabid) };
|
|
958
1024
|
try {
|
|
959
|
-
const
|
|
960
|
-
|
|
1025
|
+
const result = await tabsBackCommand(args.tabid);
|
|
1026
|
+
writeLog("tabs back", args, result);
|
|
1027
|
+
console.log(JSON.stringify(result, null, 2));
|
|
961
1028
|
} catch (error) {
|
|
962
|
-
handleCommandError(error, "tabs back");
|
|
1029
|
+
handleCommandError(error, "tabs back", args);
|
|
963
1030
|
}
|
|
964
1031
|
});
|
|
965
|
-
tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (
|
|
1032
|
+
tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (tabid) => {
|
|
1033
|
+
const args = { tabid: parseTabId(tabid) };
|
|
966
1034
|
try {
|
|
967
|
-
const
|
|
968
|
-
|
|
1035
|
+
const result = await tabsForwardCommand(args.tabid);
|
|
1036
|
+
writeLog("tabs forward", args, result);
|
|
1037
|
+
console.log(JSON.stringify(result, null, 2));
|
|
969
1038
|
} catch (error) {
|
|
970
|
-
handleCommandError(error, "tabs forward");
|
|
1039
|
+
handleCommandError(error, "tabs forward", args);
|
|
971
1040
|
}
|
|
972
1041
|
});
|
|
973
1042
|
program.parse(process.argv);
|