@tontoko/fast-playwright-mcp 0.0.8 → 0.1.0

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.
Files changed (44) hide show
  1. package/README.md +277 -117
  2. package/lib/batch/batch-executor.js +4 -5
  3. package/lib/browser-context-factory.js +2 -4
  4. package/lib/browser-server-backend.js +5 -7
  5. package/lib/config.js +1 -1
  6. package/lib/context.js +1 -4
  7. package/lib/diagnostics/common/error-enrichment-utils.js +3 -2
  8. package/lib/diagnostics/common/index.js +4 -55
  9. package/lib/diagnostics/element-discovery.js +1 -2
  10. package/lib/diagnostics/frame-reference-manager.js +5 -6
  11. package/lib/diagnostics/resource-manager.js +1 -2
  12. package/lib/diagnostics/smart-config.js +5 -6
  13. package/lib/diagnostics/smart-handle.js +1 -2
  14. package/lib/extension/cdp-relay.js +32 -34
  15. package/lib/extension/extension-context-factory.js +4 -5
  16. package/lib/in-process-client.js +1 -1
  17. package/lib/loop/loop.js +5 -5
  18. package/lib/loopTools/main.js +1 -1
  19. package/lib/mcp/proxy-backend.js +2 -2
  20. package/lib/mcp/server.js +4 -6
  21. package/lib/{log.js → mcp/tool.js} +17 -11
  22. package/lib/mcp/transport.js +2 -4
  23. package/lib/program.js +2 -3
  24. package/lib/response.js +1 -2
  25. package/lib/session-log.js +1 -1
  26. package/lib/tab.js +2 -4
  27. package/lib/tools/diagnose/diagnose-config-handler.js +2 -3
  28. package/lib/tools/evaluate.js +1 -1
  29. package/lib/tools/keyboard.js +1 -1
  30. package/lib/tools/network.js +97 -6
  31. package/lib/tools/pdf.js +1 -1
  32. package/lib/tools/screenshot.js +1 -1
  33. package/lib/tools/snapshot.js +1 -1
  34. package/lib/tools/utils.js +6 -7
  35. package/lib/{javascript.js → utils/codegen.js} +1 -1
  36. package/lib/utils/common-formatters.js +2 -3
  37. package/lib/utils/error-handler-middleware.js +1 -2
  38. package/lib/{utils.js → utils/guid.js} +1 -1
  39. package/lib/utils/index.js +6 -0
  40. package/lib/utils/log.js +90 -0
  41. package/lib/utils/network-filter.js +114 -0
  42. package/lib/{package.js → utils/package.js} +2 -2
  43. package/lib/utils/request-logger.js +1 -1
  44. package/package.json +3 -3
package/lib/program.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // src/program.ts
2
2
  import { Option, program } from "commander";
3
- import debug from "debug";
4
3
  import { startTraceViewerServer } from "playwright-core/lib/server";
5
4
  import { contextFactory } from "./browser-context-factory.js";
