@tontoko/fast-playwright-mcp 0.0.7 → 0.0.9

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 (45) hide show
  1. package/README.md +273 -112
  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/base-tool-handler.js +1 -1
  28. package/lib/tools/diagnose/diagnose-config-handler.js +2 -3
  29. package/lib/tools/evaluate.js +2 -2
  30. package/lib/tools/keyboard.js +2 -2
  31. package/lib/tools/network.js +97 -6
  32. package/lib/tools/pdf.js +1 -1
  33. package/lib/tools/screenshot.js +2 -2
  34. package/lib/tools/snapshot.js +4 -4
  35. package/lib/tools/utils.js +6 -7
  36. package/lib/{javascript.js → utils/codegen.js} +1 -1
  37. package/lib/utils/common-formatters.js +2 -3
  38. package/lib/utils/error-handler-middleware.js +1 -2
  39. package/lib/{utils.js → utils/guid.js} +1 -1
  40. package/lib/utils/index.js +6 -0
  41. package/lib/utils/log.js +90 -0
  42. package/lib/utils/network-filter.js +114 -0
  43. package/lib/{package.js → utils/package.js} +2 -2
  44. package/lib/utils/request-logger.js +1 -1
  45. package/package.json +2 -2
package/README.md CHANGED
@@ -133,6 +133,29 @@ Go to `Advanced settings` -> `Extensions` -> `Add custom extension`. Name to you
133
133
  Go to `Program` in the right sidebar -> `Install` -> `Edit mcp.json`. Use the standard config above.
134
134
  </details>
135
135
 
