chrome-devtools-mcp 1.1.1 → 1.2.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 (105) hide show
  1. package/README.md +12 -3
  2. package/build/src/DevtoolsUtils.js +57 -0
  3. package/build/src/HeapSnapshotManager.js +5 -0
  4. package/build/src/McpContext.js +28 -8
  5. package/build/src/McpPage.js +9 -9
  6. package/build/src/McpResponse.js +101 -53
  7. package/build/src/PageCollector.js +7 -7
  8. package/build/src/ServiceWorkerCollector.js +171 -0
  9. package/build/src/TextSnapshot.js +1 -1
  10. package/build/src/ToolHandler.js +10 -4
  11. package/build/src/WaitForHelper.js +2 -2
  12. package/build/src/bin/chrome-devtools-cli-options.js +22 -4
  13. package/build/src/bin/chrome-devtools-mcp-cli-options.js +19 -4
  14. package/build/src/bin/chrome-devtools-mcp-main.js +5 -5
  15. package/build/src/browser.js +8 -4
  16. package/build/src/daemon/client.js +7 -7
  17. package/build/src/daemon/daemon.js +12 -12
  18. package/build/src/daemon/utils.js +2 -2
  19. package/build/src/formatters/IssueFormatter.js +4 -4
  20. package/build/src/index.js +13 -1
  21. package/build/src/telemetry/ClearcutLogger.js +1 -1
  22. package/build/src/telemetry/WatchdogClient.js +4 -4
  23. package/build/src/telemetry/persistence.js +2 -2
  24. package/build/src/telemetry/watchdog/ClearcutSender.js +10 -10
  25. package/build/src/telemetry/watchdog/main.js +5 -5
  26. package/build/src/third_party/THIRD_PARTY_NOTICES +30 -0
  27. package/build/src/third_party/bundled-packages.json +2 -1
  28. package/build/src/third_party/devtools-formatter-worker.js +1 -0
  29. package/build/src/third_party/devtools-heap-snapshot-worker.js +107 -0
  30. package/build/src/third_party/index.js +5906 -4913
  31. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
  32. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
  33. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
  34. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
  35. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
  36. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
  37. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
  38. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
  39. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
  40. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
  41. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
  42. package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
  43. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
  44. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
  45. package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
  46. package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
  47. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
  48. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
  49. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
  50. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
  51. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
  52. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
  53. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
  54. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
  55. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
  56. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
  57. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
  58. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
  59. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
  60. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
  61. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
  62. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
  63. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
  64. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
  65. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
  66. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
  67. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
  68. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
  69. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
  70. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
  71. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
  72. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
  73. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
  74. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
  75. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
  76. package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
  77. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
  78. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
  79. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
  80. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
  81. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
  82. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
  83. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
  84. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
  85. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
  86. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
  87. package/build/src/tools/console.js +7 -0
  88. package/build/src/tools/emulation.js +1 -0
  89. package/build/src/tools/extensions.js +5 -2
  90. package/build/src/tools/input.js +11 -3
  91. package/build/src/tools/lighthouse.js +11 -6
  92. package/build/src/tools/memory.js +33 -10
  93. package/build/src/tools/network.js +2 -2
  94. package/build/src/tools/pages.js +13 -5
  95. package/build/src/tools/performance.js +8 -7
  96. package/build/src/tools/screencast.js +2 -1
  97. package/build/src/tools/screenshot.js +1 -1
  98. package/build/src/tools/script.js +1 -1
  99. package/build/src/tools/slim/tools.js +3 -0
  100. package/build/src/tools/snapshot.js +3 -2
  101. package/build/src/tools/thirdPartyDeveloper.js +12 -2
  102. package/build/src/tools/webmcp.js +2 -0
  103. package/build/src/trace-processing/parse.js +5 -5
  104. package/build/src/version.js +1 -1
  105. package/package.json +4 -3
