@opentiny/webmcp-cli 0.0.1-alpha.6 → 0.0.2

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.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";
@@ -341,13 +344,13 @@ async function connectBrowser() {
341
344
  const browserURL = addr.replace("/json/version", "");
342
345
  try {
343
346
  console.log(pc.yellow(`connectBrowser: \u68C0\u6D4B\u5230\u7AEF\u53E3 ${CDP_PORT} \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u8FDE\u63A5 ${browserURL}...`));
344
- const browser2 = await promiseWithTimeout(
347
+ const browser = await promiseWithTimeout(
345
348
  puppeteer.connect({ browserURL, defaultViewport: null, targetFilter }),
346
349
  1e4,
347
350
  `puppeteer.connect to ${browserURL} timed out`
348
351
  );
349
352
  console.log(pc.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
350
- return browser2;
353
+ return browser;
351
354
  } catch {
352
355
  }
353
356
  }
@@ -365,20 +368,20 @@ async function connectBrowser() {
365
368
  const browserURL = addr.replace("/json/version", "");
366
369
  try {
367
370
  console.log(pc.yellow(`connectBrowser: \u6D4F\u89C8\u5668\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5 ${browserURL}...`));
368
- const browser2 = await promiseWithTimeout(
371
+ const browser = await promiseWithTimeout(
369
372
  puppeteer.connect({ browserURL, defaultViewport: null, targetFilter }),
370
373
  1e4,
371
374
  `puppeteer.connect to ${browserURL} after launch timed out`
372
375
  );
373
376
  console.log(pc.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
374
- return browser2;
377
+ return browser;
375
378
  } catch {
376
379
  }
377
380
  }
378
381
  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
382
  }
380
- async function getPageTargetId(page2) {
381
- const session = await page2.target().createCDPSession();
383
+ async function getPageTargetId(page) {
384
+ const session = await page.target().createCDPSession();
382
385
  try {
383
386
  const { targetInfo } = await session.send("Target.getTargetInfo");
384
387
  return targetInfo.targetId;
@@ -387,8 +390,8 @@ async function getPageTargetId(page2) {
387
390
  });
388
391
  }
389
392
  }
390
- function getPageTargets(browser2) {
391
- return browser2.targets().filter((t) => {
393
+ function getPageTargets(browser) {
394
+ return browser.targets().filter((t) => {
392
395
  try {
393
396
  const type = (typeof t.type === "function" ? t.type() : t.type) || "";
394
397
  const url = (typeof t.url === "function" ? t.url() : t.url) || "";
@@ -401,26 +404,26 @@ function getPageTargets(browser2) {
401
404
  function getTargetIdFromTarget(target) {
402
405
  return typeof target._getTargetInfo === "function" ? target._getTargetInfo().targetId : target._targetId || target.targetId || "";
403
406
  }
404
- function findPageTargetByTabId(browser2, tabid2) {
405
- const pageTargets = getPageTargets(browser2);
407
+ function findPageTargetByTabId(browser, tabid) {
408
+ const pageTargets = getPageTargets(browser);
406
409
  return pageTargets.find((t) => {
407
410
  const tid = getTargetIdFromTarget(t);
408
- return tid === tabid2 || tid.includes(tabid2);
411
+ return tid === tabid || tid.includes(tabid);
409
412
  }) ?? null;
410
413
  }
411
- async function activateTabById(browser2, tabid2) {
412
- const target = findPageTargetByTabId(browser2, tabid2);
414
+ async function activateTabById(browser, tabid) {
415
+ const target = findPageTargetByTabId(browser, tabid);
413
416
  if (!target) {
414
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
417
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
415
418
  }
416
419
  const realTabId = getTargetIdFromTarget(target);
417
- const pages = await browser2.pages();
420
+ const pages = await browser.pages();
418
421
  let sessionPage = pages.find((p) => !p.url().startsWith("devtools://"));
419
422
  if (!sessionPage && pages.length > 0) {
420
423
  sessionPage = pages[0];
421
424
  }
422
425
  if (!sessionPage) {
423
- sessionPage = await browser2.newPage();
426
+ sessionPage = await browser.newPage();
424
427
  }
425
428
  const session = await sessionPage.createCDPSession();
426
429
  try {
@@ -430,18 +433,18 @@ async function activateTabById(browser2, tabid2) {
430
433
  });
431
434
  }
432
435
  }
433
- async function getTargetPage(browser2, tabid2) {
434
- const pageTargets = getPageTargets(browser2);
436
+ async function getTargetPage(browser, tabid) {
437
+ const pageTargets = getPageTargets(browser);
435
438
  if (pageTargets.length === 0) {
436
- const newPage = await browser2.newPage();
439
+ const newPage = await browser.newPage();
437
440
  await injectWebMCPPolyfillAndTools(newPage);
438
441
  return newPage;
439
442
  }
440
443
  let targetPage = null;
441
- if (tabid2 !== void 0) {
442
- const target = findPageTargetByTabId(browser2, tabid2);
444
+ if (tabid !== void 0) {
445
+ const target = findPageTargetByTabId(browser, tabid);
443
446
  if (!target) {
444
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
447
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
445
448
  }
446
449
  targetPage = await target.page();
447
450
  } else {
@@ -484,11 +487,11 @@ async function getTargetPage(browser2, tabid2) {
484
487
  await injectWebMCPPolyfillAndTools(targetPage);
485
488
  return targetPage;
486
489
  }
487
- async function injectIntoPage(page2) {
488
- await injectWebMCPPolyfillAndTools(page2, true);
490
+ async function injectIntoPage(page) {
491
+ await injectWebMCPPolyfillAndTools(page, true);
489
492
  }
490
- async function injectWebMCPPolyfillAndTools(page2, force = false) {
491
- const polyfillReady = !force && await page2.evaluate(() => {
493
+ async function injectWebMCPPolyfillAndTools(page, force = false) {
494
+ const polyfillReady = !force && await page.evaluate(() => {
492
495
  return !!window.__webmcpcli_init;
493
496
  }).catch(() => false);
494
497
  if (!polyfillReady) {
@@ -499,31 +502,63 @@ async function injectWebMCPPolyfillAndTools(page2, force = false) {
499
502
  }
500
503
  const scriptContent = fs.readFileSync(injectScriptPath, "utf-8");
501
504
  try {
502
- await page2.evaluate(scriptContent);
505
+ await page.evaluate(scriptContent);
503
506
  } catch (err) {
504
507
  const msg = err instanceof Error ? err.message : String(err);
505
508
  throw new Error("\u81EA\u52A8\u6CE8\u5165\u811A\u672C\u6267\u884C\u5931\u8D25: " + msg);
506
509
  }
507
- await new Promise((resolve3) => setTimeout(resolve3, 300));
510
+ await page.waitForFunction(() => {
511
+ const mcp = navigator.modelContext;
512
+ return mcp && typeof mcp.registerTool === "function";
513
+ }, { timeout: 1e4 }).catch(() => {
514
+ console.warn("\u7B49\u5F85 WebMCP registerTool \u63A5\u53E3\u5C31\u7EEA\u8D85\u65F6\uFF0C\u6B63\u5728\u7EE7\u7EED\u6CE8\u5165...");
515
+ });
516
+ }
517
+ await injectDomainTools(page);
518
+ }
519
+ function getToolsBundleName(hostname) {
520
+ const normalized = hostname.split(":")[0].toLowerCase();
521
+ const toolsDir = path.resolve(__dirname, "webmcp-tools");
522
+ if (!fs.existsSync(toolsDir)) {
523
+ return null;
524
+ }
525
+ let files = [];
526
+ try {
527
+ files = fs.readdirSync(toolsDir);
528
+ } catch {
529
+ return null;
530
+ }
531
+ const supportedDomains = files.filter((f) => f.endsWith(".js")).map((f) => f.slice(0, -3));
532
+ if (supportedDomains.includes(normalized)) {
533
+ return `webmcp-tools/${normalized}.js`;
534
+ }
535
+ for (const domain of supportedDomains) {
536
+ if (normalized.endsWith("." + domain)) {
537
+ return `webmcp-tools/${domain}.js`;
538
+ }
508
539
  }
509
- await injectDomainTools(page2);
540
+ return null;
510
541
  }
511
- async function injectDomainTools(page2) {
542
+ async function injectDomainTools(page) {
512
543
  let hostname;
513
544
  try {
514
- const url = new URL(page2.url());
545
+ const url = new URL(page.url());
515
546
  hostname = url.hostname;
516
547
  } catch {
517
548
  return;
518
549
  }
519
- const toolBundlePath = path.resolve(__dirname, "webmcp-tools", `${hostname}.js`);
550
+ const bundleName = getToolsBundleName(hostname);
551
+ if (!bundleName) {
552
+ return;
553
+ }
554
+ const toolBundlePath = path.resolve(__dirname, bundleName);
520
555
  if (!fs.existsSync(toolBundlePath)) {
521
556
  return;
522
557
  }
523
558
  console.log(pc.cyan(`\u68C0\u6D4B\u5230\u57DF\u540D ${hostname} \u6709\u9884\u7F6E\u5DE5\u5177\uFF0C\u6B63\u5728\u6CE8\u5165...`));
524
559
  const toolScript = fs.readFileSync(toolBundlePath, "utf-8");
525
560
  try {
526
- await page2.evaluate(toolScript);
561
+ await page.evaluate(toolScript);
527
562
  console.log(pc.green(`\u5DF2\u4E3A ${hostname} \u6CE8\u5165\u9884\u7F6E\u5DE5\u5177`));
528
563
  } catch (err) {
529
564
  const msg = err instanceof Error ? err.message : String(err);
@@ -532,60 +567,23 @@ async function injectDomainTools(page2) {
532
567
  }
533
568
 
534
569
  // src/commands/state.ts
535
- async function stateCommand({ tabid: tabid2 }) {
536
- const browser2 = await connectBrowser();
570
+ async function stateCommand({ tabid }) {
571
+ const browser = await connectBrowser();
537
572
  try {
538
- const page2 = await getTargetPage(browser2, tabid2);
539
- await injectIntoPage(page2);
540
- const state = await page2.evaluate(async () => {
573
+ const page = await getTargetPage(browser, tabid);
574
+ await injectIntoPage(page);
575
+ const state = await page.evaluate(async () => {
541
576
  const url = document.URL;
542
577
  const title = document.title;
543
578
  const mcp = navigator.modelContextTesting || navigator.modelContext;
544
579
  let webmcpTools = [];
545
- let contentData = `\u9875\u9762\u5DF2\u51C6\u5907\u597D: ${title}`;
546
- if (mcp) {
547
- if (typeof mcp.listTools === "function") {
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
- }
580
+ if (mcp && typeof mcp.listTools === "function") {
581
+ const toolsResult = await mcp.listTools();
582
+ webmcpTools = toolsResult?.tools || toolsResult || [];
580
583
  }
581
- return {
582
- content: contentData,
583
- url,
584
- title,
585
- webmcpTools
586
- };
584
+ return { url, title, webmcpTools };
587
585
  });
588
- const pages = await browser2.pages();
586
+ const pages = await browser.pages();
589
587
  const tabs2 = await Promise.all(
590
588
  pages.map(async (p) => {
591
589
  const pUrl = p.url();
@@ -607,7 +605,7 @@ async function stateCommand({ tabid: tabid2 }) {
607
605
  tabs: tabs2.filter(Boolean)
608
606
  };
609
607
  } finally {
610
- await browser2.disconnect();
608
+ await browser.disconnect();
611
609
  }
612
610
  }
613
611
 
@@ -615,13 +613,13 @@ async function stateCommand({ tabid: tabid2 }) {
615
613
  async function runCommand({
616
614
  toolName,
617
615
  argsJson,
618
- tabid: tabid2
616
+ tabid
619
617
  }) {
620
- const browser2 = await connectBrowser();
618
+ const browser = await connectBrowser();
621
619
  try {
622
- const page2 = await getTargetPage(browser2, tabid2);
620
+ const page = await getTargetPage(browser, tabid);
623
621
  const cleanedArgs = argsJson.trim();
624
- const result2 = await page2.evaluate(async (name, inputString) => {
622
+ const result = await page.evaluate(async (name, inputString) => {
625
623
  const mcp = navigator.modelContextTesting || navigator.modelContext;
626
624
  if (!mcp || typeof mcp.executeTool !== "function") {
627
625
  throw new Error("\u5F53\u524D\u9875\u9762\u6CA1\u6709\u6CE8\u5165 WebMCP \u73AF\u5883 (navigator.modelContextTesting.executeTool \u672A\u627E\u5230)");
@@ -642,35 +640,6 @@ async function runCommand({
642
640
  }
643
641
  return res;
644
642
  }, 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
643
  return result;
675
644
  } finally {
676
645
  await browser.disconnect();
@@ -695,114 +664,114 @@ function normalizeUrl(url) {
695
664
  return url;
696
665
  }
697
666
  async function tabsOpenCommand(url) {
698
- const browser2 = await connectBrowser();
667
+ const browser = await connectBrowser();
699
668
  try {
700
- const page2 = await browser2.newPage();
669
+ const page = await browser.newPage();
701
670
  url = normalizeUrl(url);
702
- await page2.goto(url, { waitUntil: "domcontentloaded" });
703
- await injectIntoPage(page2);
671
+ await page.goto(url, { waitUntil: "domcontentloaded" });
672
+ await injectIntoPage(page);
704
673
  await new Promise((resolve3) => setTimeout(resolve3, 500));
705
674
  return {
706
675
  success: true,
707
- tabid: await getPageTargetId(page2),
708
- url: page2.url(),
709
- title: await page2.title()
676
+ tabid: await getPageTargetId(page),
677
+ url: page.url(),
678
+ title: await page.title()
710
679
  };
711
680
  } finally {
712
- await browser2.disconnect();
681
+ await browser.disconnect();
713
682
  }
714
683
  }
715
- async function tabsCloseCommand(tabid2) {
716
- const browser2 = await connectBrowser();
684
+ async function tabsCloseCommand(tabid) {
685
+ const browser = await connectBrowser();
717
686
  try {
718
- const target = findPageTargetByTabId(browser2, tabid2);
687
+ const target = findPageTargetByTabId(browser, tabid);
719
688
  if (!target) {
720
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
689
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
721
690
  }
722
- const page2 = await target.page();
723
- if (!page2) {
724
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
691
+ const page = await target.page();
692
+ if (!page) {
693
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
725
694
  }
726
- const closedTabid = await getPageTargetId(page2).catch(() => tabid2);
727
- await page2.close();
695
+ const closedTabid = await getPageTargetId(page).catch(() => tabid);
696
+ await page.close();
728
697
  return {
729
698
  success: true,
730
699
  tabid: closedTabid
731
700
  };
732
701
  } finally {
733
- await browser2.disconnect();
702
+ await browser.disconnect();
734
703
  }
735
704
  }
736
- async function tabsSwitchCommand(tabid2) {
737
- const browser2 = await connectBrowser();
705
+ async function tabsSwitchCommand(tabid) {
706
+ const browser = await connectBrowser();
738
707
  try {
739
- await activateTabById(browser2, tabid2);
740
- const page2 = await getTargetPage(browser2, tabid2);
708
+ await activateTabById(browser, tabid);
709
+ const page = await getTargetPage(browser, tabid);
741
710
  return {
742
711
  success: true,
743
- tabid: await getPageTargetId(page2),
744
- url: page2.url(),
745
- title: await page2.title()
712
+ tabid: await getPageTargetId(page),
713
+ url: page.url(),
714
+ title: await page.title()
746
715
  };
747
716
  } finally {
748
- await browser2.disconnect();
717
+ await browser.disconnect();
749
718
  }
750
719
  }
751
- async function tabsBackCommand(tabid2) {
752
- const browser2 = await connectBrowser();
720
+ async function tabsBackCommand(tabid) {
721
+ const browser = await connectBrowser();
753
722
  try {
754
- const page2 = await getTargetPage(browser2, tabid2);
755
- const response = await page2.goBack();
723
+ const page = await getTargetPage(browser, tabid);
724
+ const response = await page.goBack();
756
725
  if (!response) {
757
726
  return {
758
727
  success: false,
759
728
  error: "\u65E0\u6CD5\u540E\u9000\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u8D77\u70B9",
760
- tabid: await getPageTargetId(page2).catch(() => tabid2),
761
- url: page2.url(),
762
- title: await page2.title()
729
+ tabid: await getPageTargetId(page).catch(() => tabid),
730
+ url: page.url(),
731
+ title: await page.title()
763
732
  };
764
733
  }
765
- await injectIntoPage(page2);
734
+ await injectIntoPage(page);
766
735
  return {
767
736
  success: true,
768
- tabid: await getPageTargetId(page2),
769
- url: page2.url(),
770
- title: await page2.title()
737
+ tabid: await getPageTargetId(page),
738
+ url: page.url(),
739
+ title: await page.title()
771
740
  };
772
741
  } finally {
773
- await browser2.disconnect();
742
+ await browser.disconnect();
774
743
  }
775
744
  }
776
- async function tabsForwardCommand(tabid2) {
777
- const browser2 = await connectBrowser();
745
+ async function tabsForwardCommand(tabid) {
746
+ const browser = await connectBrowser();
778
747
  try {
779
- const page2 = await getTargetPage(browser2, tabid2);
780
- const response = await page2.goForward();
748
+ const page = await getTargetPage(browser, tabid);
749
+ const response = await page.goForward();
781
750
  if (!response) {
782
751
  return {
783
752
  success: false,
784
753
  error: "\u65E0\u6CD5\u524D\u8FDB\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u672B\u5C3E",
785
- tabid: await getPageTargetId(page2).catch(() => tabid2),
786
- url: page2.url(),
787
- title: await page2.title()
754
+ tabid: await getPageTargetId(page).catch(() => tabid),
755
+ url: page.url(),
756
+ title: await page.title()
788
757
  };
789
758
  }
790
- await injectIntoPage(page2);
759
+ await injectIntoPage(page);
791
760
  return {
792
761
  success: true,
793
- tabid: await getPageTargetId(page2),
794
- url: page2.url(),
795
- title: await page2.title()
762
+ tabid: await getPageTargetId(page),
763
+ url: page.url(),
764
+ title: await page.title()
796
765
  };
797
766
  } finally {
798
- await browser2.disconnect();
767
+ await browser.disconnect();
799
768
  }
800
769
  }
801
770
 
802
771
  // package.json
803
772
  var package_default = {
804
773
  name: "@opentiny/webmcp-cli",
805
- version: "0.0.1-alpha.6",
774
+ version: "0.0.2",
806
775
  type: "module",
807
776
  description: "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
808
777
  main: "dist/index.js",
@@ -860,8 +829,97 @@ function parseTabId(id) {
860
829
  if (!id) return void 0;
861
830
  return id;
862
831
  }
863
- function handleCommandError(error, commandName) {
832
+ function cleanOldLogs(baseDir, logDir) {
833
+ try {
834
+ const oldLogFile = path2.join(baseDir, "webmcp-cli.log");
835
+ if (fs2.existsSync(oldLogFile)) {
836
+ try {
837
+ fs2.unlinkSync(oldLogFile);
838
+ } catch {
839
+ }
840
+ }
841
+ if (fs2.existsSync(baseDir)) {
842
+ const baseFiles = fs2.readdirSync(baseDir);
843
+ for (const file of baseFiles) {
844
+ if (/^webmcp-cli-\d{4}-\d{2}-\d{2}\.log$/.test(file)) {
845
+ try {
846
+ fs2.unlinkSync(path2.join(baseDir, file));
847
+ } catch {
848
+ }
849
+ }
850
+ }
851
+ }
852
+ if (!fs2.existsSync(logDir)) return;
853
+ const files = fs2.readdirSync(logDir);
854
+ const logFilePattern = /^webmcp-cli-(\d{4}-\d{2}-\d{2})\.log$/;
855
+ const now = Date.now();
856
+ const maxAgeMs = 7 * 24 * 60 * 60 * 1e3;
857
+ for (const file of files) {
858
+ const match = file.match(logFilePattern);
859
+ if (match) {
860
+ const fileDateStr = match[1];
861
+ const fileDate = new Date(fileDateStr).getTime();
862
+ if (isNaN(fileDate)) continue;
863
+ if (now - fileDate > maxAgeMs) {
864
+ try {
865
+ fs2.unlinkSync(path2.join(logDir, file));
866
+ } catch {
867
+ }
868
+ }
869
+ }
870
+ }
871
+ } catch (e) {
872
+ }
873
+ }
874
+ function writeLog(commandName, args, result, error) {
875
+ try {
876
+ const baseDir = process.env.WEBMCP_WORKSPACE || path2.join(os2.homedir(), ".webmcp_chrome_profile");
877
+ const logDir = path2.join(baseDir, "logs");
878
+ if (!fs2.existsSync(logDir)) {
879
+ fs2.mkdirSync(logDir, { recursive: true });
880
+ }
881
+ const todayStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
882
+ const logFile = path2.join(logDir, `webmcp-cli-${todayStr}.log`);
883
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
884
+ let logText = `========================================
885
+ `;
886
+ logText += `[${timestamp}] COMMAND: ${commandName}
887
+ `;
888
+ logText += `ARGS:
889
+ ${JSON.stringify(args, null, 2)}
890
+
891
+ `;
892
+ if (error) {
893
+ logText += `ERROR:
894
+ ${error instanceof Error ? error.stack : String(error)}
895
+ `;
896
+ } else if (result) {
897
+ logText += `RESULT:
898
+ `;
899
+ try {
900
+ if (result && typeof result === "object") {
901
+ logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
902
+ } else {
903
+ logText += String(result).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
904
+ }
905
+ } catch {
906
+ logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
907
+ }
908
+ } else {
909
+ logText += `RESULT: null
910
+ `;
911
+ }
912
+ logText += `========================================
913
+
914
+ `;
915
+ fs2.appendFileSync(logFile, logText, "utf-8");
916
+ cleanOldLogs(baseDir, logDir);
917
+ } catch (e) {
918
+ }
919
+ }
920
+ function handleCommandError(error, commandName, args) {
864
921
  const msg = error instanceof Error ? error.message : String(error);
922
+ writeLog(commandName, args, null, error);
865
923
  console.error(pc2.red(`Error executing ${commandName} command: ${msg}`));
866
924
  process.exit(1);
867
925
  }
@@ -871,12 +929,14 @@ program.name("webmcp-cli").description("WebMCP CLI for interacting with browser
871
929
  process.env.WEBMCP_WORKSPACE = opts.workspace;
872
930
  }
873
931
  });
874
- program.command("state").description("\u83B7\u53D6\u6D4F\u89C8\u5668\u5F53\u524D\u9875\u7B7E\u6216\u6307\u5B9A\u9875\u7B7E\u7684\u72B6\u6001\uFF08\u5185\u5BB9\u3001\u6240\u6709\u9875\u7B7E\u5217\u8868\u3001\u53EF\u7528 WebMCP \u5DE5\u5177\u5217\u8868\uFF09").option("-t, --tabid <id>", "\u6307\u5B9A\u9875\u7B7E\u7684 ID").action(async (options) => {
932
+ 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) => {
933
+ const args = { tabid: parseTabId(options.tabid) };
875
934
  try {
876
- const result2 = await stateCommand({ tabid: parseTabId(options.tabid) });
877
- console.log(JSON.stringify(result2, null, 2));
935
+ const result = await stateCommand(args);
936
+ writeLog("state", args, result);
937
+ console.log(JSON.stringify(result, null, 2));
878
938
  } catch (error) {
879
- handleCommandError(error, "state");
939
+ handleCommandError(error, "state", args);
880
940
  }
881
941
  });
882
942
  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 +947,8 @@ program.command("run <toolName> [args...]").description("\u5411\u6307\u5B9A\u987
887
947
  @base64file:<path> \u8BFB\u53D6\u6587\u4EF6\u5E76 Base64 \u7F16\u7801
888
948
  \u793A\u4F8B\uFF1Awebmcp-cli run mytool '{"content":"@base64file:./doc.md"}'`
889
949
  ).action(async (toolName, args, options) => {
950
+ let finalArgsJson = "";
951
+ const rawArgs = { toolName, args, file: options.file, tabid: options.tabid };
890
952
  try {
891
953
  let fileContent;
892
954
  let fileBaseDir = process.cwd();
@@ -899,75 +961,78 @@ program.command("run <toolName> [args...]").description("\u5411\u6307\u5B9A\u987
899
961
  throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 "${filePath}": ${e.message}`);
900
962
  }
901
963
  }
902
- const finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir);
903
- const result2 = await runCommand({
964
+ finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir);
965
+ const result = await runCommand({
904
966
  toolName,
905
967
  argsJson: finalArgsJson,
906
968
  tabid: parseTabId(options.tabid)
907
969
  });
908
- console.log(JSON.stringify(result2, null, 2));
909
- } catch (error) {
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));
970
+ writeLog("run", { ...rawArgs, finalArgsJson }, result);
971
+ console.log(JSON.stringify(result, null, 2));
920
972
  } catch (error) {
921
- handleCommandError(error, "evaluate");
973
+ handleCommandError(error, "run", { ...rawArgs, finalArgsJson });
922
974
  }
923
975
  });
924
976
  program.command("clipboard <content>").description("\u5C06\u5185\u5BB9\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F").action(async (content) => {
977
+ const args = { content };
925
978
  try {
926
979
  await setClipboard(content);
927
- console.log(JSON.stringify({ success: true, message: "\u5185\u5BB9\u5DF2\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F" }, null, 2));
980
+ const result = { success: true, message: "\u5185\u5BB9\u5DF2\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F" };
981
+ writeLog("clipboard", args, result);
982
+ console.log(JSON.stringify(result, null, 2));
928
983
  } catch (error) {
929
- handleCommandError(error, "clipboard");
984
+ handleCommandError(error, "clipboard", args);
930
985
  }
931
986
  });
932
987
  var tabs = program.command("tabs").description("\u7BA1\u7406\u6D4F\u89C8\u5668\u6807\u7B7E\u9875");
933
988
  tabs.command("open <url>").description("\u6253\u5F00\u65B0\u7F51\u9875").action(async (url) => {
989
+ const args = { url };
934
990
  try {
935
- const result2 = await tabsOpenCommand(url);
936
- console.log(JSON.stringify(result2, null, 2));
991
+ const result = await tabsOpenCommand(url);
992
+ writeLog("tabs open", args, result);
993
+ console.log(JSON.stringify(result, null, 2));
937
994
  } catch (error) {
938
- handleCommandError(error, "tabs open");
995
+ handleCommandError(error, "tabs open", args);
939
996
  }
940
997
  });
941
- tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid2) => {
998
+ tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
999
+ const args = { tabid };
942
1000
  try {
943
- const result2 = await tabsCloseCommand(tabid2);
944
- console.log(JSON.stringify(result2, null, 2));
1001
+ const result = await tabsCloseCommand(tabid);
1002
+ writeLog("tabs close", args, result);
1003
+ console.log(JSON.stringify(result, null, 2));
945
1004
  } catch (error) {
946
- handleCommandError(error, "tabs close");
1005
+ handleCommandError(error, "tabs close", args);
947
1006
  }
948
1007
  });
949
- tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid2) => {
1008
+ tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
1009
+ const args = { tabid };
950
1010
  try {
951
- const result2 = await tabsSwitchCommand(tabid2);
952
- console.log(JSON.stringify(result2, null, 2));
1011
+ const result = await tabsSwitchCommand(tabid);
1012
+ writeLog("tabs switch", args, result);
1013
+ console.log(JSON.stringify(result, null, 2));
953
1014
  } catch (error) {
954
- handleCommandError(error, "tabs switch");
1015
+ handleCommandError(error, "tabs switch", args);
955
1016
  }
956
1017
  });
957
- tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (tabid2) => {
1018
+ tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (tabid) => {
1019
+ const args = { tabid: parseTabId(tabid) };
958
1020
  try {
959
- const result2 = await tabsBackCommand(parseTabId(tabid2));
960
- console.log(JSON.stringify(result2, null, 2));
1021
+ const result = await tabsBackCommand(args.tabid);
1022
+ writeLog("tabs back", args, result);
1023
+ console.log(JSON.stringify(result, null, 2));
961
1024
  } catch (error) {
962
- handleCommandError(error, "tabs back");
1025
+ handleCommandError(error, "tabs back", args);
963
1026
  }
964
1027
  });
965
- tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (tabid2) => {
1028
+ tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (tabid) => {
1029
+ const args = { tabid: parseTabId(tabid) };
966
1030
  try {
967
- const result2 = await tabsForwardCommand(parseTabId(tabid2));
968
- console.log(JSON.stringify(result2, null, 2));
1031
+ const result = await tabsForwardCommand(args.tabid);
1032
+ writeLog("tabs forward", args, result);
1033
+ console.log(JSON.stringify(result, null, 2));
969
1034
  } catch (error) {
970
- handleCommandError(error, "tabs forward");
1035
+ handleCommandError(error, "tabs forward", args);
971
1036
  }
972
1037
  });
973
1038
  program.parse(process.argv);