136
+ <details>
137
+ <summary>opencode</summary>
138
+
139
+ Follow the MCP Servers [documentation](https://opencode.ai/docs/mcp-servers/). For example in `~/.config/opencode/opencode.json`:
140
+
141
+ ```json
142
+ {
143
+ "$schema": "https://opencode.ai/config.json",
144
+ "mcp": {
145
+ "playwright": {
146
+ "type": "local",
147
+ "command": [
148
+ "npx",
149
+ "@tontoko/fast-playwright-mcp"
150
+ ],
151
+ "enabled": true
152
+ }
153
+ }
154
+ }
155
+
156
+ ```
157
+ </details>
158
+
136
159
  <details>
137
160
  <summary>Qodo Gen</summary>
138
161
 
@@ -191,6 +214,9 @@ Playwright MCP server supports following arguments. They can be provided in the
191
214
  --config <path> path to the configuration file.
192
215
  --device <device> device to emulate, for example: "iPhone 15"
193
216
  --executable-path <path> path to the browser executable.
217
+ --extension Connect to a running browser instance
218
+ (Edge/Chrome only). Requires the "Playwright MCP
219
+ Bridge" browser extension to be installed.
194
220
  --headless run browser in headless mode, headed by default
195
221
  --host <host> host to bind server to. Default is localhost. Use
196
222
  0.0.0.0 to bind to all interfaces.
@@ -224,7 +250,7 @@ Playwright MCP server supports following arguments. They can be provided in the
224
250
 
225
251
  ### User profile
226
252
 
227
- You can run Playwright MCP with persistent profile like a regular browser (default), or in the isolated contexts for the testing sessions.
253
+ You can run Playwright MCP with persistent profile like a regular browser (default), in isolated contexts for testing sessions, or connect to your existing browser using the browser extension.
228
254
 
229
255
  **Persistent profile**
230
256
 
@@ -264,6 +290,10 @@ state [here](https://playwright.dev/docs/auth).
264
290
  }
265
291
  ```
266
292
 
293
+ **Browser Extension**
294
+
295
+ The Playwright MCP Chrome Extension allows you to connect to existing browser tabs and leverage your logged-in sessions and browser state. See [extension/README.md](extension/README.md) for installation and setup instructions.
296
+
267
297
  ### Configuration file
268
298
 
269
299
  The Playwright MCP server can be configured using a JSON configuration file. You can specify the configuration file
@@ -581,8 +611,14 @@ http.createServer(async (req, res) => {
581
611
 
582
612
  - **browser_network_requests**
583
613
  - Title: List network requests
584
- - Description: Returns all network requests since loading the page
585
- - Parameters: None
614
+ - 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.
615
+ - Parameters:
616
+ - `urlPatterns` (array, optional): URL patterns to include (supports regex)
617
+ - `excludeUrlPatterns` (array, optional): URL patterns to exclude (supports regex)
618
+ - `statusRanges` (array, optional): Status code ranges to include
619
+ - `methods` (array, optional): HTTP methods to filter by
620
+ - `maxRequests` (number, optional): Maximum number of results to return (default: 20)
621
+ - `newestFirst` (boolean, optional): Sort order - true for newest first (default: true)
586
622
  - Read-only: **true**
587
623
 
588
624
  <!-- NOTE: This has been generated via update-readme.js -->
@@ -792,19 +828,27 @@ All browser tools support an optional `expectation` parameter that controls what
792
828
 
793
829
  #### Basic Usage
794
830
 
795
- ```javascript
831
+ ```json
796
832
  // Standard call - includes all information (snapshot, console, tabs, etc.)
797
- await browser_navigate({ url: 'https://example.com' });
833
+ {
834
+ "name": "browser_navigate",
835
+ "arguments": {
836
+ "url": "https://example.com"
837
+ }
838
+ }
798
839
 
799
840
  // Optimized call - only includes essential information
800
- await browser_navigate({
801
- url: 'https://example.com',
802
- expectation: {
803
- includeSnapshot: false, // Skip page snapshot
804
- includeConsole: false, // Skip console messages
805
- includeTabs: false // Skip tab information
841
+ {
842
+ "name": "browser_navigate",
843
+ "arguments": {
844
+ "url": "https://example.com",
845
+ "expectation": {
846
+ "includeSnapshot": false,
847
+ "includeConsole": false,
848
+ "includeTabs": false
849
+ }
806
850
  }
807
- });
851
+ }
808
852
  ```
809
853
 
810
854
  #### Expectation Options
@@ -817,36 +861,42 @@ await browser_navigate({
817
861
 
818
862
  #### Advanced Snapshot Options
819
863
 
820
- ```javascript
821
- await browser_click({
822
- element: 'Login button',
823
- ref: '#login-btn',
824
- expectation: {
825
- includeSnapshot: true,
826
- snapshotOptions: {
827
- selector: '.dashboard', // Only capture dashboard area
828
- maxLength: 1000, // Limit snapshot length
829
- format: 'text' // Use text format instead of aria
864
+ ```json
865
+ {
866
+ "name": "browser_click",
867
+ "arguments": {
868
+ "element": "Login button",
869
+ "ref": "#login-btn",
870
+ "expectation": {
871
+ "includeSnapshot": true,
872
+ "snapshotOptions": {
873
+ "selector": ".dashboard",
874
+ "maxLength": 1000,
875
+ "format": "text"
876
+ }
830
877
  }
831
878
  }
832
- });
879
+ }
833
880
  ```
834
881
 
835
882
  #### Console Filtering Options
836
883
 
837
- ```javascript
838
- await browser_navigate({
839
- url: 'https://example.com',
840
- expectation: {
841
- includeConsole: true,
842
- consoleOptions: {
843
- levels: ['error', 'warn'], // Only errors and warnings
844
- maxMessages: 5, // Limit to 5 messages
845
- patterns: ['^Error:'], // Filter by regex patterns
846
- removeDuplicates: true // Remove duplicate messages
884
+ ```json
885
+ {
886
+ "name": "browser_navigate",
887
+ "arguments": {
888
+ "url": "https://example.com",
889
+ "expectation": {
890
+ "includeConsole": true,
891
+ "consoleOptions": {
892
+ "levels": ["error", "warn"],
893
+ "maxMessages": 5,
894
+ "patterns": ["^Error:"],
895
+ "removeDuplicates": true
896
+ }
847
897
  }
848
898
  }
849
- });
899
+ }
850
900
  ```
851
901
 
852
902
  ### Batch Execution
@@ -855,63 +905,69 @@ Execute multiple browser actions in a single request with optimized response han
855
905
 
856
906
  #### Basic Batch Execution
857
907
 
858
- ```javascript
859
- await browser_batch_execute({
860
- steps: [
861
- {
862
- tool: 'browser_navigate',
863
- arguments: { url: 'https://example.com/login' }
864
- },
865
- {
866
- tool: 'browser_type',
867
- arguments: {
868
- element: 'username field',
869
- ref: '#username',
870
- text: 'testuser'
871
- }
872
- },
873
- {
874
- tool: 'browser_type',
875
- arguments: {
876
- element: 'password field',
877
- ref: '#password',
878
- text: 'password'
908
+ ```json
909
+ {
910
+ "name": "browser_batch_execute",
911
+ "arguments": {
912
+ "steps": [
913
+ {
914
+ "tool": "browser_navigate",
915
+ "arguments": { "url": "https://example.com/login" }
916
+ },
917
+ {
918
+ "tool": "browser_type",
919
+ "arguments": {
920
+ "element": "username field",
921
+ "ref": "#username",
922
+ "text": "testuser"
923
+ }
924
+ },
925
+ {
926
+ "tool": "browser_type",
927
+ "arguments": {
928
+ "element": "password field",
929
+ "ref": "#password",
930
+ "text": "password"
931
+ }
932
+ },
933
+ {
934
+ "tool": "browser_click",
935
+ "arguments": { "element": "login button", "ref": "#login-btn" }
879
936
  }
880
- },
881
- {
882
- tool: 'browser_click',
883
- arguments: { element: 'login button', ref: '#login-btn' }
884
- }
885
- ]
886
- });
937
+ ]
938
+ }
939
+ }
887
940
  ```
888
941
 
889
942
  #### Advanced Batch Configuration
890
943
 
891
- ```javascript
892
- await browser_batch_execute({
893
- steps: [
894
- {
895
- tool: 'browser_navigate',
896
- arguments: { url: 'https://example.com' },
897
- expectation: { includeSnapshot: false }, // Step-specific optimization
898
- continueOnError: true // Continue if this step fails
899
- },
900
- {
901
- tool: 'browser_click',
902
- arguments: { element: 'button', ref: '#submit' },
903
- expectation: {
904
- includeSnapshot: true,
905
- snapshotOptions: { selector: '.result-area' }
944
+ ```json
945
+ {
946
+ "name": "browser_batch_execute",
947
+ "arguments": {
948
+ "steps": [
949
+ {
950
+ "tool": "browser_navigate",
951
+ "arguments": { "url": "https://example.com" },
952
+ "expectation": { "includeSnapshot": false },
953
+ "continueOnError": true
954
+ },
955
+ {
956
+ "tool": "browser_click",
957
+ "arguments": { "element": "button", "ref": "#submit" },
958
+ "expectation": {
959
+ "includeSnapshot": true,
960
+ "snapshotOptions": { "selector": ".result-area" }
961
+ }
906
962
  }
963
+ ],
964
+ "stopOnFirstError": false,
965
+ "globalExpectation": {
966
+ "includeConsole": false,
967
+ "includeTabs": false
907
968
  }
908
- ],
909
- stopOnFirstError: false, // Continue executing remaining steps
910
- globalExpectation: { // Default for all steps
911
- includeConsole: false,
912
- includeTabs: false
913
969
  }
914
- });
970
+ }
915
971
  ```
916
972
 
917
973
  #### Error Handling Options
@@ -941,22 +997,24 @@ Each tool has optimized defaults based on typical usage patterns:
941
997
 
942
998
  The Fast Server includes automatic diff detection to efficiently track changes between consecutive tool executions:
943
999
 
944
- ```javascript
945
- // Enable diff detection for any tool
946
- await browser_click({
947
- element: 'Load more button',
948
- ref: '#load-more',
949
- expectation: {
950
- includeSnapshot: true,
951
- diffOptions: {
952
- enabled: true,
953
- threshold: 0.1, // Show diff if >10% changed
954
- format: 'unified', // or 'split', 'minimal'
955
- maxDiffLines: 50, // Limit diff output size
956
- context: 3 // Lines of context around changes
1000
+ ```json
1001
+ {
1002
+ "name": "browser_click",
1003
+ "arguments": {
1004
+ "element": "Load more button",
1005
+ "ref": "#load-more",
1006
+ "expectation": {
1007
+ "includeSnapshot": true,
1008
+ "diffOptions": {
1009
+ "enabled": true,
1010
+ "threshold": 0.1,
1011
+ "format": "unified",
1012
+ "maxDiffLines": 50,
1013
+ "context": 3
1014
+ }
957
1015
  }
958
1016
  }
959
- });
1017
+ }
960
1018
  ```
961
1019
 
962
1020
  #### Diff Detection Benefits
@@ -973,23 +1031,25 @@ await browser_click({
973
1031
  3. **Form interactions**: Track changes as users fill forms
974
1032
  4. **Selective monitoring**: Use with CSS selectors to track specific areas
975
1033
 
976
- ```javascript
977
- // Example: Track only search results changes
978
- await browser_type({
979
- element: 'Search input',
980
- ref: '#search',
981
- text: 'playwright',
982
- expectation: {
983
- includeSnapshot: true,
984
- snapshotOptions: {
985
- selector: '#search-results' // Only monitor results area
986
- },
987
- diffOptions: {
988
- enabled: true,
989
- format: 'minimal' // Just show what changed
1034
+ ```json
1035
+ {
1036
+ "name": "browser_type",
1037
+ "arguments": {
1038
+ "element": "Search input",
1039
+ "ref": "#search",
1040
+ "text": "playwright",
1041
+ "expectation": {
1042
+ "includeSnapshot": true,
1043
+ "snapshotOptions": {
1044
+ "selector": "#search-results"
1045
+ },
1046
+ "diffOptions": {
1047
+ "enabled": true,
1048
+ "format": "minimal"
1049
+ }
990
1050
  }
991
1051
  }
992
- });
1052
+ }
993
1053
  ```
994
1054
 
995
1055
  ### Best Practices
@@ -1037,6 +1097,107 @@ All tools automatically provide enhanced error messages with:
1037
1097
  - Context-aware troubleshooting tips
1038
1098
  - Performance insights
1039
1099
 
1100
+ ### Network Request Filtering
1101
+
1102
+ The `browser_network_requests` tool provides advanced filtering capabilities to reduce token usage by up to 80-95% when working with network logs.
1103
+
1104
+ #### Basic Usage Examples
1105
+
1106
+ ```json
1107
+ // Filter API requests only
1108
+ {
1109
+ "name": "browser_network_requests",
1110
+ "arguments": {
1111
+ "urlPatterns": ["api/", "/graphql"]
1112
+ }
1113
+ }
1114
+
1115
+ // Exclude analytics and tracking
1116
+ {
1117
+ "name": "browser_network_requests",
1118
+ "arguments": {
1119
+ "excludeUrlPatterns": ["analytics", "tracking", "ads"]
1120
+ }
1121
+ }
1122
+
1123
+ // Success responses only
1124
+ {
1125
+ "name": "browser_network_requests",
1126
+ "arguments": {
1127
+ "statusRanges": [{ "min": 200, "max": 299 }]
1128
+ }
1129
+ }
1130
+
1131
+ // Recent errors only
1132
+ {
1133
+ "name": "browser_network_requests",
1134
+ "arguments": {
1135
+ "statusRanges": [{ "min": 400, "max": 599 }],
1136
+ "maxRequests": 5,
1137
+ "newestFirst": true
1138
+ }
1139
+ }
1140
+ ```
1141
+
1142
+ #### Advanced Filtering
1143
+
1144
+ ```json
1145
+ // Complex filtering for API debugging
1146
+ {
1147
+ "name": "browser_network_requests",
1148
+ "arguments": {
1149
+ "urlPatterns": ["/api/users", "/api/posts"],
1150
+ "excludeUrlPatterns": ["/api/health"],
1151
+ "methods": ["GET", "POST"],
1152
+ "statusRanges": [
1153
+ { "min": 200, "max": 299 },
1154
+ { "min": 400, "max": 499 }
1155
+ ],
1156
+ "maxRequests": 10,
1157
+ "newestFirst": true
1158
+ }
1159
+ }
1160
+
1161
+ // Monitor only failed requests
1162
+ {
1163
+ "name": "browser_network_requests",
1164
+ "arguments": {
1165
+ "statusRanges": [
1166
+ { "min": 400, "max": 499 },
1167
+ { "min": 500, "max": 599 }
1168
+ ],
1169
+ "maxRequests": 3
1170
+ }
1171
+ }
1172
+ ```
1173
+
1174
+ #### Regex Pattern Support
1175
+
1176
+ ```json
1177
+ {
1178
+ "name": "browser_network_requests",
1179
+ "arguments": {
1180
+ "urlPatterns": ["^/api/v[0-9]+/users$"],
1181
+ "excludeUrlPatterns": ["\\.(css|js|png)$"]
1182
+ }
1183
+ }
1184
+ ```
1185
+
1186
+ #### Token Optimization Benefits
1187
+
1188
+ - **Massive reduction**: 80-95% fewer tokens for large applications
1189
+ - **Focused debugging**: See only relevant network activity
1190
+ - **Performance monitoring**: Track specific endpoints or error patterns
1191
+ - **Cost savings**: Lower API costs due to reduced token usage
1192
+
1193
+ #### When to Use Network Filtering
1194
+
1195
+ 1. **API debugging**: Focus on specific endpoints and methods
1196
+ 2. **Error monitoring**: Track only failed requests
1197
+ 3. **Performance analysis**: Monitor slow or problematic endpoints
1198
+ 4. **Large applications**: Reduce overwhelming network logs
1199
+ 5. **Token management**: Stay within LLM context limits
1200
+
1040
1201
  ### Migration Guide
1041
1202
 
1042
1203
  Existing code continues to work without changes. To optimize:
@@ -19,11 +19,10 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/batch/batch-executor.ts
21
21
  import { randomBytes } from "node:crypto";
22
- import debug from "debug";
23
22
  import { Response } from "../response.js";
24
23
  import { mergeExpectations } from "../schemas/expectation.js";
25
24
  import { getErrorMessage } from "../utils/common-formatters.js";
26
- var batchDebug = debug("pw:mcp:batch");
25
+ import { batchExecutorDebug } from "../utils/log.js";
27
26
 
28
27
  class BatchExecutor {
29
28
  toolRegistry;
@@ -66,7 +65,7 @@ class BatchExecutor {
66
65
  batchId: this.generateBatchId(),
67
66
  startTime
68
67
  };
69
- batchDebug(`Starting batch execution ${this.currentBatchContext.batchId} with ${options.steps.length} steps`);
68
+ batchExecutorDebug(`Starting batch execution ${this.currentBatchContext.batchId} with ${options.steps.length} steps`);
70
69
  this.validateAllSteps(options.steps);
71
70
  const executeSequentially = async (index) => {
72
71
  if (index >= options.steps.length) {
@@ -132,10 +131,10 @@ class BatchExecutor {
132
131
  this.context.batchContext = batchContext;
133
132
  try {
134
133
  const response = new Response(this.context, step.tool, argsWithExpectation, mergedExpectation);
135
- batchDebug(`Executing batch step: ${step.tool}`);
134
+ batchExecutorDebug(`Executing batch step: ${step.tool}`);
136
135
  await tool.handle(this.context, argsWithExpectation, response);
137
136
  await response.finish();
138
- batchDebug(`Batch step ${step.tool} completed`);
137
+ batchExecutorDebug(`Batch step ${step.tool} completed`);
139
138
  return response.serialize();
140
139
  } finally {
141
140
  this.context.batchContext = previousBatchContext;
@@ -21,7 +21,6 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
21
21
  import { promises as fsPromises } from "node:fs";
22
22
  import { createServer } from "node:net";
23
23
  import { join as pathJoin } from "node:path";
24
- import debug from "debug";
25
24
  import {
26
25
  chromium,
27
26
  firefox,
@@ -29,9 +28,8 @@ import {
29
28
  } from "playwright";
30
29
  import { registryDirectory } from "playwright-core/lib/server/registry/index";
31
30
  import { outputFile } from "./config.js";
32
- import { logUnhandledError, testDebug } from "./log.js";
33
- import { createHash } from "./utils.js";
34
- var browserDebug = debug("pw:mcp:browser");
31
+ import { createHash } from "./utils/guid.js";
32
+ import { browserDebug, logUnhandledError, testDebug } from "./utils/log.js";
35
33
  function getBrowserType(browserName) {
36
34
  switch (browserName) {
37
35
  case "chromium":
@@ -19,16 +19,14 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/browser-server-backend.ts
21
21
  import { fileURLToPath } from "node:url";
22
- import debug from "debug";
23
22
  import { z } from "zod";
24
23
  import { Context } from "./context.js";
25
- import { logUnhandledError } from "./log.js";
26
- import { packageJSON } from "./package.js";
27
24
  import { Response } from "./response.js";
28
25
  import { SessionLog } from "./session-log.js";
29
26
  import { defineTool } from "./tools/tool.js";
30
27
  import { filteredTools } from "./tools.js";
31
- var backendDebug = debug("pw:mcp:backend");
28
+ import { browserServerBackendDebug, logUnhandledError } from "./utils/log.js";
29
+ import { packageJSON } from "./utils/package.js";
32
30
 
33
31
  class BrowserServerBackend {
34
32
  name = "Playwright";
@@ -79,14 +77,14 @@ class BrowserServerBackend {
79
77
  throw new Error(`Tool not found: ${schema.name}`);
80
78
  }
81
79
  context.setRunningTool(true);
82
- backendDebug(`Executing tool: ${schema.name}`);
80
+ browserServerBackendDebug(`Executing tool: ${schema.name}`);
83
81
  try {
84
82
  await matchedTool.handle(context, parsedArguments, response);
85
83
  await response.finish();
86
84
  this._sessionLog?.logResponse(response);
87
- backendDebug(`Tool ${schema.name} completed successfully`);
85
+ browserServerBackendDebug(`Tool ${schema.name} completed successfully`);
88
86
  } catch (error) {
89
- backendDebug(`Error executing tool ${schema.name}:`, error);
87
+ browserServerBackendDebug(`Error executing tool ${schema.name}:`, error);
90
88
  response.addError(String(error));
91
89
  } finally {
92
90
  context.setRunningTool(false);
package/lib/config.js CHANGED
@@ -22,7 +22,7 @@ import { promises as fsPromises } from "node:fs";
22
22
  import { platform, tmpdir } from "node:os";
23
23
  import { join as pathJoin } from "node:path";
24
24
  import { devices } from "playwright";
25
- import { sanitizeForFilePath } from "./utils.js";
25
+ import { sanitizeForFilePath } from "./utils/guid.js";
26
26
  var defaultConfig = {
27
27
  browser: {
28
28
  browserName: "chromium",
package/lib/context.js CHANGED
@@ -18,13 +18,10 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/context.ts
21
- import debug from "debug";
22
21
  import { BatchExecutor } from "./batch/batch-executor.js";
23
22
  import { outputFile } from "./config.js";
24
- import { logUnhandledError } from "./log.js";
25
23
  import { Tab } from "./tab.js";
26
- var testDebug = debug("pw:mcp:test");
27
- var contextDebug = debug("pw:mcp:context");
24
+ import { contextDebug, logUnhandledError, testDebug } from "./utils/log.js";
28
25
 
29
26
  class Context {
30
27
  tools;
@@ -19,6 +19,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/diagnostics/common/error-enrichment-utils.ts
21
21
  import { deduplicateAndLimit } from "../../utils/array-utils.js";
22
+ import { errorEnrichmentDebug } from "../../utils/log.js";
22
23
  var errorPatterns = new Map([
23
24
  [
24
25
  /timeout/i,
@@ -101,11 +102,11 @@ function generateSuggestions(error, context) {
101
102
  }
102
103
  return deduplicateAndLimit(suggestions, 5);
103
104
  }
104
- async function safeDispose(resource, _resourceType, _operation) {
105
+ async function safeDispose(resource, resourceType, operation) {
105
106
  try {
106
107
  await resource.dispose();
107
108
  } catch (error) {
108
- console.warn(`Failed to dispose ${_resourceType} during ${_operation}:`, error);
109
+ errorEnrichmentDebug(`Failed to dispose ${resourceType} during ${operation}:`, error);
109
110
  }
110
111
  }
111
112
  async function safeDisposeAll(resources, resourceType, operation) {