@@ -0,0 +1 @@
1
+ # Email verification request failed because the accounts endpoint returned an empty list of accounts.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the accounts endpoint was not found (HTTP 404).
@@ -0,0 +1 @@
1
+ # Email verification request failed because the accounts endpoint returned an invalid Content-Type.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the accounts endpoint returned an invalid response.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the accounts endpoint did not respond.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the DNS fetch failed.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the DNS record is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the email verification well-known file was not found (HTTP 404).
@@ -0,0 +1 @@
1
+ # Email verification request failed because the email verification well-known file returned an invalid Content-Type.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the email verification well-known file returned an invalid response.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the email verification well-known file did not respond.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the email address is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the JWKS endpoint was not found (HTTP 404).
@@ -0,0 +1 @@
1
+ # Email verification request failed because the JWKS endpoint returned an invalid response.
@@ -0,0 +1 @@
1
+ # Email verification request failed because key binding signing failed.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the Relying Party origin is opaque.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the token endpoint was not found (HTTP 404).
@@ -0,0 +1 @@
1
+ # Email verification request failed because the token endpoint had an invalid Content-Type.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the token endpoint response was invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the token endpoint returned an invalid SD-JWT.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the token endpoint returned a malformed SD-JWT.
@@ -0,0 +1 @@
1
+ # Email verification request failed because there was no response from the token endpoint.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding audience claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding issued at claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding nonce claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding SD hash claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding type header is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding audience claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding confirmation claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding issued at claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding nonce claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding SD hash claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the key binding signature verification failed.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT email claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT email verified claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT holder key is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT issued at claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT issuer claim is invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT JWKS is missing keys.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT confirmation claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT email claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT issued at claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT issuer claim is missing.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT signature verification failed.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the SD-JWT signature header algorithm is unsupported.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the user is logged out.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the accounts endpoint in the well-known file is cross-origin.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the well-known file was not found (HTTP 404).
@@ -0,0 +1 @@
1
+ # Email verification request failed because the well-known file had an invalid Content-Type.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the well-known file response was invalid.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the issuance endpoint in the well-known file is cross-origin.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the well-known file list was empty.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the well-known file is missing the accounts endpoint.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the well-known file is missing the issuance endpoint.
@@ -0,0 +1 @@
1
+ # Email verification request failed because there was no response when fetching the well-known file.
@@ -0,0 +1 @@
1
+ # Email verification request failed because the well-known file specifies an unsupported signing algorithm.
@@ -59,14 +59,20 @@ export const listConsoleMessages = definePageTool(cliArgs => {
59
59
  .default(false)
60
60
  .optional()
61
61
  .describe('Set to true to return the preserved messages over the last 3 navigations.'),
62
+ serviceWorkerId: zod
63
+ .string()
64
+ .optional()
65
+ .describe('Filter messages to only return messages of the specified service worker.'),
62
66
  },
63
67
  blockedByDialog: false,
68
+ verifyFilesSchema: [],
64
69
  handler: async (request, response) => {
65
70
  response.setIncludeConsoleData(true, {
66
71
  pageSize: request.params.pageSize,
67
72
  pageIdx: request.params.pageIdx,
68
73
  types: request.params.types,
69
74
  includePreservedMessages: request.params.includePreservedMessages,
75
+ serviceWorkerId: request.params.serviceWorkerId,
70
76
  });
71
77
  },
72
78
  };
