@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.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 import_fs3 = require("fs");
30
- var import_path3 = require("path");
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");
@@ -365,13 +368,13 @@ async function connectBrowser() {
365
368
  const browserURL = addr.replace("/json/version", "");
366
369
  try {
367
370
  console.log(import_picocolors.default.yellow(`connectBrowser: \u68C0\u6D4B\u5230\u7AEF\u53E3 ${CDP_PORT} \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u8FDE\u63A5 ${browserURL}...`));
368
- const browser2 = await promiseWithTimeout(
371
+ const browser = await promiseWithTimeout(
369
372
  import_puppeteer_core.default.connect({ browserURL, defaultViewport: null, targetFilter }),
370
373
  1e4,
371
374
  `puppeteer.connect to ${browserURL} timed out`
372
375
  );
373
376
  console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
374
- return browser2;
377
+ return browser;
375
378
  } catch {
376
379
  }
377
380
  }
@@ -389,20 +392,20 @@ async function connectBrowser() {
389
392
  const browserURL = addr.replace("/json/version", "");
390
393
  try {
391
394
  console.log(import_picocolors.default.yellow(`connectBrowser: \u6D4F\u89C8\u5668\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5 ${browserURL}...`));
392
- const browser2 = await promiseWithTimeout(
395
+ const browser = await promiseWithTimeout(
393
396
  import_puppeteer_core.default.connect({ browserURL, defaultViewport: null, targetFilter }),
394
397
  1e4,
395
398
  `puppeteer.connect to ${browserURL} after launch timed out`
396
399
  );
397
400
  console.log(import_picocolors.default.green(`connectBrowser: \u6210\u529F\u8FDE\u63A5 ${browserURL}`));
398
- return browser2;
401
+ return browser;
399
402
  } catch {
400
403
  }
401
404
  }
402
405
  throw new Error(`\u65E0\u6CD5\u8FDE\u63A5\u5230\u6D4F\u89C8\u5668\uFF08\u7AEF\u53E3 ${CDP_PORT}\uFF09\uFF0C\u8BF7\u68C0\u67E5 Chrome/Edge \u662F\u5426\u5DF2\u5B89\u88C5\u3002`);
403
406
  }
404
- async function getPageTargetId(page2) {
405
- const session = await page2.target().createCDPSession();
407
+ async function getPageTargetId(page) {
408
+ const session = await page.target().createCDPSession();
406
409
  try {
407
410
  const { targetInfo } = await session.send("Target.getTargetInfo");
408
411
  return targetInfo.targetId;
@@ -411,8 +414,8 @@ async function getPageTargetId(page2) {
411
414
  });
412
415
  }
413
416
  }
414
- function getPageTargets(browser2) {
415
- return browser2.targets().filter((t) => {
417
+ function getPageTargets(browser) {
418
+ return browser.targets().filter((t) => {
416
419
  try {
417
420
  const type = (typeof t.type === "function" ? t.type() : t.type) || "";
418
421
  const url = (typeof t.url === "function" ? t.url() : t.url) || "";
@@ -425,26 +428,26 @@ function getPageTargets(browser2) {
425
428
  function getTargetIdFromTarget(target) {
426
429
  return typeof target._getTargetInfo === "function" ? target._getTargetInfo().targetId : target._targetId || target.targetId || "";
427
430
  }
428
- function findPageTargetByTabId(browser2, tabid2) {
429
- const pageTargets = getPageTargets(browser2);
431
+ function findPageTargetByTabId(browser, tabid) {
432
+ const pageTargets = getPageTargets(browser);
430
433
  return pageTargets.find((t) => {
431
434
  const tid = getTargetIdFromTarget(t);
432
- return tid === tabid2 || tid.includes(tabid2);
435
+ return tid === tabid || tid.includes(tabid);
433
436
  }) ?? null;
434
437
  }
435
- async function activateTabById(browser2, tabid2) {
436
- const target = findPageTargetByTabId(browser2, tabid2);
438
+ async function activateTabById(browser, tabid) {
439
+ const target = findPageTargetByTabId(browser, tabid);
437
440
  if (!target) {
438
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
441
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
439
442
  }
440
443
  const realTabId = getTargetIdFromTarget(target);
441
- const pages = await browser2.pages();
444
+ const pages = await browser.pages();
442
445
  let sessionPage = pages.find((p) => !p.url().startsWith("devtools://"));
443
446
  if (!sessionPage && pages.length > 0) {
444
447
  sessionPage = pages[0];
445
448
  }
446
449
  if (!sessionPage) {
447
- sessionPage = await browser2.newPage();
450
+ sessionPage = await browser.newPage();
448
451
  }
449
452
  const session = await sessionPage.createCDPSession();
450
453
  try {
@@ -454,18 +457,18 @@ async function activateTabById(browser2, tabid2) {
454
457
  });
455
458
  }
456
459
  }
457
- async function getTargetPage(browser2, tabid2) {
458
- const pageTargets = getPageTargets(browser2);
460
+ async function getTargetPage(browser, tabid) {
461
+ const pageTargets = getPageTargets(browser);
459
462
  if (pageTargets.length === 0) {
460
- const newPage = await browser2.newPage();
463
+ const newPage = await browser.newPage();
461
464
  await injectWebMCPPolyfillAndTools(newPage);
462
465
  return newPage;
463
466
  }
464
467
  let targetPage = null;
465
- if (tabid2 !== void 0) {
466
- const target = findPageTargetByTabId(browser2, tabid2);
468
+ if (tabid !== void 0) {
469
+ const target = findPageTargetByTabId(browser, tabid);
467
470
  if (!target) {
468
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
471
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
469
472
  }
470
473
  targetPage = await target.page();
471
474
  } else {
@@ -508,11 +511,11 @@ async function getTargetPage(browser2, tabid2) {
508
511
  await injectWebMCPPolyfillAndTools(targetPage);
509
512
  return targetPage;
510
513
  }
511
- async function injectIntoPage(page2) {
512
- await injectWebMCPPolyfillAndTools(page2, true);
514
+ async function injectIntoPage(page) {
515
+ await injectWebMCPPolyfillAndTools(page, true);
513
516
  }
514
- async function injectWebMCPPolyfillAndTools(page2, force = false) {
515
- const polyfillReady = !force && await page2.evaluate(() => {
517
+ async function injectWebMCPPolyfillAndTools(page, force = false) {
518
+ const polyfillReady = !force && await page.evaluate(() => {
516
519
  return !!window.__webmcpcli_init;
517
520
  }).catch(() => false);
518
521
  if (!polyfillReady) {
@@ -523,31 +526,63 @@ async function injectWebMCPPolyfillAndTools(page2, force = false) {
523
526
  }
524
527
  const scriptContent = import_fs2.default.readFileSync(injectScriptPath, "utf-8");
525
528
  try {
526
- await page2.evaluate(scriptContent);
529
+ await page.evaluate(scriptContent);
527
530
  } catch (err) {
528
531
  const msg = err instanceof Error ? err.message : String(err);
529
532
  throw new Error("\u81EA\u52A8\u6CE8\u5165\u811A\u672C\u6267\u884C\u5931\u8D25: " + msg);
530
533
  }
531
- await new Promise((resolve3) => setTimeout(resolve3, 300));
534
+ await page.waitForFunction(() => {
535
+ const mcp = navigator.modelContext;
536
+ return mcp && typeof mcp.registerTool === "function";
537
+ }, { timeout: 1e4 }).catch(() => {
538
+ console.warn("\u7B49\u5F85 WebMCP registerTool \u63A5\u53E3\u5C31\u7EEA\u8D85\u65F6\uFF0C\u6B63\u5728\u7EE7\u7EED\u6CE8\u5165...");
539
+ });
540
+ }
541
+ await injectDomainTools(page);
542
+ }
543
+ function getToolsBundleName(hostname) {
544
+ const normalized = hostname.split(":")[0].toLowerCase();
545
+ const toolsDir = import_path2.default.resolve(__dirname, "webmcp-tools");
546
+ if (!import_fs2.default.existsSync(toolsDir)) {
547
+ return null;
548
+ }
549
+ let files = [];
550
+ try {
551
+ files = import_fs2.default.readdirSync(toolsDir);
552
+ } catch {
553
+ return null;
554
+ }
555
+ const supportedDomains = files.filter((f) => f.endsWith(".js")).map((f) => f.slice(0, -3));
556
+ if (supportedDomains.includes(normalized)) {
557
+ return `webmcp-tools/${normalized}.js`;
558
+ }
559
+ for (const domain of supportedDomains) {
560
+ if (normalized.endsWith("." + domain)) {
561
+ return `webmcp-tools/${domain}.js`;
562
+ }
532
563
  }
533
- await injectDomainTools(page2);
564
+ return null;
534
565
  }
535
- async function injectDomainTools(page2) {
566
+ async function injectDomainTools(page) {
536
567
  let hostname;
537
568
  try {
538
- const url = new URL(page2.url());
569
+ const url = new URL(page.url());
539
570
  hostname = url.hostname;
540
571
  } catch {
541
572
  return;
542
573
  }
543
- const toolBundlePath = import_path2.default.resolve(__dirname, "webmcp-tools", `${hostname}.js`);
574
+ const bundleName = getToolsBundleName(hostname);
575
+ if (!bundleName) {
576
+ return;
577
+ }
578
+ const toolBundlePath = import_path2.default.resolve(__dirname, bundleName);
544
579
  if (!import_fs2.default.existsSync(toolBundlePath)) {
545
580
  return;
546
581
  }
547
582
  console.log(import_picocolors.default.cyan(`\u68C0\u6D4B\u5230\u57DF\u540D ${hostname} \u6709\u9884\u7F6E\u5DE5\u5177\uFF0C\u6B63\u5728\u6CE8\u5165...`));
548
583
  const toolScript = import_fs2.default.readFileSync(toolBundlePath, "utf-8");
549
584
  try {
550
- await page2.evaluate(toolScript);
585
+ await page.evaluate(toolScript);
551
586
  console.log(import_picocolors.default.green(`\u5DF2\u4E3A ${hostname} \u6CE8\u5165\u9884\u7F6E\u5DE5\u5177`));
552
587
  } catch (err) {
553
588
  const msg = err instanceof Error ? err.message : String(err);
@@ -556,60 +591,23 @@ async function injectDomainTools(page2) {
556
591
  }
557
592
 
558
593
  // src/commands/state.ts
559
- async function stateCommand({ tabid: tabid2 }) {
560
- const browser2 = await connectBrowser();
594
+ async function stateCommand({ tabid }) {
595
+ const browser = await connectBrowser();
561
596
  try {
562
- const page2 = await getTargetPage(browser2, tabid2);
563
- await injectIntoPage(page2);
564
- const state = await page2.evaluate(async () => {
597
+ const page = await getTargetPage(browser, tabid);
598
+ await injectIntoPage(page);
599
+ const state = await page.evaluate(async () => {
565
600
  const url = document.URL;
566
601
  const title = document.title;
567
602
  const mcp = navigator.modelContextTesting || navigator.modelContext;
568
603
  let webmcpTools = [];
569
- let contentData = `\u9875\u9762\u5DF2\u51C6\u5907\u597D: ${title}`;
570
- if (mcp) {
571
- if (typeof mcp.listTools === "function") {
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
- }
604
+ if (mcp && typeof mcp.listTools === "function") {
605
+ const toolsResult = await mcp.listTools();
606
+ webmcpTools = toolsResult?.tools || toolsResult || [];
604
607
  }
605
- return {
606
- content: contentData,
607
- url,
608
- title,
609
- webmcpTools
610
- };
608
+ return { url, title, webmcpTools };
611
609
  });
612
- const pages = await browser2.pages();
610
+ const pages = await browser.pages();
613
611
  const tabs2 = await Promise.all(
614
612
  pages.map(async (p) => {
615
613
  const pUrl = p.url();
@@ -631,7 +629,7 @@ async function stateCommand({ tabid: tabid2 }) {
631
629
  tabs: tabs2.filter(Boolean)
632
630
  };
633
631
  } finally {
634
- await browser2.disconnect();
632
+ await browser.disconnect();
635
633
  }
636
634
  }
637
635
 
@@ -639,13 +637,13 @@ async function stateCommand({ tabid: tabid2 }) {
639
637
  async function runCommand({
640
638
  toolName,
641
639
  argsJson,
642
- tabid: tabid2
640
+ tabid
643
641
  }) {
644
- const browser2 = await connectBrowser();
642
+ const browser = await connectBrowser();
645
643
  try {
646
- const page2 = await getTargetPage(browser2, tabid2);
644
+ const page = await getTargetPage(browser, tabid);
647
645
  const cleanedArgs = argsJson.trim();
648
- const result2 = await page2.evaluate(async (name, inputString) => {
646
+ const result = await page.evaluate(async (name, inputString) => {
649
647
  const mcp = navigator.modelContextTesting || navigator.modelContext;
650
648
  if (!mcp || typeof mcp.executeTool !== "function") {
651
649
  throw new Error("\u5F53\u524D\u9875\u9762\u6CA1\u6709\u6CE8\u5165 WebMCP \u73AF\u5883 (navigator.modelContextTesting.executeTool \u672A\u627E\u5230)");
@@ -666,35 +664,6 @@ async function runCommand({
666
664
  }
667
665
  return res;
668
666
  }, 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
667
  return result;
699
668
  } finally {
700
669
  await browser.disconnect();
@@ -719,114 +688,114 @@ function normalizeUrl(url) {
719
688
  return url;
720
689
  }
721
690
  async function tabsOpenCommand(url) {
722
- const browser2 = await connectBrowser();
691
+ const browser = await connectBrowser();
723
692
  try {
724
- const page2 = await browser2.newPage();
693
+ const page = await browser.newPage();
725
694
  url = normalizeUrl(url);
726
- await page2.goto(url, { waitUntil: "domcontentloaded" });
727
- await injectIntoPage(page2);
695
+ await page.goto(url, { waitUntil: "domcontentloaded" });
696
+ await injectIntoPage(page);
728
697
  await new Promise((resolve3) => setTimeout(resolve3, 500));
729
698
  return {
730
699
  success: true,
731
- tabid: await getPageTargetId(page2),
732
- url: page2.url(),
733
- title: await page2.title()
700
+ tabid: await getPageTargetId(page),
701
+ url: page.url(),
702
+ title: await page.title()
734
703
  };
735
704
  } finally {
736
- await browser2.disconnect();
705
+ await browser.disconnect();
737
706
  }
738
707
  }
739
- async function tabsCloseCommand(tabid2) {
740
- const browser2 = await connectBrowser();
708
+ async function tabsCloseCommand(tabid) {
709
+ const browser = await connectBrowser();
741
710
  try {
742
- const target = findPageTargetByTabId(browser2, tabid2);
711
+ const target = findPageTargetByTabId(browser, tabid);
743
712
  if (!target) {
744
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
713
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
745
714
  }
746
- const page2 = await target.page();
747
- if (!page2) {
748
- throw new Error(`Tab with targetId "${tabid2}" not found.`);
715
+ const page = await target.page();
716
+ if (!page) {
717
+ throw new Error(`Tab with targetId "${tabid}" not found.`);
749
718
  }
750
- const closedTabid = await getPageTargetId(page2).catch(() => tabid2);
751
- await page2.close();
719
+ const closedTabid = await getPageTargetId(page).catch(() => tabid);
720
+ await page.close();
752
721
  return {
753
722
  success: true,
754
723
  tabid: closedTabid
755
724
  };
756
725
  } finally {
757
- await browser2.disconnect();
726
+ await browser.disconnect();
758
727
  }
759
728
  }
760
- async function tabsSwitchCommand(tabid2) {
761
- const browser2 = await connectBrowser();
729
+ async function tabsSwitchCommand(tabid) {
730
+ const browser = await connectBrowser();
762
731
  try {
763
- await activateTabById(browser2, tabid2);
764
- const page2 = await getTargetPage(browser2, tabid2);
732
+ await activateTabById(browser, tabid);
733
+ const page = await getTargetPage(browser, tabid);
765
734
  return {
766
735
  success: true,
767
- tabid: await getPageTargetId(page2),
768
- url: page2.url(),
769
- title: await page2.title()
736
+ tabid: await getPageTargetId(page),
737
+ url: page.url(),
738
+ title: await page.title()
770
739
  };
771
740
  } finally {
772
- await browser2.disconnect();
741
+ await browser.disconnect();
773
742
  }
774
743
  }
775
- async function tabsBackCommand(tabid2) {
776
- const browser2 = await connectBrowser();
744
+ async function tabsBackCommand(tabid) {
745
+ const browser = await connectBrowser();
777
746
  try {
778
- const page2 = await getTargetPage(browser2, tabid2);
779
- const response = await page2.goBack();
747
+ const page = await getTargetPage(browser, tabid);
748
+ const response = await page.goBack();
780
749
  if (!response) {
781
750
  return {
782
751
  success: false,
783
752
  error: "\u65E0\u6CD5\u540E\u9000\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u8D77\u70B9",
784
- tabid: await getPageTargetId(page2).catch(() => tabid2),
785
- url: page2.url(),
786
- title: await page2.title()
753
+ tabid: await getPageTargetId(page).catch(() => tabid),
754
+ url: page.url(),
755
+ title: await page.title()
787
756
  };
788
757
  }
789
- await injectIntoPage(page2);
758
+ await injectIntoPage(page);
790
759
  return {
791
760
  success: true,
792
- tabid: await getPageTargetId(page2),
793
- url: page2.url(),
794
- title: await page2.title()
761
+ tabid: await getPageTargetId(page),
762
+ url: page.url(),
763
+ title: await page.title()
795
764
  };
796
765
  } finally {
797
- await browser2.disconnect();
766
+ await browser.disconnect();
798
767
  }
799
768
  }
800
- async function tabsForwardCommand(tabid2) {
801
- const browser2 = await connectBrowser();
769
+ async function tabsForwardCommand(tabid) {
770
+ const browser = await connectBrowser();
802
771
  try {
803
- const page2 = await getTargetPage(browser2, tabid2);
804
- const response = await page2.goForward();
772
+ const page = await getTargetPage(browser, tabid);
773
+ const response = await page.goForward();
805
774
  if (!response) {
806
775
  return {
807
776
  success: false,
808
777
  error: "\u65E0\u6CD5\u524D\u8FDB\uFF1A\u5DF2\u5728\u5386\u53F2\u8BB0\u5F55\u672B\u5C3E",
809
- tabid: await getPageTargetId(page2).catch(() => tabid2),
810
- url: page2.url(),
811
- title: await page2.title()
778
+ tabid: await getPageTargetId(page).catch(() => tabid),
779
+ url: page.url(),
780
+ title: await page.title()
812
781
  };
813
782
  }
814
- await injectIntoPage(page2);
783
+ await injectIntoPage(page);
815
784
  return {
816
785
  success: true,
817
- tabid: await getPageTargetId(page2),
818
- url: page2.url(),
819
- title: await page2.title()
786
+ tabid: await getPageTargetId(page),
787
+ url: page.url(),
788
+ title: await page.title()
820
789
  };
821
790
  } finally {
822
- await browser2.disconnect();
791
+ await browser.disconnect();
823
792
  }
824
793
  }
825
794
 
826
795
  // package.json
827
796
  var package_default = {
828
797
  name: "@opentiny/webmcp-cli",
829
- version: "0.0.1-alpha.6",
798
+ version: "0.0.2",
830
799
  type: "module",
831
800
  description: "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
832
801
  main: "dist/index.js",
@@ -884,8 +853,97 @@ function parseTabId(id) {
884
853
  if (!id) return void 0;
885
854
  return id;
886
855
  }
887
- function handleCommandError(error, commandName) {
856
+ function cleanOldLogs(baseDir, logDir) {
857
+ try {
858
+ const oldLogFile = import_path3.default.join(baseDir, "webmcp-cli.log");
859
+ if (import_fs3.default.existsSync(oldLogFile)) {
860
+ try {
861
+ import_fs3.default.unlinkSync(oldLogFile);
862
+ } catch {
863
+ }
864
+ }
865
+ if (import_fs3.default.existsSync(baseDir)) {
866
+ const baseFiles = import_fs3.default.readdirSync(baseDir);
867
+ for (const file of baseFiles) {
868
+ if (/^webmcp-cli-\d{4}-\d{2}-\d{2}\.log$/.test(file)) {
869
+ try {
870
+ import_fs3.default.unlinkSync(import_path3.default.join(baseDir, file));
871
+ } catch {
872
+ }
873
+ }
874
+ }
875
+ }
876
+ if (!import_fs3.default.existsSync(logDir)) return;
877
+ const files = import_fs3.default.readdirSync(logDir);
878
+ const logFilePattern = /^webmcp-cli-(\d{4}-\d{2}-\d{2})\.log$/;
879
+ const now = Date.now();
880
+ const maxAgeMs = 7 * 24 * 60 * 60 * 1e3;
881
+ for (const file of files) {
882
+ const match = file.match(logFilePattern);
883
+ if (match) {
884
+ const fileDateStr = match[1];
885
+ const fileDate = new Date(fileDateStr).getTime();
886
+ if (isNaN(fileDate)) continue;
887
+ if (now - fileDate > maxAgeMs) {
888
+ try {
889
+ import_fs3.default.unlinkSync(import_path3.default.join(logDir, file));
890
+ } catch {
891
+ }
892
+ }
893
+ }
894
+ }
895
+ } catch (e) {
896
+ }
897
+ }
898
+ function writeLog(commandName, args, result, error) {
899
+ try {
900
+ const baseDir = process.env.WEBMCP_WORKSPACE || import_path3.default.join(import_os2.default.homedir(), ".webmcp_chrome_profile");
901
+ const logDir = import_path3.default.join(baseDir, "logs");
902
+ if (!import_fs3.default.existsSync(logDir)) {
903
+ import_fs3.default.mkdirSync(logDir, { recursive: true });
904
+ }
905
+ const todayStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
906
+ const logFile = import_path3.default.join(logDir, `webmcp-cli-${todayStr}.log`);
907
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
908
+ let logText = `========================================
909
+ `;
910
+ logText += `[${timestamp}] COMMAND: ${commandName}
911
+ `;
912
+ logText += `ARGS:
913
+ ${JSON.stringify(args, null, 2)}
914
+
915
+ `;
916
+ if (error) {
917
+ logText += `ERROR:
918
+ ${error instanceof Error ? error.stack : String(error)}
919
+ `;
920
+ } else if (result) {
921
+ logText += `RESULT:
922
+ `;
923
+ try {
924
+ if (result && typeof result === "object") {
925
+ logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
926
+ } else {
927
+ logText += String(result).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
928
+ }
929
+ } catch {
930
+ logText += JSON.stringify(result, null, 2).split("\n").map((line) => ` ${line}`).join("\n") + "\n";
931
+ }
932
+ } else {
933
+ logText += `RESULT: null
934
+ `;
935
+ }
936
+ logText += `========================================
937
+
938
+ `;
939
+ import_fs3.default.appendFileSync(logFile, logText, "utf-8");
940
+ cleanOldLogs(baseDir, logDir);
941
+ } catch (e) {
942
+ }
943
+ }
944
+ function handleCommandError(error, commandName, args) {
888
945
  const msg = error instanceof Error ? error.message : String(error);
946
+ writeLog(commandName, args, null, error);
889
947
  console.error(import_picocolors2.default.red(`Error executing ${commandName} command: ${msg}`));
890
948
  process.exit(1);
891
949
  }
@@ -895,12 +953,14 @@ program.name("webmcp-cli").description("WebMCP CLI for interacting with browser
895
953
  process.env.WEBMCP_WORKSPACE = opts.workspace;
896
954
  }
897
955
  });
898
- 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) => {
956
+ 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) => {
957
+ const args = { tabid: parseTabId(options.tabid) };
899
958
  try {
900
- const result2 = await stateCommand({ tabid: parseTabId(options.tabid) });
901
- console.log(JSON.stringify(result2, null, 2));
959
+ const result = await stateCommand(args);
960
+ writeLog("state", args, result);
961
+ console.log(JSON.stringify(result, null, 2));
902
962
  } catch (error) {
903
- handleCommandError(error, "state");
963
+ handleCommandError(error, "state", args);
904
964
  }
905
965
  });
906
966
  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 +971,92 @@ program.command("run <toolName> [args...]").description("\u5411\u6307\u5B9A\u987
911
971
  @base64file:<path> \u8BFB\u53D6\u6587\u4EF6\u5E76 Base64 \u7F16\u7801
912
972
  \u793A\u4F8B\uFF1Awebmcp-cli run mytool '{"content":"@base64file:./doc.md"}'`
913
973
  ).action(async (toolName, args, options) => {
974
+ let finalArgsJson = "";
975
+ const rawArgs = { toolName, args, file: options.file, tabid: options.tabid };
914
976
  try {
915
977
  let fileContent;
916
978
  let fileBaseDir = process.cwd();
917
979
  if (options.file) {
918
- const filePath = (0, import_path3.resolve)(process.cwd(), options.file);
980
+ const filePath = (0, import_path4.resolve)(process.cwd(), options.file);
919
981
  fileBaseDir = getFileBaseDir(options.file);
920
982
  try {
921
- fileContent = (0, import_fs3.readFileSync)(filePath, "utf-8");
983
+ fileContent = (0, import_fs4.readFileSync)(filePath, "utf-8");
922
984
  } catch (e) {
923
985
  throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 "${filePath}": ${e.message}`);
924
986
  }
925
987
  }
926
- const finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir);
927
- const result2 = await runCommand({
988
+ finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir);
989
+ const result = await runCommand({
928
990
  toolName,
929
991
  argsJson: finalArgsJson,
930
992
  tabid: parseTabId(options.tabid)
931
993
  });
932
- console.log(JSON.stringify(result2, null, 2));
933
- } catch (error) {
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));
994
+ writeLog("run", { ...rawArgs, finalArgsJson }, result);
995
+ console.log(JSON.stringify(result, null, 2));
944
996
  } catch (error) {
945
- handleCommandError(error, "evaluate");
997
+ handleCommandError(error, "run", { ...rawArgs, finalArgsJson });
946
998
  }
947
999
  });
948
1000
  program.command("clipboard <content>").description("\u5C06\u5185\u5BB9\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F").action(async (content) => {
1001
+ const args = { content };
949
1002
  try {
950
1003
  await setClipboard(content);
951
- console.log(JSON.stringify({ success: true, message: "\u5185\u5BB9\u5DF2\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F" }, null, 2));
1004
+ const result = { success: true, message: "\u5185\u5BB9\u5DF2\u8BBE\u7F6E\u5230\u7CFB\u7EDF\u526A\u8D34\u677F" };
1005
+ writeLog("clipboard", args, result);
1006
+ console.log(JSON.stringify(result, null, 2));
952
1007
  } catch (error) {
953
- handleCommandError(error, "clipboard");
1008
+ handleCommandError(error, "clipboard", args);
954
1009
  }
955
1010
  });
956
1011
  var tabs = program.command("tabs").description("\u7BA1\u7406\u6D4F\u89C8\u5668\u6807\u7B7E\u9875");
957
1012
  tabs.command("open <url>").description("\u6253\u5F00\u65B0\u7F51\u9875").action(async (url) => {
1013
+ const args = { url };
958
1014
  try {
959
- const result2 = await tabsOpenCommand(url);
960
- console.log(JSON.stringify(result2, null, 2));
1015
+ const result = await tabsOpenCommand(url);
1016
+ writeLog("tabs open", args, result);
1017
+ console.log(JSON.stringify(result, null, 2));
961
1018
  } catch (error) {
962
- handleCommandError(error, "tabs open");
1019
+ handleCommandError(error, "tabs open", args);
963
1020
  }
964
1021
  });
965
- tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid2) => {
1022
+ tabs.command("close <tabid>").description("\u5173\u95ED\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
1023
+ const args = { tabid };
966
1024
  try {
967
- const result2 = await tabsCloseCommand(tabid2);
968
- console.log(JSON.stringify(result2, null, 2));
1025
+ const result = await tabsCloseCommand(tabid);
1026
+ writeLog("tabs close", args, result);
1027
+ console.log(JSON.stringify(result, null, 2));
969
1028
  } catch (error) {
970
- handleCommandError(error, "tabs close");
1029
+ handleCommandError(error, "tabs close", args);
971
1030
  }
972
1031
  });
973
- tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid2) => {
1032
+ tabs.command("switch <tabid>").description("\u6FC0\u6D3B\u5E76\u5207\u6362\u5230\u6307\u5B9A tabid \u7684\u6807\u7B7E\u9875").action(async (tabid) => {
1033
+ const args = { tabid };
974
1034
  try {
975
- const result2 = await tabsSwitchCommand(tabid2);
976
- console.log(JSON.stringify(result2, null, 2));
1035
+ const result = await tabsSwitchCommand(tabid);
1036
+ writeLog("tabs switch", args, result);
1037
+ console.log(JSON.stringify(result, null, 2));
977
1038
  } catch (error) {
978
- handleCommandError(error, "tabs switch");
1039
+ handleCommandError(error, "tabs switch", args);
979
1040
  }
980
1041
  });
981
- tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (tabid2) => {
1042
+ tabs.command("back [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u540E\u9000\u4E00\u6B65").action(async (tabid) => {
1043
+ const args = { tabid: parseTabId(tabid) };
982
1044
  try {
983
- const result2 = await tabsBackCommand(parseTabId(tabid2));
984
- console.log(JSON.stringify(result2, null, 2));
1045
+ const result = await tabsBackCommand(args.tabid);
1046
+ writeLog("tabs back", args, result);
1047
+ console.log(JSON.stringify(result, null, 2));
985
1048
  } catch (error) {
986
- handleCommandError(error, "tabs back");
1049
+ handleCommandError(error, "tabs back", args);
987
1050
  }
988
1051
  });
989
- tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (tabid2) => {
1052
+ tabs.command("forward [tabid]").description("\u5C06\u5F53\u524D\u6216\u6307\u5B9A\u6807\u7B7E\u9875\u5BFC\u822A\u524D\u8FDB\u4E00\u6B65").action(async (tabid) => {
1053
+ const args = { tabid: parseTabId(tabid) };
990
1054
  try {
991
- const result2 = await tabsForwardCommand(parseTabId(tabid2));
992
- console.log(JSON.stringify(result2, null, 2));
1055
+ const result = await tabsForwardCommand(args.tabid);
1056
+ writeLog("tabs forward", args, result);
1057
+ console.log(JSON.stringify(result, null, 2));
993
1058
  } catch (error) {
994
- handleCommandError(error, "tabs forward");
1059
+ handleCommandError(error, "tabs forward", args);
995
1060
  }
996
1061
  });
997
1062
  program.parse(process.argv);