chrome-devtools-mcp 0.15.0 → 0.16.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.
package/README.md CHANGED
@@ -15,7 +15,7 @@ Chrome DevTools for reliable automation, in-depth debugging, and performance ana
15
15
  DevTools](https://github.com/ChromeDevTools/devtools-frontend) to record
16
16
  traces and extract actionable performance insights.
17
17
  - **Advanced browser debugging**: Analyze network requests, take screenshots and
18
- check the browser console.
18
+ check browser console messages (with source-mapped stack traces).
19
19
  - **Reliable automation**. Uses
20
20
  [puppeteer](https://github.com/puppeteer/puppeteer) to automate actions in
21
21
  Chrome and automatically wait for action results.
@@ -41,6 +41,8 @@ Google handles this data in accordance with the [Google Privacy Policy](https://
41
41
 
42
42
  Google's collection of usage statistics for Chrome DevTools MCP is independent from the Chrome browser's usage statistics. Opting out of Chrome metrics does not automatically opt you out of this tool, and vice-versa.
43
43
 
44
+ Collection is disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.
45
+
44
46
  ## Requirements
45
47
 
46
48
  - [Node.js](https://nodejs.org/) v20.19 or a newer [latest maintenance LTS](https://github.com/nodejs/Release#release-schedule) version.
@@ -465,7 +467,7 @@ The Chrome DevTools MCP server supports the following configuration option:
465
467
  - **Default:** `true`
466
468
 
467
469
  - **`--usageStatistics`/ `--usage-statistics`**
468
- Set to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics.
470
+ Set to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics. Disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.
469
471
  - **Type:** boolean
470
472
  - **Default:** `true`
471
473
 
@@ -561,15 +563,12 @@ The following code snippet is an example configuration for gemini-cli:
561
563
  "mcpServers": {
562
564
  "chrome-devtools": {
563
565
  "command": "npx",
564
- "args": ["chrome-devtools-mcp@latest", "--autoConnect", "--channel=beta"]
566
+ "args": ["chrome-devtools-mcp@latest", "--autoConnect"]
565
567
  }
566
568
  }
567
569
  }
568
570
  ```
569
571
 
570
- Note: you have to specify `--channel=beta` until Chrome M144 has reached the
571
- stable channel.
572
-
573
572
  **Step 3:** Test your setup
574
573
 
575
574
  Make sure your browser is running. Open gemini-cli and run the following prompt:
@@ -172,13 +172,15 @@ const SKIP_ALL_PAUSES = {
172
172
  export async function createStackTraceForConsoleMessage(devTools, consoleMessage) {
173
173
  const message = consoleMessage;
174
174
  const rawStackTrace = message._rawStackTrace();
175
- if (!rawStackTrace) {
176
- return undefined;
175
+ if (rawStackTrace) {
176
+ return createStackTrace(devTools, rawStackTrace, message._targetId());
177
177
  }
178
+ return undefined;
179
+ }
180
+ export async function createStackTrace(devTools, rawStackTrace, targetId) {
178
181
  const targetManager = devTools.universe.context.get(DevTools.TargetManager);
179
- const messageTargetId = message._targetId();
180
- const target = messageTargetId
181
- ? targetManager.targetById(messageTargetId) || devTools.target
182
+ const target = targetId
183
+ ? targetManager.targetById(targetId) || devTools.target
182
184
  : devTools.target;
183
185
  const model = target.model(DevTools.DebuggerModel);
184
186
  // DevTools doesn't wait for source maps to attach before building a stack trace, rather it'll send
@@ -80,15 +80,8 @@ export class McpContext {
80
80
  console: event => {
81
81
  collect(event);
82
82
  },
83
- pageerror: event => {
84
- if (event instanceof Error) {
85
- collect(event);
86
- }
87
- else {
88
- const error = new Error(`${event}`);
89
- error.stack = undefined;
90
- collect(error);
91
- }
83
+ uncaughtError: event => {
84
+ collect(event);
92
85
  },
93
86
  issue: event => {
94
87
  collect(event);
@@ -551,12 +544,12 @@ export class McpContext {
551
544
  getWaitForHelper(page, cpuMultiplier, networkMultiplier) {
552
545
  return new WaitForHelper(page, cpuMultiplier, networkMultiplier);
553
546
  }
554
- waitForEventsAfterAction(action) {
547
+ waitForEventsAfterAction(action, options) {
555
548
  const page = this.getSelectedPage();
556
549
  const cpuMultiplier = this.getCpuThrottlingRate();
557
550
  const networkMultiplier = getNetworkMultiplierFromString(this.getNetworkConditions());
558
551
  const waitForHelper = this.getWaitForHelper(page, cpuMultiplier, networkMultiplier);
559
- return waitForHelper.waitForEventsAfterAction(action);
552
+ return waitForHelper.waitForEventsAfterAction(action, options);
560
553
  }
561
554
  getNetworkRequestStableId(request) {
562
555
  return this.#networkCollector.getIdForResource(request);
@@ -7,6 +7,7 @@ import { ConsoleFormatter } from './formatters/ConsoleFormatter.js';
7
7
  import { IssueFormatter } from './formatters/IssueFormatter.js';
8
8
  import { NetworkFormatter } from './formatters/NetworkFormatter.js';
9
9
  import { SnapshotFormatter } from './formatters/SnapshotFormatter.js';
10
+ import { UncaughtError } from './PageCollector.js';
10
11
  import { DevTools } from './third_party/index.js';
11
12
  import { handleDialog } from './tools/pages.js';
12
13
  import { getInsightOutput, getTraceSummary } from './trace-processing/parse.js';
@@ -173,7 +174,7 @@ export class McpResponse {
173
174
  if (this.#attachedConsoleMessageId) {
174
175
  const message = context.getConsoleMessageById(this.#attachedConsoleMessageId);
175
176
  const consoleMessageStableId = this.#attachedConsoleMessageId;
176
- if ('args' in message) {
177
+ if ('args' in message || message instanceof UncaughtError) {
177
178
  const consoleMessage = message;
178
179
  const devTools = context.getDevToolsUniverse();
179
180
  detailedConsoleMessage = await ConsoleFormatter.from(consoleMessage, {
@@ -220,7 +221,7 @@ export class McpResponse {
220
221
  }
221
222
  consoleMessages = (await Promise.all(messages.map(async (item) => {
222
223
  const consoleMessageStableId = context.getConsoleMessageStableId(item);
223
- if ('args' in item) {
224
+ if ('args' in item || item instanceof UncaughtError) {
224
225
  const consoleMessage = item;
225
226
  const devTools = context.getDevToolsUniverse();
226
227
  return await ConsoleFormatter.from(consoleMessage, {
@@ -6,6 +6,16 @@
6
6
  import { FakeIssuesManager } from './DevtoolsUtils.js';
7
7
  import { logger } from './logger.js';
8
8
  import { DevTools } from './third_party/index.js';
9
+ export class UncaughtError {
10
+ message;
11
+ stackTrace;
12
+ targetId;
13
+ constructor(message, stackTrace, targetId) {
14
+ this.message = message;
15
+ this.stackTrace = stackTrace;
16
+ this.targetId = targetId;
17
+ }
18
+ }
9
19
  function createIdGenerator() {
10
20
  let i = 1;
11
21
  return () => {
@@ -161,7 +171,7 @@ export class ConsoleCollector extends PageCollector {
161
171
  addPage(page) {
162
172
  super.addPage(page);
163
173
  if (!this.#subscribedPages.has(page)) {
164
- const subscriber = new PageIssueSubscriber(page);
174
+ const subscriber = new PageEventSubscriber(page);
165
175
  this.#subscribedPages.set(page, subscriber);
166
176
  void subscriber.subscribe();
167
177
  }
@@ -172,17 +182,20 @@ export class ConsoleCollector extends PageCollector {
172
182
  this.#subscribedPages.delete(page);
173
183
  }
174
184
  }
175
- class PageIssueSubscriber {
185
+ class PageEventSubscriber {
176
186
  #issueManager = new FakeIssuesManager();
177
187
  #issueAggregator = new DevTools.IssueAggregator(this.#issueManager);
178
188
  #seenKeys = new Set();
179
189
  #seenIssues = new Set();
180
190
  #page;
181
191
  #session;
192
+ #targetId;
182
193
  constructor(page) {
183
194
  this.#page = page;
184
195
  // @ts-expect-error use existing CDP client (internal Puppeteer API).
185
196
  this.#session = this.#page._client();
197
+ // @ts-expect-error use internal Puppeteer API to get target ID
198
+ this.#targetId = this.#session.target()._targetId;
186
199
  }
187
200
  #resetIssueAggregator() {
188
201
  this.#issueManager = new FakeIssuesManager();
@@ -196,6 +209,7 @@ class PageIssueSubscriber {
196
209
  this.#resetIssueAggregator();
197
210
  this.#page.on('framenavigated', this.#onFrameNavigated);
198
211
  this.#session.on('Audits.issueAdded', this.#onIssueAdded);
212
+ this.#session.on('Runtime.exceptionThrown', this.#onExceptionThrown);
199
213
  try {
200
214
  await this.#session.send('Audits.enable');
201
215
  }
@@ -208,6 +222,7 @@ class PageIssueSubscriber {
208
222
  this.#seenIssues.clear();
209
223
  this.#page.off('framenavigated', this.#onFrameNavigated);
210
224
  this.#session.off('Audits.issueAdded', this.#onIssueAdded);
225
+ this.#session.off('Runtime.exceptionThrown', this.#onExceptionThrown);
211
226
  if (this.#issueAggregator) {
212
227
  this.#issueAggregator.removeEventListener("AggregatedIssueUpdated" /* DevTools.IssueAggregatorEvents.AGGREGATED_ISSUE_UPDATED */, this.#onAggregatedissue);
213
228
  }
@@ -222,6 +237,12 @@ class PageIssueSubscriber {
222
237
  this.#seenIssues.add(event.data);
223
238
  this.#page.emit('issue', event.data);
224
239
  };
240
+ #onExceptionThrown = (event) => {
241
+ const { exception, text, stackTrace } = event.exceptionDetails;
242
+ const messageWithRest = exception?.description?.split('\n at ', 2) ?? [];
243
+ const message = text + ' ' + (messageWithRest[0] ?? '');
244
+ this.#page.emit('uncaughtError', new UncaughtError(message, stackTrace, this.#targetId));
245
+ };
225
246
  // On navigation, we reset issue aggregation.
226
247
  #onFrameNavigated = (frame) => {
227
248
  // Only split the storage on main frame navigation
@@ -103,12 +103,12 @@ export class WaitForHelper {
103
103
  });
104
104
  });
105
105
  }
106
- async waitForEventsAfterAction(action) {
106
+ async waitForEventsAfterAction(action, options) {
107
107
  const navigationFinished = this.waitForNavigationStarted()
108
108
  .then(navigationStated => {
109
109
  if (navigationStated) {
110
110
  return this.#page.waitForNavigation({
111
- timeout: this.#navigationTimeout,
111
+ timeout: options?.timeout ?? this.#navigationTimeout,
112
112
  signal: this.#abortController.signal,
113
113
  });
114
114
  }
package/build/src/cli.js CHANGED
@@ -191,7 +191,7 @@ export const cliOptions = {
191
191
  usageStatistics: {
192
192
  type: 'boolean',
193
193
  default: true,
194
- describe: 'Set to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics.',
194
+ describe: 'Set to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics. Disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.',
195
195
  },
196
196
  clearcutEndpoint: {
197
197
  type: 'string',
@@ -3,7 +3,7 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { createStackTraceForConsoleMessage, } from '../DevtoolsUtils.js';
6
+ import { createStackTraceForConsoleMessage, createStackTrace, } from '../DevtoolsUtils.js';
7
7
  export class ConsoleFormatter {
8
8
  #msg;
9
9
  #resolvedArgs = [];
@@ -21,21 +21,32 @@ export class ConsoleFormatter {
21
21
  }
22
22
  return formatter;
23
23
  }
24
+ #isConsoleMessage(msg) {
25
+ // No `instanceof` as tests mock `ConsoleMessage`.
26
+ return 'args' in msg && typeof msg.args === 'function';
27
+ }
24
28
  async #loadDetailedData(devTools) {
25
29
  if (this.#msg instanceof Error) {
26
30
  return;
27
31
  }
28
- this.#resolvedArgs = await Promise.all(this.#msg.args().map(async (arg, i) => {
29
- try {
30
- return await arg.jsonValue();
31
- }
32
- catch {
33
- return `<error: Argument ${i} is no longer available>`;
34
- }
35
- }));
32
+ if (this.#isConsoleMessage(this.#msg)) {
33
+ this.#resolvedArgs = await Promise.all(this.#msg.args().map(async (arg, i) => {
34
+ try {
35
+ return await arg.jsonValue();
36
+ }
37
+ catch {
38
+ return `<error: Argument ${i} is no longer available>`;
39
+ }
40
+ }));
41
+ }
36
42
  if (devTools) {
37
43
  try {
38
- this.#resolvedStackTrace = await createStackTraceForConsoleMessage(devTools, this.#msg);
44
+ if (this.#isConsoleMessage(this.#msg)) {
45
+ this.#resolvedStackTrace = await createStackTraceForConsoleMessage(devTools, this.#msg);
46
+ }
47
+ else if (this.#msg.stackTrace) {
48
+ this.#resolvedStackTrace = await createStackTrace(devTools, this.#msg.stackTrace, this.#msg.targetId);
49
+ }
39
50
  }
40
51
  catch {
41
52
  // ignore
@@ -46,9 +57,7 @@ export class ConsoleFormatter {
46
57
  toString() {
47
58
  const type = this.#getType();
48
59
  const text = this.#getText();
49
- const argsCount = this.#msg instanceof Error
50
- ? 0
51
- : this.#resolvedArgs.length || this.#msg.args().length;
60
+ const argsCount = this.#getArgsCount();
52
61
  const idPart = this.#id !== undefined ? `msgid=${this.#id} ` : '';
53
62
  return `${idPart}[${type}] ${text} (${argsCount} args)`;
54
63
  }
@@ -63,19 +72,19 @@ export class ConsoleFormatter {
63
72
  return result.join('\n');
64
73
  }
65
74
  #getType() {
66
- if (this.#msg instanceof Error) {
75
+ if (!this.#isConsoleMessage(this.#msg)) {
67
76
  return 'error';
68
77
  }
69
78
  return this.#msg.type();
70
79
  }
71
80
  #getText() {
72
- if (this.#msg instanceof Error) {
81
+ if (!this.#isConsoleMessage(this.#msg)) {
73
82
  return this.#msg.message;
74
83
  }
75
84
  return this.#msg.text();
76
85
  }
77
86
  #getArgs() {
78
- if (this.#msg instanceof Error) {
87
+ if (!this.#isConsoleMessage(this.#msg)) {
79
88
  return [];
80
89
  }
81
90
  if (this.#resolvedArgs.length > 0) {
@@ -88,6 +97,12 @@ export class ConsoleFormatter {
88
97
  }
89
98
  return [];
90
99
  }
100
+ #getArgsCount() {
101
+ if (!this.#isConsoleMessage(this.#msg)) {
102
+ return 0;
103
+ }
104
+ return this.#resolvedArgs.length || this.#msg.args().length;
105
+ }
91
106
  #formatArg(arg) {
92
107
  return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
93
108
  }
@@ -110,6 +125,7 @@ export class ConsoleFormatter {
110
125
  '### Stack trace',
111
126
  this.#formatFragment(stackTrace.syncFragment),
112
127
  ...stackTrace.asyncFragments.map(this.#formatAsyncFragment.bind(this)),
128
+ 'Note: line and column numbers use 1-based indexing',
113
129
  ].join('\n');
114
130
  }
115
131
  #formatFragment(fragment) {
@@ -124,7 +140,8 @@ export class ConsoleFormatter {
124
140
  #formatFrame(frame) {
125
141
  let result = `at ${frame.name ?? '<anonymous>'}`;
126
142
  if (frame.uiSourceCode) {
127
- result += ` (${frame.uiSourceCode.displayName()}:${frame.line}:${frame.column})`;
143
+ const location = frame.uiSourceCode.uiLocation(frame.line, frame.column);
144
+ result += ` (${location.linkText(/* skipTrim */ false, /* showColumnNumber */ true)})`;
128
145
  }
129
146
  else if (frame.url) {
130
147
  result += ` (${frame.url}:${frame.line}:${frame.column})`;
@@ -135,9 +152,7 @@ export class ConsoleFormatter {
135
152
  return {
136
153
  type: this.#getType(),
137
154
  text: this.#getText(),
138
- argsCount: this.#msg instanceof Error
139
- ? 0
140
- : this.#resolvedArgs.length || this.#msg.args().length,
155
+ argsCount: this.#getArgsCount(),
141
156
  id: this.#id,
142
157
  };
143
158
  }
package/build/src/main.js CHANGED
@@ -20,10 +20,15 @@ import { ToolCategory } from './tools/categories.js';
20
20
  import { tools } from './tools/tools.js';
21
21
  // If moved update release-please config
22
22
  // x-release-please-start-version
23
- const VERSION = '0.15.0';
23
+ const VERSION = '0.16.0';
24
24
  // x-release-please-end
25
25
  export const args = parseArguments(VERSION);
26
26
  const logFile = args.logFile ? saveLogsToFile(args.logFile) : undefined;
27
+ if (process.env['CI'] ||
28
+ process.env['CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS']) {
29
+ console.error("turning off usage statistics. process.env['CI'] || process.env['CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS'] is set.");
30
+ args.usageStatistics = false;
31
+ }
27
32
  let clearcutLogger;
28
33
  if (args.usageStatistics) {
29
34
  clearcutLogger = new ClearcutLogger({
@@ -0,0 +1,8 @@
1
+ {
2
+ "@modelcontextprotocol/sdk": "1.25.3",
3
+ "chrome-devtools-frontend": "1.0.1576915",
4
+ "core-js": "3.48.0",
5
+ "debug": "4.4.3",
6
+ "yargs": "18.0.0",
7
+ "puppeteer-core": "24.36.1"
8
+ }
@@ -101867,6 +101867,41 @@ function registerCommands(inspectorBackend) {
101867
101867
  inspectorBackend.registerType("ServiceWorker.ServiceWorkerRegistration", [{ "name": "registrationId", "type": "string", "optional": false, "description": "", "typeRef": "ServiceWorker.RegistrationID" }, { "name": "scopeURL", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "isDeleted", "type": "boolean", "optional": false, "description": "", "typeRef": null }]);
101868
101868
  inspectorBackend.registerType("ServiceWorker.ServiceWorkerVersion", [{ "name": "versionId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "registrationId", "type": "string", "optional": false, "description": "", "typeRef": "ServiceWorker.RegistrationID" }, { "name": "scriptURL", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "runningStatus", "type": "string", "optional": false, "description": "", "typeRef": "ServiceWorker.ServiceWorkerVersionRunningStatus" }, { "name": "status", "type": "string", "optional": false, "description": "", "typeRef": "ServiceWorker.ServiceWorkerVersionStatus" }, { "name": "scriptLastModified", "type": "number", "optional": true, "description": "The Last-Modified header value of the main script.", "typeRef": null }, { "name": "scriptResponseTime", "type": "number", "optional": true, "description": "The time at which the response headers of the main script were received from the server. For cached script it is the last time the cache entry was validated.", "typeRef": null }, { "name": "controlledClients", "type": "array", "optional": true, "description": "", "typeRef": "Target.TargetID" }, { "name": "targetId", "type": "string", "optional": true, "description": "", "typeRef": "Target.TargetID" }, { "name": "routerRules", "type": "string", "optional": true, "description": "", "typeRef": null }]);
101869
101869
  inspectorBackend.registerType("ServiceWorker.ServiceWorkerErrorMessage", [{ "name": "errorMessage", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "registrationId", "type": "string", "optional": false, "description": "", "typeRef": "ServiceWorker.RegistrationID" }, { "name": "versionId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "sourceURL", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "lineNumber", "type": "number", "optional": false, "description": "", "typeRef": null }, { "name": "columnNumber", "type": "number", "optional": false, "description": "", "typeRef": null }]);
101870
+ inspectorBackend.registerEnum("SmartCardEmulation.ResultCode", { Success: "success", RemovedCard: "removed-card", ResetCard: "reset-card", UnpoweredCard: "unpowered-card", UnresponsiveCard: "unresponsive-card", UnsupportedCard: "unsupported-card", ReaderUnavailable: "reader-unavailable", SharingViolation: "sharing-violation", NotTransacted: "not-transacted", NoSmartcard: "no-smartcard", ProtoMismatch: "proto-mismatch", SystemCancelled: "system-cancelled", NotReady: "not-ready", Cancelled: "cancelled", InsufficientBuffer: "insufficient-buffer", InvalidHandle: "invalid-handle", InvalidParameter: "invalid-parameter", InvalidValue: "invalid-value", NoMemory: "no-memory", Timeout: "timeout", UnknownReader: "unknown-reader", UnsupportedFeature: "unsupported-feature", NoReadersAvailable: "no-readers-available", ServiceStopped: "service-stopped", NoService: "no-service", CommError: "comm-error", InternalError: "internal-error", ServerTooBusy: "server-too-busy", Unexpected: "unexpected", Shutdown: "shutdown", UnknownCard: "unknown-card", Unknown: "unknown" });
101871
+ inspectorBackend.registerEnum("SmartCardEmulation.ShareMode", { Shared: "shared", Exclusive: "exclusive", Direct: "direct" });
101872
+ inspectorBackend.registerEnum("SmartCardEmulation.Disposition", { LeaveCard: "leave-card", ResetCard: "reset-card", UnpowerCard: "unpower-card", EjectCard: "eject-card" });
101873
+ inspectorBackend.registerEnum("SmartCardEmulation.ConnectionState", { Absent: "absent", Present: "present", Swallowed: "swallowed", Powered: "powered", Negotiable: "negotiable", Specific: "specific" });
101874
+ inspectorBackend.registerEnum("SmartCardEmulation.Protocol", { T0: "t0", T1: "t1", Raw: "raw" });
101875
+ inspectorBackend.registerEvent("SmartCardEmulation.establishContextRequested", ["requestId"]);
101876
+ inspectorBackend.registerEvent("SmartCardEmulation.releaseContextRequested", ["requestId", "contextId"]);
101877
+ inspectorBackend.registerEvent("SmartCardEmulation.listReadersRequested", ["requestId", "contextId"]);
101878
+ inspectorBackend.registerEvent("SmartCardEmulation.getStatusChangeRequested", ["requestId", "contextId", "readerStates", "timeout"]);
101879
+ inspectorBackend.registerEvent("SmartCardEmulation.cancelRequested", ["requestId", "contextId"]);
101880
+ inspectorBackend.registerEvent("SmartCardEmulation.connectRequested", ["requestId", "contextId", "reader", "shareMode", "preferredProtocols"]);
101881
+ inspectorBackend.registerEvent("SmartCardEmulation.disconnectRequested", ["requestId", "handle", "disposition"]);
101882
+ inspectorBackend.registerEvent("SmartCardEmulation.transmitRequested", ["requestId", "handle", "data", "protocol"]);
101883
+ inspectorBackend.registerEvent("SmartCardEmulation.controlRequested", ["requestId", "handle", "controlCode", "data"]);
101884
+ inspectorBackend.registerEvent("SmartCardEmulation.getAttribRequested", ["requestId", "handle", "attribId"]);
101885
+ inspectorBackend.registerEvent("SmartCardEmulation.setAttribRequested", ["requestId", "handle", "attribId", "data"]);
101886
+ inspectorBackend.registerEvent("SmartCardEmulation.statusRequested", ["requestId", "handle"]);
101887
+ inspectorBackend.registerEvent("SmartCardEmulation.beginTransactionRequested", ["requestId", "handle"]);
101888
+ inspectorBackend.registerEvent("SmartCardEmulation.endTransactionRequested", ["requestId", "handle", "disposition"]);
101889
+ inspectorBackend.registerCommand("SmartCardEmulation.enable", [], [], "Enables the |SmartCardEmulation| domain.");
101890
+ inspectorBackend.registerCommand("SmartCardEmulation.disable", [], [], "Disables the |SmartCardEmulation| domain.");
101891
+ inspectorBackend.registerCommand("SmartCardEmulation.reportEstablishContextResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "contextId", "type": "number", "optional": false, "description": "", "typeRef": null }], [], "Reports the successful result of a |SCardEstablishContext| call. This maps to: PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#gaa1b8970169fd4883a6dc4a8f43f19b67 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardestablishcontext");
101892
+ inspectorBackend.registerCommand("SmartCardEmulation.reportReleaseContextResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }], [], "Reports the successful result of a |SCardReleaseContext| call. This maps to: PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#ga6aabcba7744c5c9419fdd6404f73a934 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardreleasecontext");
101893
+ inspectorBackend.registerCommand("SmartCardEmulation.reportListReadersResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "readers", "type": "array", "optional": false, "description": "", "typeRef": "string" }], [], "Reports the successful result of a |SCardListReaders| call. This maps to: PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#ga93b07815789b3cf2629d439ecf20f0d9 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardlistreadersa");
101894
+ inspectorBackend.registerCommand("SmartCardEmulation.reportGetStatusChangeResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "readerStates", "type": "array", "optional": false, "description": "", "typeRef": "SmartCardEmulation.ReaderStateOut" }], [], "Reports the successful result of a |SCardGetStatusChange| call. This maps to: PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#ga33247d5d1257d59e55647c3bb717db24 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardgetstatuschangea");
101895
+ inspectorBackend.registerCommand("SmartCardEmulation.reportBeginTransactionResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }], [], "Reports the result of a |SCardBeginTransaction| call. On success, this creates a new transaction object. This maps to: PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#gaddb835dce01a0da1d6ca02d33ee7d861 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardbegintransaction");
101896
+ inspectorBackend.registerCommand("SmartCardEmulation.reportPlainResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }], [], "Reports the successful result of a call that returns only a result code. Used for: |SCardCancel|, |SCardDisconnect|, |SCardSetAttrib|, |SCardEndTransaction|. This maps to: 1. SCardCancel PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#gaacbbc0c6d6c0cbbeb4f4debf6fbeeee6 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardcancel 2. SCardDisconnect PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#ga4be198045c73ec0deb79e66c0ca1738a Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scarddisconnect 3. SCardSetAttrib PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#ga060f0038a4ddfd5dd2b8fadf3c3a2e4f Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardsetattrib 4. SCardEndTransaction PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#gae8742473b404363e5c587f570d7e2f3b Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardendtransaction");
101897
+ inspectorBackend.registerCommand("SmartCardEmulation.reportConnectResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "handle", "type": "number", "optional": false, "description": "", "typeRef": null }, { "name": "activeProtocol", "type": "string", "optional": true, "description": "", "typeRef": "SmartCardEmulation.Protocol" }], [], "Reports the successful result of a |SCardConnect| call. This maps to: PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#ga4e515829752e0a8dbc4d630696a8d6a5 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardconnecta");
101898
+ inspectorBackend.registerCommand("SmartCardEmulation.reportDataResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "data", "type": "string", "optional": false, "description": "", "typeRef": null }], [], "Reports the successful result of a call that sends back data on success. Used for |SCardTransmit|, |SCardControl|, and |SCardGetAttrib|. This maps to: 1. SCardTransmit PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#ga9a2d77242a271310269065e64633ab99 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardtransmit 2. SCardControl PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#gac3454d4657110fd7f753b2d3d8f4e32f Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardcontrol 3. SCardGetAttrib PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#gaacfec51917255b7a25b94c5104961602 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardgetattrib");
101899
+ inspectorBackend.registerCommand("SmartCardEmulation.reportStatusResult", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "readerName", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "state", "type": "string", "optional": false, "description": "", "typeRef": "SmartCardEmulation.ConnectionState" }, { "name": "atr", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "protocol", "type": "string", "optional": true, "description": "", "typeRef": "SmartCardEmulation.Protocol" }], [], "Reports the successful result of a |SCardStatus| call. This maps to: PC/SC Lite: https://pcsclite.apdu.fr/api/group__API.html#gae49c3c894ad7ac12a5b896bde70d0382 Microsoft: https://learn.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardstatusa");
101900
+ inspectorBackend.registerCommand("SmartCardEmulation.reportError", [{ "name": "requestId", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "resultCode", "type": "string", "optional": false, "description": "", "typeRef": "SmartCardEmulation.ResultCode" }], [], "Reports an error result for the given request.");
101901
+ inspectorBackend.registerType("SmartCardEmulation.ReaderStateFlags", [{ "name": "unaware", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "ignore", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "changed", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "unknown", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "unavailable", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "empty", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "present", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "exclusive", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "inuse", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "mute", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "unpowered", "type": "boolean", "optional": true, "description": "", "typeRef": null }]);
101902
+ inspectorBackend.registerType("SmartCardEmulation.ProtocolSet", [{ "name": "t0", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "t1", "type": "boolean", "optional": true, "description": "", "typeRef": null }, { "name": "raw", "type": "boolean", "optional": true, "description": "", "typeRef": null }]);
101903
+ inspectorBackend.registerType("SmartCardEmulation.ReaderStateIn", [{ "name": "reader", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "currentState", "type": "object", "optional": false, "description": "", "typeRef": "SmartCardEmulation.ReaderStateFlags" }, { "name": "currentInsertionCount", "type": "number", "optional": false, "description": "", "typeRef": null }]);
101904
+ inspectorBackend.registerType("SmartCardEmulation.ReaderStateOut", [{ "name": "reader", "type": "string", "optional": false, "description": "", "typeRef": null }, { "name": "eventState", "type": "object", "optional": false, "description": "", "typeRef": "SmartCardEmulation.ReaderStateFlags" }, { "name": "eventCount", "type": "number", "optional": false, "description": "", "typeRef": null }, { "name": "atr", "type": "string", "optional": false, "description": "", "typeRef": null }]);
101870
101905
  inspectorBackend.registerEnum("Storage.StorageType", { Cookies: "cookies", File_systems: "file_systems", Indexeddb: "indexeddb", Local_storage: "local_storage", Shader_cache: "shader_cache", Websql: "websql", Service_workers: "service_workers", Cache_storage: "cache_storage", Interest_groups: "interest_groups", Shared_storage: "shared_storage", Storage_buckets: "storage_buckets", All: "all", Other: "other" });
101871
101906
  inspectorBackend.registerEnum("Storage.InterestGroupAccessType", { Join: "join", Leave: "leave", Update: "update", Loaded: "loaded", Bid: "bid", Win: "win", AdditionalBid: "additionalBid", AdditionalBidWin: "additionalBidWin", TopLevelBid: "topLevelBid", TopLevelAdditionalBid: "topLevelAdditionalBid", Clear: "clear" });
101872
101907
  inspectorBackend.registerEnum("Storage.InterestGroupAuctionEventType", { Started: "started", ConfigResolved: "configResolved" });
@@ -105845,6 +105880,7 @@ const generatedProperties = [
105845
105880
  "font-variation-settings",
105846
105881
  "font-weight",
105847
105882
  "forced-color-adjust",
105883
+ "frame-sizing",
105848
105884
  "gap-rule-overlap",
105849
105885
  "grid-auto-columns",
105850
105886
  "grid-auto-flow",
@@ -105864,6 +105900,7 @@ const generatedProperties = [
105864
105900
  "hyphenate-character",
105865
105901
  "hyphenate-limit-chars",
105866
105902
  "hyphens",
105903
+ "image-animation",
105867
105904
  "image-orientation",
105868
105905
  "image-rendering",
105869
105906
  "inherits",
@@ -107943,6 +107980,16 @@ const generatedProperties = [
107943
107980
  ],
107944
107981
  "name": "forced-color-adjust"
107945
107982
  },
107983
+ {
107984
+ "keywords": [
107985
+ "auto",
107986
+ "content-width",
107987
+ "content-height",
107988
+ "content-block-size",
107989
+ "content-inline-size"
107990
+ ],
107991
+ "name": "frame-sizing"
107992
+ },
107946
107993
  {
107947
107994
  "longhands": [
107948
107995
  "row-gap",
@@ -108125,6 +108172,15 @@ const generatedProperties = [
108125
108172
  ],
108126
108173
  "name": "hyphens"
108127
108174
  },
108175
+ {
108176
+ "inherited": true,
108177
+ "keywords": [
108178
+ "normal",
108179
+ "running",
108180
+ "paused"
108181
+ ],
108182
+ "name": "image-animation"
108183
+ },
108128
108184
  {
108129
108185
  "inherited": true,
108130
108186
  "name": "image-orientation"
@@ -109271,6 +109327,13 @@ const generatedProperties = [
109271
109327
  ],
109272
109328
  "name": "rule-style"
109273
109329
  },
109330
+ {
109331
+ "longhands": [
109332
+ "column-rule-visibility-items",
109333
+ "row-rule-visibility-items"
109334
+ ],
109335
+ "name": "rule-visibility-items"
109336
+ },
109274
109337
  {
109275
109338
  "longhands": [
109276
109339
  "column-rule-width",
@@ -111373,6 +111436,15 @@ const generatedPropertyValues = {
111373
111436
  "preserve-parent-color"
111374
111437
  ]
111375
111438
  },
111439
+ "frame-sizing": {
111440
+ "values": [
111441
+ "auto",
111442
+ "content-width",
111443
+ "content-height",
111444
+ "content-block-size",
111445
+ "content-inline-size"
111446
+ ]
111447
+ },
111376
111448
  "gap-rule-overlap": {
111377
111449
  "values": [
111378
111450
  "row-over-column",
@@ -111469,6 +111541,13 @@ const generatedPropertyValues = {
111469
111541
  "auto"
111470
111542
  ]
111471
111543
  },
111544
+ "image-animation": {
111545
+ "values": [
111546
+ "normal",
111547
+ "running",
111548
+ "paused"
111549
+ ]
111550
+ },
111472
111551
  "image-rendering": {
111473
111552
  "values": [
111474
111553
  "auto",
@@ -118069,6 +118148,10 @@ class CSSMatchedStyles {
118069
118148
  const domCascade = this.#styleToDOMCascade.get(property.ownerStyle);
118070
118149
  return domCascade ? domCascade.propertyState(property) : null;
118071
118150
  }
118151
+ isPropertyOverriddenByAnimation(property) {
118152
+ const domCascade = this.#styleToDOMCascade.get(property.ownerStyle);
118153
+ return domCascade?.isPropertyOverriddenByAnimation(property) ?? false;
118154
+ }
118072
118155
  resetActiveProperties() {
118073
118156
  assertNotNullOrUndefined(this.#mainDOMCascade);
118074
118157
  assertNotNullOrUndefined(this.#pseudoDOMCascades);
@@ -118119,6 +118202,7 @@ class NodeCascade {
118119
118202
  styles;
118120
118203
  #isInherited;
118121
118204
  propertiesState = new Map();
118205
+ propertiesOverriddenByAnimation = new Set();
118122
118206
  activeProperties = new Map();
118123
118207
  #node;
118124
118208
  constructor(matchedStyles, styles, node, isInherited, isHighlightPseudoCascade = false) {
@@ -118130,6 +118214,7 @@ class NodeCascade {
118130
118214
  }
118131
118215
  computeActiveProperties() {
118132
118216
  this.propertiesState.clear();
118217
+ this.propertiesOverriddenByAnimation.clear();
118133
118218
  this.activeProperties.clear();
118134
118219
  for (let i = this.styles.length - 1; i >= 0; i--) {
118135
118220
  const style = this.styles[i];
@@ -118214,6 +118299,10 @@ class NodeCascade {
118214
118299
  }
118215
118300
  if (activeProperty) {
118216
118301
  this.propertiesState.set(activeProperty, "Overloaded" );
118302
+ if (propertyWithHigherSpecificity.ownerStyle.type === Type$3.Animation ||
118303
+ propertyWithHigherSpecificity.ownerStyle.type === Type$3.Transition) {
118304
+ this.propertiesOverriddenByAnimation.add(activeProperty);
118305
+ }
118217
118306
  }
118218
118307
  this.propertiesState.set(propertyWithHigherSpecificity, "Active" );
118219
118308
  this.activeProperties.set(canonicalName, propertyWithHigherSpecificity);
@@ -118294,6 +118383,7 @@ function* forEach(array, startAfter) {
118294
118383
  }
118295
118384
  class DOMInheritanceCascade {
118296
118385
  #propertiesState = new Map();
118386
+ #propertiesOverriddenByAnimation = new Set();
118297
118387
  #availableCSSVariables = new Map();
118298
118388
  #computedCSSVariables = new Map();
118299
118389
  #styleToNodeCascade = new Map();
@@ -118604,9 +118694,14 @@ class DOMInheritanceCascade {
118604
118694
  this.ensureInitialized();
118605
118695
  return this.#propertiesState.get(property) || null;
118606
118696
  }
118697
+ isPropertyOverriddenByAnimation(property) {
118698
+ this.ensureInitialized();
118699
+ return this.#propertiesOverriddenByAnimation.has(property);
118700
+ }
118607
118701
  reset() {
118608
118702
  this.#initialized = false;
118609
118703
  this.#propertiesState.clear();
118704
+ this.#propertiesOverriddenByAnimation.clear();
118610
118705
  this.#availableCSSVariables.clear();
118611
118706
  this.#computedCSSVariables.clear();
118612
118707
  }
@@ -118621,11 +118716,20 @@ class DOMInheritanceCascade {
118621
118716
  for (const [property, state] of nodeCascade.propertiesState) {
118622
118717
  if (state === "Overloaded" ) {
118623
118718
  this.#propertiesState.set(property, "Overloaded" );
118719
+ if (nodeCascade.propertiesOverriddenByAnimation.has(property)) {
118720
+ this.#propertiesOverriddenByAnimation.add(property);
118721
+ }
118624
118722
  continue;
118625
118723
  }
118626
118724
  const canonicalName = cssMetadata().canonicalPropertyName(property.name);
118627
118725
  if (activeProperties.has(canonicalName)) {
118628
118726
  this.#propertiesState.set(property, "Overloaded" );
118727
+ const activeProperty = activeProperties.get(canonicalName);
118728
+ if (activeProperty &&
118729
+ (activeProperty.ownerStyle.type === Type$3.Animation ||
118730
+ activeProperty.ownerStyle.type === Type$3.Transition)) {
118731
+ this.#propertiesOverriddenByAnimation.add(property);
118732
+ }
118629
118733
  continue;
118630
118734
  }
118631
118735
  activeProperties.set(canonicalName, property);
@@ -120210,6 +120314,7 @@ class NetworkRequest extends ObjectWrapper {
120210
120314
  #exemptedResponseCookies = [];
120211
120315
  #responseCookiesPartitionKey = null;
120212
120316
  #responseCookiesPartitionKeyOpaque = null;
120317
+ #deviceBoundSessionUsages = [];
120213
120318
  #siteHasCookieInOtherPartition = false;
120214
120319
  localizedFailDescription = null;
120215
120320
  #url;
@@ -121163,6 +121268,7 @@ class NetworkRequest extends ObjectWrapper {
121163
121268
  this.setRequestHeaders(extraRequestInfo.requestHeaders);
121164
121269
  this.#hasExtraRequestInfo = true;
121165
121270
  this.setRequestHeadersText('');
121271
+ this.#deviceBoundSessionUsages = extraRequestInfo.deviceBoundSessionUsages || [];
121166
121272
  this.#clientSecurityState = extraRequestInfo.clientSecurityState;
121167
121273
  this.#appliedNetworkConditionsId = extraRequestInfo.appliedNetworkConditionsId;
121168
121274
  if (extraRequestInfo.connectTiming) {
@@ -121174,6 +121280,9 @@ class NetworkRequest extends ObjectWrapper {
121174
121280
  setAppliedNetworkConditions(appliedNetworkConditionsId) {
121175
121281
  this.#appliedNetworkConditionsId = appliedNetworkConditionsId;
121176
121282
  }
121283
+ getDeviceBoundSessionUsages() {
121284
+ return this.#deviceBoundSessionUsages;
121285
+ }
121177
121286
  hasExtraRequestInfo() {
121178
121287
  return this.#hasExtraRequestInfo;
121179
121288
  }
@@ -122484,7 +122593,7 @@ class NetworkDispatcher {
122484
122593
  }
122485
122594
  requestIntercepted({}) {
122486
122595
  }
122487
- requestWillBeSentExtraInfo({ requestId, associatedCookies, headers, clientSecurityState, connectTiming, siteHasCookieInOtherPartition, appliedNetworkConditionsId }) {
122596
+ requestWillBeSentExtraInfo({ requestId, associatedCookies, headers, deviceBoundSessionUsages, clientSecurityState, connectTiming, siteHasCookieInOtherPartition, appliedNetworkConditionsId }) {
122488
122597
  const blockedRequestCookies = [];
122489
122598
  const includedRequestCookies = [];
122490
122599
  for (const { blockedReasons, exemptionReason, cookie } of associatedCookies) {
@@ -122499,6 +122608,7 @@ class NetworkDispatcher {
122499
122608
  blockedRequestCookies,
122500
122609
  includedRequestCookies,
122501
122610
  requestHeaders: this.headersMapToHeadersArray(headers),
122611
+ deviceBoundSessionUsages,
122502
122612
  clientSecurityState,
122503
122613
  connectTiming,
122504
122614
  siteHasCookieInOtherPartition,
@@ -124108,14 +124218,19 @@ function decode(sourceMap, options = DEFAULT_DECODE_OPTIONS) {
124108
124218
  return decodeMap(sourceMap, opts);
124109
124219
  }
124110
124220
  function decodeMap(sourceMap, options) {
124111
- if (!sourceMap.scopes || !sourceMap.names)
124112
- return { scopes: [], ranges: [] };
124221
+ if (!sourceMap.scopes || !sourceMap.names) {
124222
+ return { scopes: [], ranges: [], hasVariableAndBindingInfo: false };
124223
+ }
124113
124224
  return new Decoder(sourceMap.scopes, sourceMap.names, options).decode();
124114
124225
  }
124115
124226
  function decodeIndexMap(sourceMap, options) {
124116
- const scopeInfo = { scopes: [], ranges: [] };
124227
+ const scopeInfo = {
124228
+ scopes: [],
124229
+ ranges: [],
124230
+ hasVariableAndBindingInfo: false,
124231
+ };
124117
124232
  for (const section of sourceMap.sections) {
124118
- const { scopes, ranges } = decode(section.map, {
124233
+ const { scopes, ranges, hasVariableAndBindingInfo } = decode(section.map, {
124119
124234
  ...options,
124120
124235
  generatedOffset: section.offset,
124121
124236
  });
@@ -124123,6 +124238,7 @@ function decodeIndexMap(sourceMap, options) {
124123
124238
  scopeInfo.scopes.push(scope);
124124
124239
  for (const range of ranges)
124125
124240
  scopeInfo.ranges.push(range);
124241
+ scopeInfo.hasVariableAndBindingInfo ||= hasVariableAndBindingInfo;
124126
124242
  }
124127
124243
  return scopeInfo;
124128
124244
  }
@@ -124150,6 +124266,8 @@ class Decoder {
124150
124266
  #rangeStack = [];
124151
124267
  #flatOriginalScopes = [];
124152
124268
  #subRangeBindingsForRange = new Map();
124269
+ #seenOriginalScopeVariables = false;
124270
+ #seenGeneratedRangeBindings = false;
124153
124271
  constructor(scopes, names, options) {
124154
124272
  this.#encodedScopes = scopes;
124155
124273
  this.#names = names;
@@ -124187,6 +124305,7 @@ class Decoder {
124187
124305
  variableIdxs.push(iter.nextSignedVLQ());
124188
124306
  }
124189
124307
  this.#handleOriginalScopeVariablesItem(variableIdxs);
124308
+ this.#seenOriginalScopeVariables = true;
124190
124309
  break;
124191
124310
  }
124192
124311
  case 2 : {
@@ -124229,6 +124348,7 @@ class Decoder {
124229
124348
  valueIdxs.push(iter.nextUnsignedVLQ());
124230
124349
  }
124231
124350
  this.#handleGeneratedRangeBindingsItem(valueIdxs);
124351
+ this.#seenGeneratedRangeBindings = true;
124232
124352
  break;
124233
124353
  }
124234
124354
  case 7 : {
@@ -124242,6 +124362,7 @@ class Decoder {
124242
124362
  ]);
124243
124363
  }
124244
124364
  this.#recordGeneratedSubRangeBindingItem(variableIndex, bindings);
124365
+ this.#seenGeneratedRangeBindings = true;
124245
124366
  break;
124246
124367
  }
124247
124368
  case 8 : {
@@ -124268,10 +124389,17 @@ class Decoder {
124268
124389
  if (this.#rangeStack.length > 0) {
124269
124390
  this.#throwInStrictMode("Encountered GENERATED_RANGE_START without matching END!");
124270
124391
  }
124271
- const info = { scopes: this.#scopes, ranges: this.#ranges };
124392
+ const info = {
124393
+ scopes: this.#scopes,
124394
+ ranges: this.#ranges,
124395
+ hasVariableAndBindingInfo: this.#seenOriginalScopeVariables &&
124396
+ this.#seenGeneratedRangeBindings,
124397
+ };
124272
124398
  this.#scopes = [];
124273
124399
  this.#ranges = [];
124274
124400
  this.#flatOriginalScopes = [];
124401
+ this.#seenOriginalScopeVariables = false;
124402
+ this.#seenGeneratedRangeBindings = false;
124275
124403
  return info;
124276
124404
  }
124277
124405
  #throwInStrictMode(message) {
@@ -125107,7 +125235,8 @@ class SourceMapScopesInfo {
125107
125235
  return Boolean(this.#originalScopes[sourceIdx]);
125108
125236
  }
125109
125237
  isEmpty() {
125110
- return !this.#originalScopes.length && !this.#generatedRanges.length;
125238
+ const noScopes = this.#originalScopes.every(scope => scope === null);
125239
+ return noScopes && !this.#generatedRanges.length;
125111
125240
  }
125112
125241
  addOriginalScopesAtIndex(sourceIdx, scope) {
125113
125242
  if (!this.#originalScopes[sourceIdx]) {
@@ -137865,28 +137994,22 @@ class DebuggableFrameImpl {
137865
137994
  // Copyright 2025 The Chromium Authors
137866
137995
  class DebuggableFrameFlavor {
137867
137996
  static #last;
137868
- url;
137869
- uiSourceCode;
137870
- name;
137871
- line;
137872
- column;
137873
- missingDebugInfo;
137874
- sdkFrame;
137997
+ frame;
137998
+ #missingDebugInfo;
137875
137999
  constructor(frame) {
137876
- this.url = frame.url;
137877
- this.uiSourceCode = frame.uiSourceCode;
137878
- this.name = frame.name;
137879
- this.line = frame.line;
137880
- this.column = frame.column;
137881
- this.missingDebugInfo = frame.missingDebugInfo;
137882
- this.sdkFrame = frame.sdkFrame;
138000
+ this.frame = frame;
138001
+ this.#missingDebugInfo = frame.sdkFrame.missingDebugInfoDetails;
138002
+ }
138003
+ get sdkFrame() {
138004
+ return this.frame.sdkFrame;
137883
138005
  }
137884
138006
  static for(frame) {
137885
138007
  function equals(a, b) {
137886
138008
  return a.url === b.url && a.uiSourceCode === b.uiSourceCode && a.name === b.name && a.line === b.line &&
137887
138009
  a.column === b.column && a.sdkFrame === b.sdkFrame;
137888
138010
  }
137889
- if (!DebuggableFrameFlavor.#last || !equals(DebuggableFrameFlavor.#last, frame)) {
138011
+ if (!DebuggableFrameFlavor.#last || !equals(DebuggableFrameFlavor.#last.frame, frame) ||
138012
+ DebuggableFrameFlavor.#last.#missingDebugInfo !== frame.sdkFrame.missingDebugInfoDetails) {
137890
138013
  DebuggableFrameFlavor.#last = new DebuggableFrameFlavor(frame);
137891
138014
  }
137892
138015
  return DebuggableFrameFlavor.#last;
@@ -140654,8 +140777,6 @@ const UIStrings$L = {
140654
140777
  loadedDebugSymbolsForButDidnt: '[{PH1}] Loaded debug symbols for {PH2}, but didn\'t find any source files',
140655
140778
  loadedDebugSymbolsForFound: '[{PH1}] Loaded debug symbols for {PH2}, found {PH3} source file(s)',
140656
140779
  failedToLoadDebugSymbolsFor: '[{PH1}] Failed to load debug symbols for {PH2} ({PH3})',
140657
- failedToLoadDebugSymbolsForFunction: 'No debug information for function "{PH1}"',
140658
- debugSymbolsIncomplete: 'The debug information for function {PH1} is incomplete',
140659
140780
  };
140660
140781
  const str_$K = registerUIStrings('models/bindings/DebuggerLanguagePlugins.ts', UIStrings$L);
140661
140782
  const i18nString$x = getLocalizedString.bind(undefined, str_$K);
@@ -141000,16 +141121,14 @@ class DebuggerLanguagePluginManager {
141000
141121
  return functionInfo.frames.map(({ name }, index) => callFrame.createVirtualCallFrame(index, name));
141001
141122
  }
141002
141123
  if ('missingSymbolFiles' in functionInfo && functionInfo.missingSymbolFiles.length) {
141003
- const resources = functionInfo.missingSymbolFiles;
141004
- const details = i18nString$x(UIStrings$L.debugSymbolsIncomplete, { PH1: callFrame.functionName });
141005
- callFrame.missingDebugInfoDetails = { details, resources };
141006
- }
141007
- else {
141008
141124
  callFrame.missingDebugInfoDetails = {
141009
- details: i18nString$x(UIStrings$L.failedToLoadDebugSymbolsForFunction, { PH1: callFrame.functionName }),
141010
- resources: [],
141125
+ type: "PARTIAL_INFO" ,
141126
+ missingDebugFiles: functionInfo.missingSymbolFiles,
141011
141127
  };
141012
141128
  }
141129
+ else {
141130
+ callFrame.missingDebugInfoDetails = { type: "NO_INFO" };
141131
+ }
141013
141132
  }
141014
141133
  return callFrame;
141015
141134
  }))
@@ -141209,23 +141328,13 @@ class DebuggerLanguagePluginManager {
141209
141328
  const framePromises = functionInfo.frames.map(async ({ name }, index) => {
141210
141329
  const rawLocation = new Location$1(script.debuggerModel, script.scriptId, frame.lineNumber, frame.columnNumber, index);
141211
141330
  const uiLocation = await this.rawLocationToUILocation(rawLocation);
141212
- return {
141213
- uiSourceCode: uiLocation?.uiSourceCode,
141214
- url: uiLocation ? undefined : frame.url,
141215
- name,
141216
- line: uiLocation?.lineNumber ?? frame.lineNumber,
141217
- column: uiLocation?.columnNumber ?? frame.columnNumber,
141218
- };
141331
+ return translatedFromUILocation(uiLocation, name, frame);
141219
141332
  });
141220
141333
  translatedFrames.push(await Promise.all(framePromises));
141221
141334
  return true;
141222
141335
  }
141223
- const mappedFrame = {
141224
- url: frame.url,
141225
- name: frame.functionName,
141226
- line: frame.lineNumber,
141227
- column: frame.columnNumber,
141228
- };
141336
+ const uiLocation = await this.#debuggerWorkspaceBinding.rawLocationToUILocation(new Location$1(script.debuggerModel, script.scriptId, frame.lineNumber, frame.columnNumber));
141337
+ const mappedFrame = translatedFromUILocation(uiLocation, frame.functionName, frame);
141229
141338
  if ('missingSymbolFiles' in functionInfo && functionInfo.missingSymbolFiles.length) {
141230
141339
  translatedFrames.push([{
141231
141340
  ...mappedFrame,
@@ -141244,6 +141353,24 @@ class DebuggerLanguagePluginManager {
141244
141353
  }]);
141245
141354
  }
141246
141355
  return true;
141356
+ function translatedFromUILocation(uiLocation, name, fallback) {
141357
+ if (uiLocation) {
141358
+ return {
141359
+ uiSourceCode: uiLocation.uiSourceCode,
141360
+ url: undefined,
141361
+ name,
141362
+ line: uiLocation.lineNumber,
141363
+ column: uiLocation.columnNumber ?? -1,
141364
+ };
141365
+ }
141366
+ return {
141367
+ uiSourceCode: undefined,
141368
+ url: fallback.url,
141369
+ name: fallback.functionName,
141370
+ line: fallback.lineNumber,
141371
+ column: fallback.columnNumber,
141372
+ };
141373
+ }
141247
141374
  }
141248
141375
  scriptsForUISourceCode(uiSourceCode) {
141249
141376
  for (const modelData of this.#debuggerModelToData.values()) {
@@ -141321,14 +141448,12 @@ class DebuggerLanguagePluginManager {
141321
141448
  rawModuleHandle.scripts.push(script);
141322
141449
  }
141323
141450
  void rawModuleHandle.addRawModulePromise.then(sourceFileURLs => {
141324
- if (!('missingSymbolFiles' in sourceFileURLs)) {
141325
- if (script.debuggerModel.scriptForId(script.scriptId) === script) {
141326
- const modelData = this.#debuggerModelToData.get(script.debuggerModel);
141327
- if (modelData) {
141328
- modelData.addSourceFiles(script, sourceFileURLs);
141329
- void this.#debuggerWorkspaceBinding.updateLocations(script);
141330
- }
141451
+ if (script.debuggerModel.scriptForId(script.scriptId) === script) {
141452
+ const modelData = this.#debuggerModelToData.get(script.debuggerModel);
141453
+ if (modelData && Array.isArray(sourceFileURLs)) {
141454
+ modelData.addSourceFiles(script, sourceFileURLs);
141331
141455
  }
141456
+ void this.#debuggerWorkspaceBinding.updateLocations(script);
141332
141457
  }
141333
141458
  });
141334
141459
  return;
@@ -194,7 +194,6 @@ export const fill = defineTool({
194
194
  },
195
195
  handler: async (request, response, context) => {
196
196
  await context.waitForEventsAfterAction(async () => {
197
- await context.getSelectedPage().keyboard.type(request.params.value);
198
197
  await fillFormElement(request.params.uid, request.params.value, context);
199
198
  });
200
199
  response.appendResponseLine(`Successfully filled out the element`);
@@ -92,7 +92,7 @@ export const newPage = defineTool({
92
92
  await page.goto(request.params.url, {
93
93
  timeout: request.params.timeout,
94
94
  });
95
- });
95
+ }, { timeout: request.params.timeout });
96
96
  response.setIncludePages(true);
97
97
  },
98
98
  });
@@ -201,7 +201,7 @@ export const navigatePage = defineTool({
201
201
  }
202
202
  break;
203
203
  }
204
- });
204
+ }, { timeout: request.params.timeout });
205
205
  }
206
206
  finally {
207
207
  page.off('dialog', dialogHandler);
@@ -8,8 +8,8 @@ import { ToolCategory } from './categories.js';
8
8
  import { defineTool } from './ToolDefinition.js';
9
9
  export const evaluateScript = defineTool({
10
10
  name: 'evaluate_script',
11
- description: `Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON
12
- so returned values have to JSON-serializable.`,
11
+ description: `Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,
12
+ so returned values have to be JSON-serializable.`,
13
13
  annotations: {
14
14
  category: ToolCategory.DEBUGGING,
15
15
  readOnlyHint: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-devtools-mcp",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "MCP server for Chrome DevTools",
5
5
  "type": "module",
6
6
  "bin": "./build/src/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:update-snapshots": "npm run build && node scripts/test.mjs --test-update-snapshots",
23
23
  "prepare": "node --experimental-strip-types scripts/prepare.ts",
24
24
  "verify-server-json-version": "node --experimental-strip-types scripts/verify-server-json-version.ts",
25
- "eval": "npm run build && node --experimental-strip-types scripts/eval_gemini.ts",
25
+ "eval": "npm run build && CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS=true node --experimental-strip-types scripts/eval_gemini.ts",
26
26
  "count-tokens": "node --experimental-strip-types scripts/count_tokens.ts"
27
27
  },
28
28
  "files": [
@@ -54,7 +54,7 @@
54
54
  "@types/yargs": "^17.0.33",
55
55
  "@typescript-eslint/eslint-plugin": "^8.43.0",
56
56
  "@typescript-eslint/parser": "^8.43.0",
57
- "chrome-devtools-frontend": "1.0.1575174",
57
+ "chrome-devtools-frontend": "1.0.1576915",
58
58
  "core-js": "3.48.0",
59
59
  "debug": "4.4.3",
60
60
  "eslint": "^9.35.0",
@@ -63,7 +63,7 @@
63
63
  "globals": "^17.0.0",
64
64
  "prettier": "^3.6.2",
65
65
  "puppeteer": "24.36.1",
66
- "rollup": "4.57.0",
66
+ "rollup": "4.57.1",
67
67
  "rollup-plugin-cleanup": "^3.2.1",
68
68
  "rollup-plugin-license": "^3.6.0",
69
69
  "sinon": "^21.0.0",