chrome-devtools-mcp 1.2.0 → 1.3.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 +22 -2
- package/build/src/HeapSnapshotManager.js +25 -16
- package/build/src/McpContext.js +35 -1
- package/build/src/McpResponse.js +77 -7
- package/build/src/PageCollector.js +1 -1
- package/build/src/bin/chrome-devtools-cli-options.js +84 -0
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +45 -1
- package/build/src/{DevToolsConnectionAdapter.js → devtools/DevToolsConnectionAdapter.js} +1 -1
- package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +75 -71
- package/build/src/devtools/McpHostBindingAdapter.js +165 -0
- package/build/src/formatters/ConsoleFormatter.js +1 -1
- package/build/src/formatters/HeapSnapshotFormatter.js +22 -0
- package/build/src/third_party/THIRD_PARTY_NOTICES +2 -2
- package/build/src/third_party/bundled-packages.json +1 -1
- package/build/src/third_party/devtools-formatter-worker.js +0 -1
- package/build/src/third_party/devtools-heap-snapshot-worker.js +54 -3
- package/build/src/third_party/index.js +449 -196
- package/build/src/tools/memory.js +76 -0
- package/build/src/tools/screencast.js +30 -9
- package/build/src/tools/screenshot.js +158 -76
- package/build/src/version.js +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
7
|
+
import { DevTools } from '../third_party/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* BaseClass that is noop or throws for methods.
|
|
10
|
+
* the McpHostBindingAdapter should only implement methods
|
|
11
|
+
* that it needs to support.
|
|
12
|
+
*/
|
|
13
|
+
class BaseMcpHostBindingAdapter {
|
|
14
|
+
connectAutomaticFileSystem() { }
|
|
15
|
+
disconnectAutomaticFileSystem() { }
|
|
16
|
+
addFileSystem() { }
|
|
17
|
+
loadCompleted() { }
|
|
18
|
+
indexPath() { }
|
|
19
|
+
setInspectedPageBounds() { }
|
|
20
|
+
showCertificateViewer() { }
|
|
21
|
+
setWhitelistedShortcuts() { }
|
|
22
|
+
setEyeDropperActive() { }
|
|
23
|
+
inspectElementCompleted() { }
|
|
24
|
+
openInNewTab() { }
|
|
25
|
+
openSearchResultsInNewTab() { }
|
|
26
|
+
showItemInFolder() { }
|
|
27
|
+
removeFileSystem() { }
|
|
28
|
+
requestFileSystems() { }
|
|
29
|
+
save() { }
|
|
30
|
+
append() { }
|
|
31
|
+
close() { }
|
|
32
|
+
searchInPath() { }
|
|
33
|
+
stopIndexing() { }
|
|
34
|
+
bringToFront() { }
|
|
35
|
+
closeWindow() { }
|
|
36
|
+
copyText() { }
|
|
37
|
+
inspectedURLChanged() { }
|
|
38
|
+
isolatedFileSystem() {
|
|
39
|
+
throw new Error('Not implemented');
|
|
40
|
+
}
|
|
41
|
+
registerPreference() { }
|
|
42
|
+
getPreferences() { }
|
|
43
|
+
getPreference() { }
|
|
44
|
+
setPreference() { }
|
|
45
|
+
removePreference() { }
|
|
46
|
+
clearPreferences() { }
|
|
47
|
+
getSyncInformation() { }
|
|
48
|
+
getHostConfig() { }
|
|
49
|
+
upgradeDraggedFileSystemPermissions() { }
|
|
50
|
+
platform() {
|
|
51
|
+
throw new Error('Not implemented');
|
|
52
|
+
}
|
|
53
|
+
recordCountHistogram() { }
|
|
54
|
+
recordEnumeratedHistogram() { }
|
|
55
|
+
recordPerformanceHistogram() { }
|
|
56
|
+
recordPerformanceHistogramMedium() { }
|
|
57
|
+
recordUserMetricsAction() { }
|
|
58
|
+
recordNewBadgeUsage() { }
|
|
59
|
+
sendMessageToBackend() { }
|
|
60
|
+
setDevicesDiscoveryConfig() { }
|
|
61
|
+
setDevicesUpdatesEnabled() { }
|
|
62
|
+
openRemotePage() { }
|
|
63
|
+
openNodeFrontend() { }
|
|
64
|
+
setInjectedScriptForOrigin() { }
|
|
65
|
+
setIsDocked() { }
|
|
66
|
+
showSurvey() { }
|
|
67
|
+
canShowSurvey() { }
|
|
68
|
+
zoomFactor() {
|
|
69
|
+
throw new Error('Not implemented');
|
|
70
|
+
}
|
|
71
|
+
zoomIn() { }
|
|
72
|
+
zoomOut() { }
|
|
73
|
+
resetZoom() { }
|
|
74
|
+
showContextMenuAtPoint() { }
|
|
75
|
+
reattach() { }
|
|
76
|
+
readyForTest() { }
|
|
77
|
+
connectionReady() { }
|
|
78
|
+
setOpenNewWindowForPopups() { }
|
|
79
|
+
isHostedMode() {
|
|
80
|
+
throw new Error('Not implemented');
|
|
81
|
+
}
|
|
82
|
+
setAddExtensionCallback() { }
|
|
83
|
+
initialTargetId() {
|
|
84
|
+
throw new Error('Not implemented');
|
|
85
|
+
}
|
|
86
|
+
doAidaConversation(_request, _streamId, cb) {
|
|
87
|
+
cb({
|
|
88
|
+
error: 'Not implemented',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
registerAidaClientEvent(_request, cb) {
|
|
92
|
+
cb({
|
|
93
|
+
error: 'Not implemented',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
aidaCodeComplete(_request, cb) {
|
|
97
|
+
cb({
|
|
98
|
+
error: 'Not implemented',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
dispatchHttpRequest(_request, cb) {
|
|
102
|
+
cb({
|
|
103
|
+
error: 'Not implemented',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
recordImpression() { }
|
|
107
|
+
recordResize() { }
|
|
108
|
+
recordClick() { }
|
|
109
|
+
recordHover() { }
|
|
110
|
+
recordDrag() { }
|
|
111
|
+
recordChange() { }
|
|
112
|
+
recordKeyDown() { }
|
|
113
|
+
recordSettingAccess() { }
|
|
114
|
+
recordFunctionCall() { }
|
|
115
|
+
setChromeFlag() { }
|
|
116
|
+
requestRestart() { }
|
|
117
|
+
loadNetworkResource(_urlString, _headers, _streamId, _callback) { }
|
|
118
|
+
}
|
|
119
|
+
export class McpHostBindingAdapter extends BaseMcpHostBindingAdapter {
|
|
120
|
+
#loadResource;
|
|
121
|
+
constructor(loadResource) {
|
|
122
|
+
super();
|
|
123
|
+
this.#loadResource = loadResource;
|
|
124
|
+
}
|
|
125
|
+
isolatedFileSystem() {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
platform() {
|
|
129
|
+
switch (process.platform) {
|
|
130
|
+
case 'darwin':
|
|
131
|
+
return 'mac';
|
|
132
|
+
case 'win32':
|
|
133
|
+
return 'windows';
|
|
134
|
+
default:
|
|
135
|
+
return 'linux';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
zoomFactor() {
|
|
139
|
+
return 1;
|
|
140
|
+
}
|
|
141
|
+
isHostedMode() {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
initialTargetId() {
|
|
145
|
+
return Promise.resolve(null);
|
|
146
|
+
}
|
|
147
|
+
loadNetworkResource(urlString, _headers, streamId, callback) {
|
|
148
|
+
if (!URL.canParse(urlString)) {
|
|
149
|
+
callback({
|
|
150
|
+
statusCode: 404,
|
|
151
|
+
urlValid: false,
|
|
152
|
+
});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.#loadResource(urlString)
|
|
156
|
+
.then(content => {
|
|
157
|
+
DevTools.Host.ResourceLoader.streamWrite(streamId, content);
|
|
158
|
+
callback({ statusCode: 200 });
|
|
159
|
+
})
|
|
160
|
+
.catch(() => {
|
|
161
|
+
callback({ statusCode: 404 });
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=McpHostBindingAdapter.js.map
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { createStackTraceForConsoleMessage, SymbolizedError, } from '../DevtoolsUtils.js';
|
|
6
|
+
import { createStackTraceForConsoleMessage, SymbolizedError, } from '../devtools/DevtoolsUtils.js';
|
|
7
7
|
import { UncaughtError } from '../PageCollector.js';
|
|
8
8
|
import * as DevTools from '../third_party/index.js';
|
|
9
9
|
export class ConsoleFormatter {
|
|
@@ -45,6 +45,28 @@ export class HeapSnapshotFormatter {
|
|
|
45
45
|
}
|
|
46
46
|
return lines.join('\n');
|
|
47
47
|
}
|
|
48
|
+
static formatRetainingPaths(retainingPaths) {
|
|
49
|
+
const lines = [];
|
|
50
|
+
function formatEdge(edge, depth) {
|
|
51
|
+
const indent = ' '.repeat(depth);
|
|
52
|
+
lines.push(`${indent}<- @${edge.nodeId} ${edge.nodeName} via ${edge.edgeType} ${edge.edgeName} (distance: ${edge.distance})`);
|
|
53
|
+
for (const child of edge.children) {
|
|
54
|
+
formatEdge(child, depth + 1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const path of retainingPaths) {
|
|
58
|
+
formatEdge(path, 0);
|
|
59
|
+
}
|
|
60
|
+
return lines.join('\n');
|
|
61
|
+
}
|
|
62
|
+
static formatDominators(dominators) {
|
|
63
|
+
const lines = [];
|
|
64
|
+
lines.push('nodeId,nodeName,selfSize,retainedSize');
|
|
65
|
+
for (const node of dominators) {
|
|
66
|
+
lines.push(`${node.nodeId},${node.nodeName},${DevTools.I18n.ByteUtilities.formatBytesToKb(node.selfSize)},${DevTools.I18n.ByteUtilities.formatBytesToKb(node.retainedSize)}`);
|
|
67
|
+
}
|
|
68
|
+
return lines.join('\n');
|
|
69
|
+
}
|
|
48
70
|
#getSortedAggregates() {
|
|
49
71
|
return Object.values(this.#aggregates).sort((a, b) => b.maxRet - a.maxRet);
|
|
50
72
|
}
|
|
@@ -324,7 +324,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE
|
|
|
324
324
|
|
|
325
325
|
Name: semver
|
|
326
326
|
URL: git+https://github.com/npm/node-semver.git
|
|
327
|
-
Version: 7.8.
|
|
327
|
+
Version: 7.8.3
|
|
328
328
|
License: ISC
|
|
329
329
|
|
|
330
330
|
The ISC License
|
|
@@ -910,7 +910,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
910
910
|
|
|
911
911
|
Name: @toon-format/toon
|
|
912
912
|
URL: https://toonformat.dev
|
|
913
|
-
Version: 2.
|
|
913
|
+
Version: 2.3.0
|
|
914
914
|
License: MIT
|
|
915
915
|
|
|
916
916
|
MIT License
|
|
@@ -2645,7 +2645,6 @@ var ExperimentName;
|
|
|
2645
2645
|
ExperimentName["ALL"] = "*";
|
|
2646
2646
|
ExperimentName["PROTOCOL_MONITOR"] = "protocol-monitor";
|
|
2647
2647
|
ExperimentName["INSTRUMENTATION_BREAKPOINTS"] = "instrumentation-breakpoints";
|
|
2648
|
-
ExperimentName["USE_SOURCE_MAP_SCOPES"] = "use-source-map-scopes";
|
|
2649
2648
|
ExperimentName["DURABLE_MESSAGES"] = "durable-messages";
|
|
2650
2649
|
ExperimentName["JPEG_XL"] = "jpeg-xl";
|
|
2651
2650
|
ExperimentName["PLUS_BUTTON"] = "plus-button";
|
|
@@ -642,10 +642,14 @@ class Diff {
|
|
|
642
642
|
removedCount = 0;
|
|
643
643
|
addedSize = 0;
|
|
644
644
|
removedSize = 0;
|
|
645
|
-
deletedIndexes = [];
|
|
646
|
-
addedIndexes = [];
|
|
647
645
|
countDelta;
|
|
648
646
|
sizeDelta;
|
|
647
|
+
addedIndexes = [];
|
|
648
|
+
addedIds = [];
|
|
649
|
+
addedSelfSizes = [];
|
|
650
|
+
deletedIndexes = [];
|
|
651
|
+
deletedIds = [];
|
|
652
|
+
deletedSelfSizes = [];
|
|
649
653
|
constructor(name) {
|
|
650
654
|
this.name = name;
|
|
651
655
|
}
|
|
@@ -2840,7 +2844,6 @@ var ExperimentName;
|
|
|
2840
2844
|
ExperimentName["ALL"] = "*";
|
|
2841
2845
|
ExperimentName["PROTOCOL_MONITOR"] = "protocol-monitor";
|
|
2842
2846
|
ExperimentName["INSTRUMENTATION_BREAKPOINTS"] = "instrumentation-breakpoints";
|
|
2843
|
-
ExperimentName["USE_SOURCE_MAP_SCOPES"] = "use-source-map-scopes";
|
|
2844
2847
|
ExperimentName["DURABLE_MESSAGES"] = "durable-messages";
|
|
2845
2848
|
ExperimentName["JPEG_XL"] = "jpeg-xl";
|
|
2846
2849
|
ExperimentName["PLUS_BUTTON"] = "plus-button";
|
|
@@ -5936,6 +5939,9 @@ class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
5936
5939
|
nodeClassKey(snapshotObjectId) {
|
|
5937
5940
|
return this.callMethodPromise('nodeClassKey', snapshotObjectId);
|
|
5938
5941
|
}
|
|
5942
|
+
nodeIndexForId(nodeId) {
|
|
5943
|
+
return this.callMethodPromise('nodeIndexForId', nodeId);
|
|
5944
|
+
}
|
|
5939
5945
|
createEdgesProvider(nodeIndex) {
|
|
5940
5946
|
return this.callFactoryMethod('createEdgesProvider', HeapSnapshotProviderProxy, nodeIndex);
|
|
5941
5947
|
}
|
|
@@ -5996,6 +6002,9 @@ class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
5996
6002
|
getRetainingPaths(nodeIndex, maxDepth, maxNodes, maxSiblings) {
|
|
5997
6003
|
return this.callMethodPromise('getRetainingPaths', nodeIndex, maxDepth, maxNodes, maxSiblings);
|
|
5998
6004
|
}
|
|
6005
|
+
getDominatorsOf(nodeIndex) {
|
|
6006
|
+
return this.callMethodPromise('getDominatorsOf', nodeIndex);
|
|
6007
|
+
}
|
|
5999
6008
|
unignoreNodeInRetainersView(nodeIndex) {
|
|
6000
6009
|
return this.callMethodPromise('unignoreNodeInRetainersView', nodeIndex);
|
|
6001
6010
|
}
|
|
@@ -7064,6 +7073,16 @@ class HeapSnapshot {
|
|
|
7064
7073
|
}
|
|
7065
7074
|
this.#progress.updateStatus('Finished processing.');
|
|
7066
7075
|
}
|
|
7076
|
+
nodeIndexForId(nodeId) {
|
|
7077
|
+
const nodesLength = this.nodes.length;
|
|
7078
|
+
const { nodes, nodeFieldCount, nodeIdOffset } = this;
|
|
7079
|
+
for (let nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
|
|
7080
|
+
if (nodes.getValue(nodeIndex + nodeIdOffset) === nodeId) {
|
|
7081
|
+
return nodeIndex;
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
return undefined;
|
|
7085
|
+
}
|
|
7067
7086
|
startInitStep1InSecondThread(secondWorker) {
|
|
7068
7087
|
const resultsFromSecondWorker = new Promise((resolve, reject) => {
|
|
7069
7088
|
const listener = (e) => {
|
|
@@ -8287,6 +8306,8 @@ class HeapSnapshot {
|
|
|
8287
8306
|
const nodeAId = baseIds[i];
|
|
8288
8307
|
if (nodeAId < nodeB.id()) {
|
|
8289
8308
|
diff.deletedIndexes.push(baseIndexes[i]);
|
|
8309
|
+
diff.deletedIds.push(nodeAId);
|
|
8310
|
+
diff.deletedSelfSizes.push(baseSelfSizes[i]);
|
|
8290
8311
|
diff.removedCount++;
|
|
8291
8312
|
diff.removedSize += baseSelfSizes[i];
|
|
8292
8313
|
++i;
|
|
@@ -8294,6 +8315,8 @@ class HeapSnapshot {
|
|
|
8294
8315
|
else if (nodeAId >
|
|
8295
8316
|
nodeB.id()) {
|
|
8296
8317
|
diff.addedIndexes.push(indexes[j]);
|
|
8318
|
+
diff.addedIds.push(nodeB.id());
|
|
8319
|
+
diff.addedSelfSizes.push(nodeB.selfSize());
|
|
8297
8320
|
diff.addedCount++;
|
|
8298
8321
|
diff.addedSize += nodeB.selfSize();
|
|
8299
8322
|
nodeB.nodeIndex = indexes[++j];
|
|
@@ -8305,12 +8328,16 @@ class HeapSnapshot {
|
|
|
8305
8328
|
}
|
|
8306
8329
|
while (i < l) {
|
|
8307
8330
|
diff.deletedIndexes.push(baseIndexes[i]);
|
|
8331
|
+
diff.deletedIds.push(baseIds[i]);
|
|
8332
|
+
diff.deletedSelfSizes.push(baseSelfSizes[i]);
|
|
8308
8333
|
diff.removedCount++;
|
|
8309
8334
|
diff.removedSize += baseSelfSizes[i];
|
|
8310
8335
|
++i;
|
|
8311
8336
|
}
|
|
8312
8337
|
while (j < m) {
|
|
8313
8338
|
diff.addedIndexes.push(indexes[j]);
|
|
8339
|
+
diff.addedIds.push(nodeB.id());
|
|
8340
|
+
diff.addedSelfSizes.push(nodeB.selfSize());
|
|
8314
8341
|
diff.addedCount++;
|
|
8315
8342
|
diff.addedSize += nodeB.selfSize();
|
|
8316
8343
|
nodeB.nodeIndex = indexes[++j];
|
|
@@ -8466,6 +8493,30 @@ class HeapSnapshot {
|
|
|
8466
8493
|
const paths = buildForest(nodeIndex, 0);
|
|
8467
8494
|
return { paths, limitsReached };
|
|
8468
8495
|
}
|
|
8496
|
+
getDominatorsOf(nodeIndex) {
|
|
8497
|
+
const chain = [];
|
|
8498
|
+
let currentIndex = nodeIndex;
|
|
8499
|
+
const rootIndex = this.rootNodeIndex;
|
|
8500
|
+
while (currentIndex !== undefined) {
|
|
8501
|
+
const node = this.createNode(currentIndex);
|
|
8502
|
+
chain.push({
|
|
8503
|
+
nodeId: node.id(),
|
|
8504
|
+
nodeIndex: currentIndex,
|
|
8505
|
+
nodeName: node.name(),
|
|
8506
|
+
retainedSize: node.retainedSize(),
|
|
8507
|
+
selfSize: node.selfSize(),
|
|
8508
|
+
});
|
|
8509
|
+
if (currentIndex === rootIndex) {
|
|
8510
|
+
break;
|
|
8511
|
+
}
|
|
8512
|
+
const nextIndex = node.dominatorIndex();
|
|
8513
|
+
if (nextIndex === currentIndex) {
|
|
8514
|
+
break;
|
|
8515
|
+
}
|
|
8516
|
+
currentIndex = nextIndex;
|
|
8517
|
+
}
|
|
8518
|
+
return chain;
|
|
8519
|
+
}
|
|
8469
8520
|
createAddedNodesProvider(baseSnapshotId, classKey) {
|
|
8470
8521
|
const snapshotDiff = this.#snapshotDiffs[baseSnapshotId];
|
|
8471
8522
|
const diffForClass = snapshotDiff[classKey];
|