6
5
  import {
@@ -18,9 +17,9 @@ import {
18
17
  } from "./extension/main.js";
19
18
  import { runLoopTools } from "./loopTools/main.js";
20
19
  import { start } from "./mcp/transport.js";
21
- import { packageJSON } from "./package.js";
20
+ import { programDebug } from "./utils/log.js";
21
+ import { packageJSON } from "./utils/package.js";
22
22
  import { logServerStart } from "./utils/request-logger.js";
23
- var programDebug = debug("pw:mcp:program");
24
23
  program.version(`Version ${packageJSON.version}`).name(packageJSON.name).option("--allowed-origins <origins>", "semicolon-separated list of origins to allow the browser to request. Default is to allow all.", semicolonSeparatedList).option("--blocked-origins <origins>", "semicolon-separated list of origins to block the browser from requesting. Blocklist is evaluated before allowlist. If used without the allowlist, requests not matching the blocklist are still allowed.", semicolonSeparatedList).option("--block-service-workers", "block service workers").option("--browser <browser>", "browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.").option("--caps <caps>", "comma-separated list of additional capabilities to enable, possible values: vision, pdf.", commaSeparatedList).option("--cdp-endpoint <endpoint>", "CDP endpoint to connect to.").option("--config <path>", "path to the configuration file.").option("--device <device>", 'device to emulate, for example: "iPhone 15"').option("--executable-path <path>", "path to the browser executable.").option("--headless", "run browser in headless mode, headed by default").option("--host <host>", "host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.").option("--ignore-https-errors", "ignore https errors").option("--isolated", "keep the browser profile in memory, do not save it to disk.").option("--image-responses <mode>", 'whether to send image responses to the client. Can be "allow" or "omit", Defaults to "allow".').option("--no-sandbox", "disable the sandbox for all process types that are normally sandboxed.").option("--output-dir <path>", "path to the directory for output files.").option("--port <port>", "port to listen on for SSE transport.").option("--proxy-bypass <bypass>", 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option("--proxy-server <proxy>", 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option("--save-session", "Whether to save the Playwright MCP session into the output directory.").option("--save-trace", "Whether to save the Playwright Trace of the session into the output directory.").option("--storage-state <path>", "path to the storage state file for isolated sessions.").option("--user-agent <ua string>", "specify user agent string").option("--user-data-dir <path>", "path to the user data directory. If not specified, a temporary directory will be created.").option("--viewport-size <size>", 'specify browser viewport size in pixels, for example "1280, 720"').addOption(new Option("--extension", 'Connect to a running browser instance (Edge/Chrome only). Requires the "Playwright MCP Bridge" browser extension to be installed.').hideHelp()).addOption(new Option("--connect-tool", "Allow to switch between different browser connection methods.").hideHelp()).addOption(new Option("--loop-tools", "Run loop tools").hideHelp()).addOption(new Option("--vision", "Legacy option, use --caps=vision instead").hideHelp()).action(async (options) => {
25
24
  setupExitWatchdog();
26
25
  if (options.vision) {
package/lib/response.js CHANGED
@@ -18,15 +18,14 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/response.ts
21
- import debug from "debug";
22
21
  import { TIMEOUTS } from "./config/constants.js";
23
22
  import { mergeExpectations } from "./schemas/expectation.js";
24
23
  import { renderModalStates } from "./tab.js";
25
24
  import { filterConsoleMessages } from "./utils/console-filter.js";
26
25
  import { processImage } from "./utils/image-processor.js";
26
+ import { responseDebug } from "./utils/log.js";
27
27
  import { TextReportBuilder } from "./utils/report-builder.js";
28
28
  import { ResponseDiffDetector } from "./utils/response-diff-detector.js";
29
- var responseDebug = debug("pw:mcp:response");
30
29
 
31
30
  class Response {
32
31
  _result = [];
@@ -21,7 +21,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
21
21
  import fs from "node:fs";
22
22
  import path from "node:path";
23
23
  import { outputFile } from "./config.js";
24
- import { logUnhandledError } from "./log.js";
24
+ import { logUnhandledError } from "./utils/log.js";
25
25
 
26
26
  class SessionLog {
27
27
  _folder;
package/lib/tab.js CHANGED
@@ -19,17 +19,15 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tab.ts
21
21
  import { EventEmitter } from "node:events";
22
- import debug from "debug";
23
22
  import { TIMEOUTS } from "./config/constants.js";
24
- import { logUnhandledError } from "./log.js";
25
23
  import { ManualPromise } from "./manual-promise.js";
26
24
  import { callOnPageNoTrace, waitForCompletion } from "./tools/utils.js";
25
+ import { logUnhandledError } from "./utils/log.js";
26
+ import { snapshotDebug, tabDebug } from "./utils/log.js";
27
27
  var REF_VALUE_REGEX = /\[ref=([^\]]+)\]/;
28
28
  var TabEvents = {
29
29
  modalState: "modalState"
30
30
  };
31
- var snapshotDebug = debug("pw:mcp:snapshot");
32
- var tabDebug = debug("pw:mcp:tab");
33
31
 
34
32
  class Tab extends EventEmitter {
35
33
  context;
@@ -18,11 +18,10 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/diagnose/diagnose-config-handler.ts
21
- import debug from "debug";
22
21
  import { getCurrentThresholds } from "../../diagnostics/diagnostic-thresholds.js";
23
22
  import { PageAnalyzer } from "../../diagnostics/page-analyzer.js";
24
23
  import { UnifiedDiagnosticSystem } from "../../diagnostics/unified-system.js";
25
- var configDebug = debug("pw:mcp:diagnose-config");
24
+ import { smartConfigDebug } from "../../utils/log.js";
26
25
 
27
26
  class DiagnoseConfigHandler {
28
27
  validateConfiguration() {
@@ -30,7 +29,7 @@ class DiagnoseConfigHandler {
30
29
  const thresholdsManager = getCurrentThresholds();
31
30
  return thresholdsManager.getConfigDiagnostics();
32
31
  } catch (error) {
33
- configDebug("Configuration validation failed:", error);
32
+ smartConfigDebug("Configuration validation failed:", error);
34
33
  return {
35
34
  status: "failed",
36
35
  warnings: [
@@ -19,8 +19,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/evaluate.ts
21
21
  import { z } from "zod";
22
- import { quote } from "../javascript.js";
23
22
  import { expectationSchema } from "../schemas/expectation.js";
23
+ import { quote } from "../utils/codegen.js";
24
24
  import { defineTabTool } from "./tool.js";
25
25
  import { generateLocator } from "./utils.js";
26
26
  var evaluateSchema = z.object({
@@ -19,8 +19,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/keyboard.ts
21
21
  import { z } from "zod";
22
- import { quote } from "../javascript.js";
23
22
  import { expectationSchema } from "../schemas/expectation.js";
23
+ import { quote } from "../utils/codegen.js";
24
24
  import { generateKeyPressCode } from "../utils/common-formatters.js";
25
25
  import { baseElementSchema as elementSchema } from "./base-tool-handler.js";
26
26
  import { defineTabTool } from "./tool.js";
@@ -19,23 +19,114 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/network.ts
21
21
  import { z } from "zod";
22
+ import {
23
+ filterNetworkRequests
24
+ } from "../utils/network-filter.js";
22
25
  import { defineTabTool } from "./tool.js";
26
+ var networkFilterSchema = z.object({
27
+ urlPatterns: z.array(z.string()).optional(),
28
+ excludeUrlPatterns: z.array(z.string()).optional(),
29
+ statusRanges: z.array(z.object({
30
+ min: z.number(),
31
+ max: z.number()
32
+ })).optional(),
33
+ methods: z.array(z.string()).optional(),
34
+ maxRequests: z.number().default(20),
35
+ newestFirst: z.boolean().default(true)
36
+ });
23
37
  var requests = defineTabTool({
24
38
  capability: "core",
25
39
  schema: {
26
40
  name: "browser_network_requests",
27
41
  title: "List network requests",
28
- description: "Returns all network requests since loading the page",
29
- inputSchema: z.object({}),
42
+ description: 'Returns network requests since loading the page with optional filtering. urlPatterns:["api/users"] to filter by URL patterns. excludeUrlPatterns:["analytics"] to exclude specific patterns. statusRanges:[{min:200,max:299}] for success codes only. methods:["GET","POST"] to filter by HTTP method. maxRequests:10 to limit results. newestFirst:false for chronological order. Supports regex patterns for advanced filtering.',
43
+ inputSchema: networkFilterSchema.partial(),
30
44
  type: "readOnly"
31
45
  },
32
- handle: async (tab, _params, response) => {
33
- const requestList = await Promise.resolve(tab.requests());
34
- for (const [req, res] of requestList.entries()) {
35
- response.addResult(renderRequest(req, res));
46
+ handle: async (tab, params, response) => {
47
+ try {
48
+ const requestList = await Promise.resolve(tab.requests());
49
+ const requestEntries = Array.from(requestList.entries());
50
+ const filterOptions = buildFilterOptions(params);
51
+ const result = processNetworkRequests(requestEntries, filterOptions);
52
+ displayFilterSummary(response, filterOptions, result.filteredCount, result.totalCount);
53
+ displayResults(response, result.filteredRequests, result.totalCount);
54
+ } catch (error) {
55
+ response.addResult(`Error retrieving network requests: ${error instanceof Error ? error.message : String(error)}`);
36
56
  }
37
57
  }
38
58
  });
59
+ function hasFilterOptions(options) {
60
+ return !!(options.urlPatterns?.length || options.excludeUrlPatterns?.length || options.statusRanges?.length || options.methods?.length || options.maxRequests && options.maxRequests !== 20);
61
+ }
62
+ function applyFilters(requestList, options) {
63
+ const networkRequests = requestList.map(([request, response]) => ({
64
+ url: request.url(),
65
+ method: request.method(),
66
+ status: response?.status(),
67
+ statusText: response?.statusText() || "",
68
+ headers: response?.headers() || {},
69
+ timestamp: Date.now(),
70
+ duration: undefined
71
+ }));
72
+ const filtered = filterNetworkRequests(networkRequests, options);
73
+ return requestList.filter(([request]) => filtered.some((f) => f.url === request.url() && f.method === request.method()));
74
+ }
75
+ function buildFilterOptions(params) {
76
+ return {
77
+ urlPatterns: params.urlPatterns,
78
+ excludeUrlPatterns: params.excludeUrlPatterns,
79
+ statusRanges: params.statusRanges,
80
+ methods: params.methods,
81
+ maxRequests: params.maxRequests ?? 20,
82
+ newestFirst: params.newestFirst ?? true
83
+ };
84
+ }
85
+ function processNetworkRequests(requestEntries, filterOptions) {
86
+ const totalCount = requestEntries.length;
87
+ let filteredRequests = applyFilters(requestEntries, filterOptions);
88
+ if (hasFilterOptions(filterOptions) && filterOptions.newestFirst === false) {
89
+ filteredRequests = filteredRequests.slice().reverse();
90
+ }
91
+ if (filterOptions.maxRequests && filteredRequests.length > filterOptions.maxRequests) {
92
+ filteredRequests = filteredRequests.slice(0, filterOptions.maxRequests);
93
+ }
94
+ return {
95
+ filteredRequests,
96
+ filteredCount: filteredRequests.length,
97
+ totalCount
98
+ };
99
+ }
100
+ function displayFilterSummary(response, filterOptions, filteredCount, totalCount) {
101
+ if (!hasFilterOptions(filterOptions)) {
102
+ return;
103
+ }
104
+ response.addResult(`Filter Summary: ${filteredCount}/${totalCount} requests match criteria`);
105
+ if (filterOptions.urlPatterns?.length) {
106
+ response.addResult(` URL patterns: ${filterOptions.urlPatterns.join(", ")}`);
107
+ }
108
+ if (filterOptions.excludeUrlPatterns?.length) {
109
+ response.addResult(` Exclude URL patterns: ${filterOptions.excludeUrlPatterns.join(", ")}`);
110
+ }
111
+ if (filterOptions.statusRanges?.length) {
112
+ response.addResult(` Status ranges: ${filterOptions.statusRanges.map((r) => `${r.min}-${r.max}`).join(", ")}`);
113
+ }
114
+ if (filterOptions.methods?.length) {
115
+ response.addResult(` Methods: ${filterOptions.methods.join(", ")}`);
116
+ }
117
+ if (filterOptions.maxRequests && filterOptions.maxRequests !== 20) {
118
+ response.addResult(` maxRequests: ${filterOptions.maxRequests}`);
119
+ }
120
+ response.addResult("");
121
+ }
122
+ function displayResults(response, filteredRequests, totalCount) {
123
+ for (const [req, res] of filteredRequests) {
124
+ response.addResult(renderRequest(req, res));
125
+ }
126
+ if (filteredRequests.length === 0 && totalCount > 0) {
127
+ response.addResult("No requests match the specified filter criteria.");
128
+ }
129
+ }
39
130
  function renderRequest(request, response) {
40
131
  const result = [];
41
132
  result.push(`[${request.method().toUpperCase()}] ${request.url()}`);
package/lib/tools/pdf.js CHANGED
@@ -19,7 +19,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/pdf.ts
21
21
  import { z } from "zod";
22
- import { formatObject } from "../javascript.js";
22
+ import { formatObject } from "../utils/codegen.js";
23
23
  import { defineTabTool } from "./tool.js";
24
24
  var pdfSchema = z.object({
25
25
  filename: z.string().optional().describe("File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.")
@@ -19,8 +19,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/screenshot.ts
21
21
  import { z } from "zod";
22
- import { formatObject } from "../javascript.js";
23
22
  import { expectationSchema } from "../schemas/expectation.js";
23
+ import { formatObject } from "../utils/codegen.js";
24
24
  import { defineTabTool } from "./tool.js";
25
25
  import { generateLocator } from "./utils.js";
26
26
  var screenshotSchema = z.object({
@@ -19,8 +19,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/snapshot.ts
21
21
  import { z } from "zod";
22
- import { formatObject } from "../javascript.js";
23
22
  import { expectationSchema } from "../schemas/expectation.js";
23
+ import { formatObject } from "../utils/codegen.js";
24
24
  import { defineTabTool, defineTool } from "./tool.js";
25
25
  import { generateLocator } from "./utils.js";
26
26
  var snapshot = defineTool({
@@ -18,10 +18,9 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/tools/utils.ts
21
- import debug from "debug";
22
21
  import { asLocator } from "playwright-core/lib/utils";
23
22
  import { TIMEOUTS } from "../config/constants.js";
24
- var toolsDebug = debug("pw:mcp:tools");
23
+ import { toolsUtilsDebug } from "../utils/log.js";
25
24
  async function waitForCompletion(tab, callback) {
26
25
  const requests = new Set;
27
26
  let frameNavigated = false;
@@ -48,19 +47,19 @@ async function waitForCompletion(tab, callback) {
48
47
  await tab.waitForLoadState("networkidle", {
49
48
  timeout: getNavigationConfig().networkIdleTimeout
50
49
  }).catch((error) => {
51
- toolsDebug("Network idle timeout reached:", error);
50
+ toolsUtilsDebug("Network idle timeout reached:", error);
52
51
  });
53
52
  navigationCompleted = true;
54
53
  if (!requests.size) {
55
54
  waitCallback();
56
55
  }
57
56
  } catch (error) {
58
- toolsDebug("Load state waiting failed, continuing:", error);
57
+ toolsUtilsDebug("Load state waiting failed, continuing:", error);
59
58
  navigationCompleted = true;
60
59
  waitCallback();
61
60
  }
62
61
  })().catch((error) => {
63
- toolsDebug("Navigation handling failed:", error);
62
+ toolsUtilsDebug("Navigation handling failed:", error);
64
63
  navigationCompleted = true;
65
64
  waitCallback();
66
65
  });
@@ -92,7 +91,7 @@ async function waitForCompletion(tab, callback) {
92
91
  try {
93
92
  await tab.page.evaluate(() => document.readyState);
94
93
  } catch (error) {
95
- toolsDebug("Page readyState check failed (context may be destroyed):", error);
94
+ toolsUtilsDebug("Page readyState check failed (context may be destroyed):", error);
96
95
  }
97
96
  } else {
98
97
  await tab.waitForTimeout(getNavigationConfig().defaultWait);
@@ -107,7 +106,7 @@ async function generateLocator(locator) {
107
106
  const { resolvedSelector } = await locator._resolveSelector();
108
107
  return asLocator("javascript", resolvedSelector);
109
108
  } catch (error) {
110
- toolsDebug("Locator generation failed:", error);
109
+ toolsUtilsDebug("Locator generation failed:", error);
111
110
  throw new Error("Ref not found, likely because element was removed. Use browser_snapshot to see what elements are currently on the page.");
112
111
  }
113
112
  }
@@ -17,7 +17,7 @@ var __toESM = (mod, isNodeMode, target) => {
17
17
  };
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
- // src/javascript.ts
20
+ // src/utils/codegen.ts
21
21
  function escapeWithQuotes(text, char = "'") {
22
22
  const stringified = JSON.stringify(text);
23
23
  const escapedText = extractEscapedContent(stringified);
@@ -18,8 +18,7 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/utils/common-formatters.ts
21
- import debug from "debug";
22
- var formattersDebug = debug("pw:mcp:formatters");
21
+ import { commonFormattersDebug } from "./log.js";
23
22
  function formatPerformanceMetric(name, value, unit, threshold) {
24
23
  const icon = threshold && value > threshold ? "⚠️" : "✅";
25
24
  const thresholdText = threshold ? ` (threshold: ${threshold}${unit})` : "";
@@ -161,7 +160,7 @@ function createDiagnosticErrorInfo(error, operation = "Unknown operation", compo
161
160
  component
162
161
  };
163
162
  }
164
- function handleResourceDisposalError(error, resourceType, logger = formattersDebug) {
163
+ function handleResourceDisposalError(error, resourceType, logger = commonFormattersDebug) {
165
164
  logger(`${resourceType} disposal failed: ${getErrorMessage(error)}`);
166
165
  }
167
166
  function handleFrameAccessError(error, frameInfo) {
@@ -18,9 +18,8 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/utils/error-handler-middleware.ts
21
- import debug from "debug";
22
21
  import { getErrorMessage } from "./common-formatters.js";
23
- var errorHandlerDebug = debug("pw:mcp:error-handler");
22
+ import { errorHandlerDebug } from "./log.js";
24
23
  async function withErrorHandling(operation, context) {
25
24
  try {
26
25
  const result = await operation();
@@ -17,7 +17,7 @@ var __toESM = (mod, isNodeMode, target) => {
17
17
  };
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
- // src/utils.ts
20
+ // src/utils/guid.ts
21
21
  import { createHash as cryptoCreateHash } from "node:crypto";
22
22
  function createHash(data) {
23
23
  return cryptoCreateHash("sha256").update(data).digest("hex").slice(0, 7);
@@ -43,6 +43,10 @@ import {
43
43
  handleResourceDisposalError
44
44
  } from "./common-formatters.js";
45
45
  import { createDisposableManager } from "./disposable-manager.js";
46
+ import {
47
+ createStatusCategoryFilter,
48
+ filterNetworkRequests
49
+ } from "./network-filter.js";
46
50
  import {
47
51
  addMouseOperationComment,
48
52
  addNavigationComment,
@@ -78,9 +82,11 @@ export {
78
82
  formatDiagnosticKeyValue,
79
83
  formatConfidence,
80
84
  filterTruthy,
85
+ filterNetworkRequests,
81
86
  executeToolOperation,
82
87
  deduplicateAndLimit,
83
88
  deduplicate,
89
+ createStatusCategoryFilter,
84
90
  createDisposableManager,
85
91
  applyCommonExpectations,
86
92
  addToolErrorContext,
@@ -0,0 +1,90 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils/log.ts
21
+ import debug from "debug";
22
+ var elementDiscoveryDebug = debug("pw:mcp:diagnostics:element-discovery");
23
+ var frameReferenceDebug = debug("pw:mcp:diagnostics:frame-reference");
24
+ var resourceDebug = debug("pw:mcp:diagnostics:resource");
25
+ var smartConfigDebug = debug("pw:mcp:diagnostics:smart-config");
26
+ var smartHandleDebug = debug("pw:mcp:diagnostics:smart-handle");
27
+ var commonFormattersDebug = debug("pw:mcp:utils:common-formatters");
28
+ var browserContextDebug = debug("pw:mcp:browser-context");
29
+ var browserContextFactoryDebug = debug("pw:mcp:browser-context-factory");
30
+ var browserServerBackendDebug = debug("pw:mcp:browser-server-backend");
31
+ var browserDebug = debug("pw:mcp:browser");
32
+ var testDebug = debug("pw:mcp:test");
33
+ var contextDebug = debug("pw:mcp:context");
34
+ var mcpServerDebug = debug("pw:mcp:server");
35
+ var mcpTransportDebug = debug("pw:mcp:transport");
36
+ var extensionContextDebug = debug("pw:mcp:extension:context");
37
+ var extensionContextFactoryDebug = debug("pw:mcp:extension:context-factory");
38
+ var cdpRelayDebug = debug("pw:mcp:extension:cdp-relay");
39
+ var batchExecutorDebug = debug("pw:mcp:batch:executor");
40
+ var loopDebug = debug("pw:mcp:loop");
41
+ var historyDebug = debug("pw:mcp:loop:history");
42
+ var toolDebug = debug("pw:mcp:loop:tool");
43
+ var toolsUtilsDebug = debug("pw:mcp:tools:utils");
44
+ var diagnoseConfigHandlerDebug = debug("pw:mcp:tools:diagnose:config-handler");
45
+ var tabDebug = debug("pw:mcp:tab");
46
+ var programDebug = debug("pw:mcp:program");
47
+ var responseDebug = debug("pw:mcp:response");
48
+ var errorHandlerDebug = debug("pw:mcp:error-handler");
49
+ var testserverDebug = debug("pw:mcp:testserver");
50
+ var snapshotDebug = debug("pw:mcp:tab:snapshot");
51
+ var errorEnrichmentDebug = debug("pw:mcp:diagnostics:error-enrichment");
52
+ var requestDebug = debug("pw:mcp:request");
53
+ var errorsDebug = debug("pw:mcp:errors");
54
+ function logUnhandledError(error) {
55
+ errorsDebug(error);
56
+ }
57
+ export {
58
+ toolsUtilsDebug,
59
+ toolDebug,
60
+ testserverDebug,
61
+ testDebug,
62
+ tabDebug,
63
+ snapshotDebug,
64
+ smartHandleDebug,
65
+ smartConfigDebug,
66
+ responseDebug,
67
+ resourceDebug,
68
+ requestDebug,
69
+ programDebug,
70
+ mcpTransportDebug,
71
+ mcpServerDebug,
72
+ loopDebug,
73
+ logUnhandledError,
74
+ historyDebug,
75
+ frameReferenceDebug,
76
+ extensionContextFactoryDebug,
77
+ extensionContextDebug,
78
+ errorHandlerDebug,
79
+ errorEnrichmentDebug,
80
+ elementDiscoveryDebug,
81
+ diagnoseConfigHandlerDebug,
82
+ contextDebug,
83
+ commonFormattersDebug,
84
+ cdpRelayDebug,
85
+ browserServerBackendDebug,
86
+ browserDebug,
87
+ browserContextFactoryDebug,
88
+ browserContextDebug,
89
+ batchExecutorDebug
90
+ };
@@ -0,0 +1,114 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils/network-filter.ts
21
+ function filterNetworkRequests(requests, options) {
22
+ if (!requests || requests.length === 0) {
23
+ return [];
24
+ }
25
+ const opts = {
26
+ maxRequests: 20,
27
+ newestFirst: true,
28
+ ...options
29
+ };
30
+ let filtered = [...requests];
31
+ filtered = applyUrlPatternFilters(filtered, opts);
32
+ if (opts.methods && opts.methods.length > 0) {
33
+ filtered = filtered.filter((request) => {
34
+ const method = request.method.toUpperCase();
35
+ return opts.methods?.some((m) => m.toUpperCase() === method) ?? false;
36
+ });
37
+ }
38
+ filtered = applyStatusRangeFilters(filtered, opts);
39
+ if (filtered.length > 1) {
40
+ filtered = sortRequestsByTimestamp(filtered, opts.newestFirst ?? true);
41
+ }
42
+ if (opts.maxRequests && opts.maxRequests > 0) {
43
+ filtered = filtered.slice(0, opts.maxRequests);
44
+ }
45
+ return filtered;
46
+ }
47
+ function applyUrlPatternFilters(requests, options) {
48
+ let filtered = requests;
49
+ if (options.urlPatterns && options.urlPatterns.length > 0) {
50
+ filtered = filtered.filter((request) => {
51
+ return options.urlPatterns?.some((pattern) => matchesUrlPattern(request.url, pattern)) ?? false;
52
+ });
53
+ }
54
+ if (options.excludeUrlPatterns && options.excludeUrlPatterns.length > 0) {
55
+ filtered = filtered.filter((request) => {
56
+ return !options.excludeUrlPatterns?.some((pattern) => matchesUrlPattern(request.url, pattern));
57
+ });
58
+ }
59
+ return filtered;
60
+ }
61
+ function applyStatusRangeFilters(requests, options) {
62
+ if (!options.statusRanges || options.statusRanges.length === 0) {
63
+ return requests;
64
+ }
65
+ return requests.filter((request) => {
66
+ const status = request.status;
67
+ if (status === undefined) {
68
+ return true;
69
+ }
70
+ return options.statusRanges?.some((range) => {
71
+ return status >= range.min && status <= range.max;
72
+ }) ?? false;
73
+ });
74
+ }
75
+ function sortRequestsByTimestamp(requests, newestFirst) {
76
+ const sorted = [...requests].sort((a, b) => {
77
+ const timestampA = a.timestamp;
78
+ const timestampB = b.timestamp;
79
+ if (newestFirst) {
80
+ return timestampB - timestampA;
81
+ }
82
+ return timestampA - timestampB;
83
+ });
84
+ return sorted;
85
+ }
86
+ function matchesUrlPattern(url, pattern) {
87
+ if (!(pattern && url)) {
88
+ return false;
89
+ }
90
+ try {
91
+ const regex = new RegExp(pattern, "i");
92
+ return regex.test(url);
93
+ } catch {
94
+ return url.toLowerCase().includes(pattern.toLowerCase());
95
+ }
96
+ }
97
+ function createStatusCategoryFilter(category) {
98
+ switch (category) {
99
+ case "success":
100
+ return { statusRanges: [{ min: 200, max: 299 }] };
101
+ case "redirect":
102
+ return { statusRanges: [{ min: 300, max: 399 }] };
103
+ case "client-error":
104
+ return { statusRanges: [{ min: 400, max: 499 }] };
105
+ case "server-error":
106
+ return { statusRanges: [{ min: 500, max: 599 }] };
107
+ default:
108
+ return {};
109
+ }
110
+ }
111
+ export {
112
+ filterNetworkRequests,
113
+ createStatusCategoryFilter
114
+ };
@@ -17,12 +17,12 @@ var __toESM = (mod, isNodeMode, target) => {
17
17
  };
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
- // src/package.ts
20
+ // src/utils/package.ts
21
21
  import fs from "node:fs";
22
22
  import path from "node:path";
23
23
  import url from "node:url";
24
24
  var __filename2 = url.fileURLToPath(import.meta.url);
25
- var packageJSON = JSON.parse(fs.readFileSync(path.join(path.dirname(__filename2), "..", "package.json"), "utf8"));
25
+ var packageJSON = JSON.parse(fs.readFileSync(path.join(path.dirname(__filename2), "..", "..", "package.json"), "utf8"));
26
26
  export {
27
27
  packageJSON
28
28
  };
@@ -22,7 +22,7 @@ import { randomBytes } from "node:crypto";
22
22
  import { appendFileSync, existsSync, mkdirSync } from "node:fs";
23
23
  import { dirname, join } from "node:path";
24
24
  import { fileURLToPath } from "node:url";
25
- import { requestDebug } from "../log.js";
25
+ import { requestDebug } from "./log.js";
26
26
  var __filename2 = fileURLToPath(import.meta.url);
27
27
  var __dirname2 = dirname(__filename2);
28
28
  var PROJECT_ROOT = join(__dirname2, "..", "..");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tontoko/fast-playwright-mcp",
3
- "version": "0.0.8",
3
+ "version": "0.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -10,12 +10,12 @@
10
10
  "type": "git",
11
11
  "url": "https://github.com/tontoko/fast-playwright-mcp"
12
12
  },
13
- "homepage": "https://playwright.dev",
13
+ "homepage": "https://github.com/tontoko/fast-playwright-mcp",
14
14
  "engines": {
15
15
  "node": ">=18"
16
16
  },
17
17
  "author": {
18
- "name": "Microsoft Corporation"
18
+ "name": "Tomohiko Hiraki"
19
19
  },
20
20
  "license": "Apache-2.0",
21
21
  "scripts": {