@@ -84,6 +90,7 @@ export const getConsoleMessage = definePageTool({
84
90
  .describe('The msgid of a console message on the page from the listed console messages'),
85
91
  },
86
92
  blockedByDialog: false,
93
+ verifyFilesSchema: [],
87
94
  handler: async (request, response) => {
88
95
  response.attachConsoleMessage(request.params.msgid);
89
96
  },
@@ -74,6 +74,7 @@ export const emulate = definePageTool({
74
74
  .describe('Extra HTTP headers as a JSON string object, e.g. {"X-Custom": "value", "Authorization": "Bearer token"}. Headers are included into every HTTP request originating from the page and persist across navigations until cleared. Pass an empty string to clear all extra headers.'),
75
75
  },
76
76
  blockedByDialog: true,
77
+ verifyFilesSchema: [],
77
78
  handler: async (request, response, context) => {
78
79
  const page = request.page;
79
80
  await context.emulate(request.params, page.pptrPage);
@@ -19,9 +19,9 @@ export const installExtension = defineTool({
19
19
  .describe('Absolute path to the unpacked extension folder.'),
20
20
  },
21
21
  blockedByDialog: false,
22
+ verifyFilesSchema: ['path'],
22
23
  handler: async (request, response, context) => {
23
24
  const { path } = request.params;
24
- await context.validatePath(path);
25
25
  const id = await context.installExtension(path);
26
26
  response.appendResponseLine(`Extension installed. Id: ${id}`);
27
27
  },
@@ -37,6 +37,7 @@ export const uninstallExtension = defineTool({
37
37
  id: zod.string().describe('ID of the extension to uninstall.'),
38
38
  },
39
39
  blockedByDialog: false,
40
+ verifyFilesSchema: [],
40
41
  handler: async (request, response, context) => {
41
42
  const { id } = request.params;
42
43
  await context.uninstallExtension(id);
@@ -52,6 +53,7 @@ export const listExtensions = defineTool({
52
53
  },
53
54
  schema: {},
54
55
  blockedByDialog: false,
56
+ verifyFilesSchema: [],
55
57
  handler: async (_request, response, _context) => {
56
58
  response.setListExtensions();
57
59
  },
@@ -67,13 +69,13 @@ export const reloadExtension = defineTool({
67
69
  id: zod.string().describe('ID of the extension to reload.'),
68
70
  },
69
71
  blockedByDialog: false,
72
+ verifyFilesSchema: [],
70
73
  handler: async (request, response, context) => {
71
74
  const { id } = request.params;
72
75
  const extension = await context.getExtension(id);
73
76
  if (!extension) {
74
77
  throw new Error(`Extension with ID ${id} not found.`);
75
78
  }
76
- await context.validatePath(extension.path);
77
79
  await context.installExtension(extension.path);
78
80
  response.appendResponseLine('Extension reloaded.');
79
81
  },
@@ -89,6 +91,7 @@ export const triggerExtensionAction = defineTool({
89
91
  id: zod.string().describe('ID of the extension to trigger the action for.'),
90
92
  },
91
93
  blockedByDialog: false,
94
+ verifyFilesSchema: [],
92
95
  handler: async (request, response, context) => {
93
96
  const { id } = request.params;
94
97
  await context.triggerExtensionAction(id);
@@ -21,7 +21,7 @@ const submitKeySchema = zod
21
21
  .optional()
22
22
  .describe('Optional key to press after typing. E.g., "Enter", "Tab", "Escape"');
23
23
  function handleActionError(error, uid) {
24
- logger('failed to act using a locator', error);
24
+ logger?.('failed to act using a locator', error);
25
25
  throw new Error(`Failed to interact with the element with uid ${uid}. The element did not become interactive within the configured timeout.`, {
26
26
  cause: error,
27
27
  });
@@ -79,6 +79,7 @@ export const click = definePageTool({
79
79
  includeSnapshot: includeSnapshotSchema,
80
80
  },
81
81
  blockedByDialog: true,
82
+ verifyFilesSchema: [],
82
83
  handler: async (request, response) => {
83
84
  const uid = request.params.uid;
84
85
  const handle = await request.page.getElementByUid(uid);
@@ -125,6 +126,7 @@ export const clickAt = definePageTool({
125
126
  includeSnapshot: includeSnapshotSchema,
126
127
  },
127
128
  blockedByDialog: true,
129
+ verifyFilesSchema: [],
128
130
  handler: async (request, response) => {
129
131
  const page = request.page;
130
132
  const result = await page.waitForEventsAfterAction(async () => {
@@ -155,6 +157,7 @@ export const hover = definePageTool({
155
157
  includeSnapshot: includeSnapshotSchema,
156
158
  },
157
159
  blockedByDialog: true,
160
+ verifyFilesSchema: [],
158
161
  handler: async (request, response) => {
159
162
  const uid = request.params.uid;
160
163
  const handle = await request.page.getElementByUid(uid);
@@ -270,6 +273,7 @@ export const fill = definePageTool({
270
273
  includeSnapshot: includeSnapshotSchema,
271
274
  },
272
275
  blockedByDialog: true,
276
+ verifyFilesSchema: [],
273
277
  handler: async (request, response, context) => {
274
278
  const page = request.page;
275
279
  const result = await page.waitForEventsAfterAction(async () => {
@@ -294,6 +298,7 @@ export const typeText = definePageTool({
294
298
  submitKey: submitKeySchema,
295
299
  },
296
300
  blockedByDialog: true,
301
+ verifyFilesSchema: [],
297
302
  handler: async (request, response) => {
298
303
  const page = request.page;
299
304
  const result = await page.waitForEventsAfterAction(async () => {
@@ -319,6 +324,7 @@ export const drag = definePageTool({
319
324
  includeSnapshot: includeSnapshotSchema,
320
325
  },
321
326
  blockedByDialog: true,
327
+ verifyFilesSchema: [],
322
328
  handler: async (request, response) => {
323
329
  const fromHandle = await request.page.getElementByUid(request.params.from_uid);
324
330
  const toHandle = await request.page.getElementByUid(request.params.to_uid);
@@ -361,6 +367,7 @@ export const fillForm = definePageTool({
361
367
  includeSnapshot: includeSnapshotSchema,
362
368
  },
363
369
  blockedByDialog: true,
370
+ verifyFilesSchema: [],
364
371
  handler: async (request, response, context) => {
365
372
  const page = request.page;
366
373
  let lastResult = {};
@@ -391,9 +398,9 @@ export const uploadFile = definePageTool({
391
398
  includeSnapshot: includeSnapshotSchema,
392
399
  },
393
400
  blockedByDialog: true,
394
- handler: async (request, response, context) => {
401
+ verifyFilesSchema: ['filePath'],
402
+ handler: async (request, response, _context) => {
395
403
  const { uid, filePath } = request.params;
396
- await context.validatePath(filePath);
397
404
  const handle = (await request.page.getElementByUid(uid));
398
405
  try {
399
406
  try {
@@ -438,6 +445,7 @@ export const pressKey = definePageTool({
438
445
  includeSnapshot: includeSnapshotSchema,
439
446
  },
440
447
  blockedByDialog: true,
448
+ verifyFilesSchema: [],
441
449
  handler: async (request, response) => {
442
450
  const page = request.page;
443
451
  const tokens = parseKey(request.params.key);
@@ -30,6 +30,7 @@ export const lighthouseAudit = definePageTool({
30
30
  .describe('Directory for reports. If omitted, uses temporary files.'),
31
31
  },
32
32
  blockedByDialog: true,
33
+ verifyFilesSchema: ['outputDirPath'],
33
34
  handler: async (request, response, context) => {
34
35
  const page = request.page;
35
36
  const categories = [
@@ -40,7 +41,6 @@ export const lighthouseAudit = definePageTool({
40
41
  ];
41
42
  const formats = ['json', 'html'];
42
43
  const { mode = 'navigation', device = 'desktop', outputDirPath, } = request.params;
43
- await context.validatePath(outputDirPath);
44
44
  const flags = {
45
45
  onlyCategories: categories,
46
46
  output: formats,
@@ -89,18 +89,23 @@ export const lighthouseAudit = definePageTool({
89
89
  const lhr = result.lhr;
90
90
  const reportPaths = [];
91
91
  const encoder = new TextEncoder();
92
- for (const format of formats) {
92
+ const savePromises = formats.map(async (format) => {
93
93
  const report = generateReport(lhr, format);
94
94
  const data = encoder.encode(report);
95
95
  if (outputDirPath) {
96
96
  const reportPath = path.join(outputDirPath, `report`);
97
97
  const { filename } = await context.saveFile(data, reportPath, `.${format}`);
98
- reportPaths.push(filename);
98
+ return filename;
99
99
  }
100
- else {
101
- const { filepath } = await context.saveTemporaryFile(data, `report.${format}`);
102
- reportPaths.push(filepath);
100
+ const { filepath } = await context.saveTemporaryFile(data, `report.${format}`);
101
+ return filepath;
102
+ });
103
+ const results = await Promise.allSettled(savePromises);
104
+ for (const res of results) {
105
+ if (res.status === 'rejected') {
106
+ throw res.reason;
103
107
  }
108
+ reportPaths.push(res.value);
104
109
  }
105
110
  const categoryScores = Object.values(lhr.categories).map(c => ({
106
111
  id: c.id,
@@ -20,9 +20,9 @@ export const takeHeapSnapshot = definePageTool({
20
20
  .describe('A path to a .heapsnapshot file to save the heapsnapshot to.'),
21
21
  },
22
22
  blockedByDialog: true,
23
- handler: async (request, response, context) => {
23
+ verifyFilesSchema: ['filePath'],
24
+ handler: async (request, response) => {
24
25
  const page = request.page;
25
- await context.validatePath(request.params.filePath);
26
26
  await page.pptrPage.captureHeapSnapshot({
27
27
  path: ensureExtension(request.params.filePath, '.heapsnapshot'),
28
28
  });
@@ -35,14 +35,14 @@ export const getHeapSnapshotSummary = defineTool({
35
35
  annotations: {
36
36
  category: ToolCategory.MEMORY,
37
37
  readOnlyHint: true,
38
- conditions: ['experimentalMemory'],
38
+ conditions: ['memoryDebugging'],
39
39
  },
40
40
  schema: {
41
41
  filePath: zod.string().describe('A path to a .heapsnapshot file to read.'),
42
42
  },
43
43
  blockedByDialog: false,
44
+ verifyFilesSchema: ['filePath'],
44
45
  handler: async (request, response, context) => {
45
- await context.validatePath(request.params.filePath);
46
46
  const stats = await context.getHeapSnapshotStats(request.params.filePath);
47
47
  const staticData = await context.getHeapSnapshotStaticData(request.params.filePath);
48
48
  response.setHeapSnapshotStats(stats, staticData);
@@ -54,7 +54,7 @@ export const getHeapSnapshotDetails = defineTool({
54
54
  annotations: {
55
55
  category: ToolCategory.MEMORY,
56
56
  readOnlyHint: true,
57
- conditions: ['experimentalMemory'],
57
+ conditions: ['memoryDebugging'],
58
58
  },
59
59
  schema: {
60
60
  filePath: zod.string().describe('A path to a .heapsnapshot file to read.'),
@@ -68,8 +68,8 @@ export const getHeapSnapshotDetails = defineTool({
68
68
  .describe('The page size for pagination of aggregates.'),
69
69
  },
70
70
  blockedByDialog: false,
71
+ verifyFilesSchema: ['filePath'],
71
72
  handler: async (request, response, context) => {
72
- await context.validatePath(request.params.filePath);
73
73
  const aggregates = await context.getHeapSnapshotAggregates(request.params.filePath);
74
74
  response.setHeapSnapshotAggregates(aggregates, {
75
75
  pageIdx: request.params.pageIdx,
@@ -83,7 +83,7 @@ export const getHeapSnapshotClassNodes = defineTool({
83
83
  annotations: {
84
84
  category: ToolCategory.MEMORY,
85
85
  readOnlyHint: true,
86
- conditions: ['experimentalMemory'],
86
+ conditions: ['memoryDebugging'],
87
87
  },
88
88
  schema: {
89
89
  filePath: zod.string().describe('A path to a .heapsnapshot file to read.'),
@@ -92,8 +92,8 @@ export const getHeapSnapshotClassNodes = defineTool({
92
92
  pageSize: zod.number().optional().describe('The page size for pagination.'),
93
93
  },
94
94
  blockedByDialog: false,
95
+ verifyFilesSchema: ['filePath'],
95
96
  handler: async (request, response, context) => {
96
- await context.validatePath(request.params.filePath);
97
97
  const nodes = await context.getHeapSnapshotNodesById(request.params.filePath, request.params.id);
98
98
  response.setHeapSnapshotNodes(nodes, {
99
99
  pageIdx: request.params.pageIdx,
@@ -107,9 +107,10 @@ export const getHeapSnapshotRetainers = defineTool({
107
107
  annotations: {
108
108
  category: ToolCategory.MEMORY,
109
109
  readOnlyHint: true,
110
- conditions: ['experimentalMemory'],
110
+ conditions: ['memoryDebugging'],
111
111
  },
112
112
  blockedByDialog: false,
113
+ verifyFilesSchema: ['filePath'],
113
114
  schema: {
114
115
  filePath: zod.string().describe('A path to a .heapsnapshot file to read.'),
115
116
  nodeId: zod.number().describe('The node ID to get retainers for.'),
@@ -117,7 +118,6 @@ export const getHeapSnapshotRetainers = defineTool({
117
118
  pageSize: zod.number().optional().describe('The page size for pagination.'),
118
119
  },
119
120
  handler: async (request, response, context) => {
120
- await context.validatePath(request.params.filePath);
121
121
  const retainers = await context.getHeapSnapshotRetainers(request.params.filePath, request.params.nodeId);
122
122
  response.setHeapSnapshotNodes(retainers, {
123
123
  pageIdx: request.params.pageIdx,
@@ -125,4 +125,27 @@ export const getHeapSnapshotRetainers = defineTool({
125
125
  });
126
126
  },
127
127
  });
128
+ export const closeHeapSnapshot = defineTool({
129
+ name: 'close_heapsnapshot',
130
+ description: 'Closes a previously loaded memory heapsnapshot, freeing its memory.',
131
+ annotations: {
132
+ category: ToolCategory.MEMORY,
133
+ readOnlyHint: false,
134
+ conditions: ['memoryDebugging'],
135
+ },
136
+ verifyFilesSchema: ['filePath'],
137
+ schema: {
138
+ filePath: zod
139
+ .string()
140
+ .describe('A path to the .heapsnapshot file to close.'),
141
+ },
142
+ blockedByDialog: false,
143
+ handler: async (request, response, context) => {
144
+ const closed = await context.closeHeapSnapshot(request.params.filePath);
145
+ if (!closed) {
146
+ throw new Error(`Failed to close heap snapshot: ${request.params.filePath} was not loaded.`);
147
+ }
148
+ response.appendResponseLine(`Closed heap snapshot: ${request.params.filePath}`);
149
+ },
150
+ });
128
151
  //# sourceMappingURL=memory.js.map
@@ -58,6 +58,7 @@ export const listNetworkRequests = definePageTool({
58
58
  .describe('Set to true to return the preserved requests over the last 3 navigations.'),
59
59
  },
60
60
  blockedByDialog: false,
61
+ verifyFilesSchema: [],
61
62
  handler: async (request, response, context) => {
62
63
  const data = await request.page.getDevToolsData();
63
64
  response.attachDevToolsData(data);
@@ -95,9 +96,8 @@ export const getNetworkRequest = definePageTool({
95
96
  .describe('The absolute or relative path to a .network-response file to save the response body to. If omitted, the body is returned inline.'),
96
97
  },
97
98
  blockedByDialog: true,
99
+ verifyFilesSchema: ['requestFilePath', 'responseFilePath'],
98
100
  handler: async (request, response, context) => {
99
- await context.validatePath(request.params.requestFilePath);
100
- await context.validatePath(request.params.responseFilePath);
101
101
  if (request.params.reqid) {
102
102
  response.attachNetworkRequest(request.params.reqid, {
103
103
  requestFilePath: request.params.requestFilePath,