chore(deps): update chrome-devtools-mcp to 1.10.1 (#162591)

This commit is contained in:
Vincent Koc 2026-10-02 04:43:15 +07:00 • committed by GitHub
parent 99567a65b7
commit abc3297745
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 268 additions and 60 deletions

View file

@ -144,7 +144,7 @@ Notes:
### Custom Chrome MCP launch
OpenClaw includes an exact-pinned Chrome DevTools MCP 1.9.0 dependency with a
OpenClaw includes an exact-pinned Chrome DevTools MCP 1.10.1 dependency with a
temporary document-identity patch and starts its CLI directly with the runtime
running OpenClaw, Node or Bun.
The npm package carries the patched dependency; source checkouts obtain it through

View file

@ -6,7 +6,7 @@
"type": "module",
"dependencies": {
"@modelcontextprotocol/sdk": "1.30.0",
"chrome-devtools-mcp": "1.9.0",
"chrome-devtools-mcp": "1.10.1",
"express": "5.2.1",
"playwright-core": "1.63.0",
"typebox": "1.3.34",

View file

@ -2,6 +2,7 @@ import path from "node:path";
import type { BrowserContext, Page } from "playwright-core";
import { afterEach, describe, expect, it } from "vitest";
import { useAutoCleanupTempDirTracker } from "../../test-support.js";
import { callTargetTool, resolveChromeMcpSnapshotRef } from "./chrome-mcp-routing.js";
import {
clickChromeMcpCoords,
clickChromeMcpElement,
@ -291,6 +292,69 @@ describe.runIf(process.env.OPENCLAW_BROWSER_MCP_E2E === "1")(
});
}, 120_000);
it("keeps CSS lookup bound to the captured renderer and document", async () => {
await withMcpBrowser(async ({ page, context, profile, profileName }) => {
const fixturePort = await getFreePort();
const mainUrl = `http://127.0.0.1:${fixturePort}/styles`;
const frameUrl = `http://localhost:${fixturePort}/frame`;
const replacementUrl = `http://localhost:${fixturePort}/replacement`;
await context.route(mainUrl, (route) =>
route.fulfill({
contentType: "text/html",
body: `<!doctype html><style>.top { color: red; }</style>${Array.from(
{ length: 64 },
(_, index) => `<button class="top">Top ${index}</button>`,
).join("")}<iframe src="${frameUrl}"></iframe>`,
}),
);
await context.route(frameUrl, (route) =>
route.fulfill({
contentType: "text/html",
body: `<!doctype html><style>.frame { color: blue; }</style>${Array.from(
{ length: 32 },
(_, index) => `<button class="frame">Frame ${index}</button>`,
).join("")}`,
}),
);
await context.route(replacementUrl, (route) =>
route.fulfill({
contentType: "text/html",
body: '<!doctype html><button class="replacement">Replacement</button>',
}),
);
await page.goto(mainUrl);
const [tab] = await listChromeMcpTabs(profileName, profile, { timeoutMs: 30_000 });
const target = {
profileName,
profile,
targetId: tab!.targetId,
timeoutMs: 10_000,
};
const snapshot = await takeChromeMcpSnapshot(target);
const topRef = snapshotRef(snapshot, "button", "Top 0");
const frameRef = snapshotRef(snapshot, "button", "Frame 0");
const cssArgs =
(ref: string) => (session: Parameters<typeof resolveChromeMcpSnapshotRef>[0]) => ({
uid: resolveChromeMcpSnapshotRef(session, target.targetId, ref).uid,
pageSize: 10,
pageIdx: 0,
});
await expect(
callTargetTool(target, "get_css_styles", cssArgs(topRef)),
).resolves.toBeDefined();
await expect(callTargetTool(target, "get_css_styles", cssArgs(frameRef))).rejects.toThrow(
/detached or no longer exists/,
);
await page.goto(replacementUrl);
await expect(callTargetTool(target, "get_css_styles", cssArgs(topRef))).rejects.toThrow(
/no longer exists/,
);
});
}, 120_000);
it("retires canceled session handles and reconnects to the same browser", async () => {
await withMcpBrowser(async ({ page, profile, profileName }) => {
await page.setContent(

View file

@ -2270,7 +2270,7 @@
"@trycua/cua-driver": "0.28.2",
"acorn": "8.18.0",
"chalk": "6.0.0",
"chrome-devtools-mcp": "1.9.0",
"chrome-devtools-mcp": "1.10.1",
"clawpdf": "0.3.2",
"commander": "15.0.0",
"croner": "10.0.1",

View file

@ -20,16 +20,16 @@ Remove the dropdown focus hunk when an upstream release passes `ui/src/e2e/chat-
The popup disposes its previous Floating UI subscription before starting another and releases the new subscription if a synchronous reposition listener disconnects or deactivates it. Remove both popup hunks when an upstream release passes the public resize/disconnect lifecycle cases in `ui/src/components/web-awesome.test.ts` without retaining resize work after removal.
`chrome-devtools-mcp@1.9.0` has an approved exact-version snapshot-identity patch, backported from [ChromeDevTools/chrome-devtools-mcp#2788](https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/2788) at `06c8d4bc44f68bde8bd3fcd97dcc47375df81fe9`. Stable IDs include the frame's captured CDP session and document generation; ambiguous IDs stay capture-local, and stale lazy handles cannot resolve into a replacement renderer. Frame-local lookup and retained extra handles preserve actions and labeled screenshots. The published bundle also needs its existing `CdpFrame` export exposed. Original license notices remain intact, with modifications recorded in `build/src/OPENCLAW_PATCH_NOTICE.md`.
`chrome-devtools-mcp@1.10.1` has an approved exact-version snapshot-identity patch, backported from [ChromeDevTools/chrome-devtools-mcp#2788](https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/2788) at `06c8d4bc44f68bde8bd3fcd97dcc47375df81fe9` and forward-ported onto tag commit `e52c6b59b476c5e04d8dd9fd4bd017ba3b3d65df`. Stable IDs include the frame's captured CDP session and document generation; ambiguous IDs stay capture-local, and stale lazy handles cannot resolve into a replacement renderer. Frame-local lookup and retained extra handles preserve actions and labeled screenshots. The 1.10.1 CSS-style lookup resolves the same guarded handle and stays within its captured renderer, failing closed when the embedded DevTools target cannot represent a cross-renderer frame. Version 1.10.1 already exports its bundled `CdpFrame`, so the patch changes only the snapshot owner and its DOM-result caller. Original license notices remain intact, with modifications recorded in `build/src/OPENCLAW_PATCH_NOTICE.md`.
The published integrity is `sha512-RnzXoJiUQ44hpOihWk90uOhLD/CnwDkDy0ldHMZONJ2nYQ+dWN1fq1luHHqyd+7FuYnyIlCY6uTThbN5ut9kSQ==`; the patch SHA-256 is `832ce1d2ff002b44edb93bae88858d6edd8bc833acc87dd0fe82454d8834e340`.
The published integrity is `sha512-Klw6HWDqHC/XS1JwZldd2r49aUhbUJN9m9Mvcx4SEueIPXtzuQX+QelxAViobv8YUkDZ7HWDrmViR6LeYK0wAw==`; the patch SHA-256 is `d31d6e7e187ea9fd4dad87ed3ad08073c77ffcfddd52bc4761b39a2dfce0ac1e`.
| Target | Published SHA-256 | Patched SHA-256 |
| --- | --- | --- |
| `build/src/TextSnapshot.js` | `f3496989b93d174723fcf394628fabc36936b37e6a815fd85cbe20fba46d5ea0` | `299833ad0e4cfc171a417afaec41df594e4862fe53a7ada6ba160409f979788b` |
| `build/src/McpPage.js` | `829f11b3cb4c7b87dbb4f5b6a3f62583f4fc05746daee21e629287247debb340` | `6d83dbd4d79c913664fbfa428d138b22fe4246612ab4dfcd93e9d8e62d5d6b51` |
| `build/src/third_party/index.js` | `fc6ae43cb8f6007eba4b0f269290ec8fea6db7670686d17967b4812d90d2cc10` | `7609bb6c575c7c1152b3f4233ad4b98d97885c62ccff7bd9ee29257ca8ffc83f` |
| `build/src/OPENCLAW_PATCH_NOTICE.md` | Added | `0e53a04f337a3760f2f1adab9c20e3b4f07019795f503266c0b68e0f46d55a6c` |
| `build/src/McpPage.js` | `d49b2666cb9c6c5b4d7b9130235c476cb8a3af580363ff224796d9dbde99538d` | `47aa13c6b28cc11e1b0883532edea97cfde7563d78d143035850852d09809975` |
| `build/src/third_party/index.js` | `c988e0684584b75e87ae04b768c4f8ae7064401afe5187ec0d4878b2c6833f12` | Unchanged |
| `build/src/OPENCLAW_PATCH_NOTICE.md` | Added | `4bf44b52a80b5860b2160bc83407a5f0dd09f1801c85d0a2b6e4fec26bd7045d` |
The root package bundles this patched dependency so npm installations preserve the same bytes as pnpm source installs. Browser launches the packaged CLI directly with the runtime running OpenClaw, Node or Bun. Remove this patch, its registration, and the patch-specific package checks when a published upstream version passes `pnpm test:e2e:browser-mcp` and the installed-package stdio proof, including renderer replacement, cross-origin frames, cancellation, and snapshot → wait → action.

View file

@ -1,5 +1,5 @@
diff --git a/build/src/McpPage.js b/build/src/McpPage.js
index 13eb306aea9d516c1e06f4d40a6a61f83bfada11..0c02d5fc9b164dad0f65b74ad926e5cbb6437fcf 100644
index 3be93a33ad4afb206223290c96fd8749cd49a131..f6887160eb88fb0d19792d20ca6466496ca48b9c 100644
--- a/build/src/McpPage.js
+++ b/build/src/McpPage.js
@@ -1,3 +1,4 @@
@ -7,7 +7,16 @@ index 13eb306aea9d516c1e06f4d40a6a61f83bfada11..0c02d5fc9b164dad0f65b74ad926e5cb
/**
* @license
* Copyright 2025 Google LLC
@@ -516,7 +517,7 @@ export class McpPage {
@@ -105,7 +106,7 @@ import { DevToolsCommentBridge } from './devtools/DevToolsCommentBridge.js';
import { createTargetUniverse, } from './devtools/DevtoolsUtils.js';
import { ConsoleCollector, NetworkCollector, } from './collectors/PageCollector.js';
import { TextSnapshot } from './TextSnapshot.js';
-import { PredefinedNetworkConditions, DevTools, } from './third_party/index.js';
+import { PredefinedNetworkConditions, DevTools, CdpFrame, } from './third_party/index.js';
const DEFAULT_TIMEOUT = 5_000;
const NAVIGATION_TIMEOUT = 10_000;
import { logger } from './utils/logger.js';
@@ -549,7 +550,7 @@ export class McpPage {
logger?.(`No backendNodeId for stashed DOM element with index ${index}`);
return `stashed-${index}`;
}
@ -16,29 +25,133 @@ index 13eb306aea9d516c1e06f4d40a6a61f83bfada11..0c02d5fc9b164dad0f65b74ad926e5cb
if (!cdpElementId) {
logger?.(`Could not get cdpElementId for backend node ${backendNodeId}`);
return `stashed-${index}`;
@@ -639,44 +640,62 @@ export class McpPage {
}
}
async getMatchedStylesForUid(uid) {
- if (!this.textSnapshot) {
- throw new Error(`No snapshot found for page ${this.id ?? '?'}. Use take_snapshot to capture one.`);
- }
- const node = this.textSnapshot.idToNode.get(uid);
- if (!node) {
- throw new Error(`Element uid "${uid}" not found on page ${this.id}.`);
- }
- const backendNodeId = node.backendNodeId;
- if (!isBackendNodeId(backendNodeId)) {
- throw new Error(`Failed to resolve backend node ID for element with uid "${uid}".`);
- }
- if (!this.#devtoolsUniverse) {
- throw new Error(`DevTools universe is not available for page ${this.id ?? '?'}.`);
- }
- const targetManager = this.#devtoolsUniverse.universe.context.get(DevTools.TargetManager);
- let domNode;
- let cssModel = null;
- for (const dom of targetManager.models(DevTools.DOMModel.DOMModel)) {
- const nodeMap = await dom.pushNodesByBackendIdsToFrontend(new Set([backendNodeId]));
- const frontendNode = nodeMap?.get(backendNodeId);
- if (frontendNode) {
- domNode = frontendNode;
- cssModel = dom.target().model(DevTools.CSSModel.CSSModel);
- break;
+ const env_3 = { stack: [], error: void 0, hasError: false };
+ try {
+ if (!this.textSnapshot) {
+ throw new Error(`No snapshot found for page ${this.id ?? '?'}. Use take_snapshot to capture one.`);
}
+ const node = this.textSnapshot.idToNode.get(uid);
+ if (!node) {
+ throw new Error(`Element uid "${uid}" not found on page ${this.id}.`);
+ }
+ const snapshotBackendNodeId = node.backendNodeId;
+ if (!isBackendNodeId(snapshotBackendNodeId)) {
+ throw new Error(`Failed to resolve backend node ID for element with uid "${uid}".`);
+ }
+ const handle = __addDisposableResource(env_3, await this.#resolveElementHandle(node, uid), false);
+ const liveBackendNodeId = await handle.backendNodeId();
+ if (liveBackendNodeId !== snapshotBackendNodeId) {
+ throw new Error(`Element with uid "${uid}" was detached or no longer exists on the page. Please take a new snapshot with take_snapshot.`);
+ }
+ const backendNodeId = snapshotBackendNodeId;
+ if (!this.#devtoolsUniverse) {
+ throw new Error(`DevTools universe is not available for page ${this.id ?? '?'}.`);
+ }
+ const targetManager = this.#devtoolsUniverse.universe.context.get(DevTools.TargetManager);
+ const frame = handle.frame;
+ const mainFrame = this.pptrPage.mainFrame();
+ const frameTarget = frame instanceof CdpFrame ? targetManager.targetById(frame._id) : null;
+ const target = frameTarget ??
+ (frame instanceof CdpFrame &&
+ mainFrame instanceof CdpFrame &&
+ frame.client === mainFrame.client
+ ? targetManager.primaryPageTarget()
+ : null);
+ const dom = target?.model(DevTools.DOMModel.DOMModel);
+ const nodeMap = await dom?.pushNodesByBackendIdsToFrontend(new Set([backendNodeId]));
+ const domNode = nodeMap?.get(backendNodeId);
+ const cssModel = dom?.target().model(DevTools.CSSModel.CSSModel);
+ if (!domNode || !cssModel) {
+ throw new Error(`Element with uid "${uid}" was detached or no longer exists on the page. Please take a new snapshot with take_snapshot.`);
+ }
+ const targetElement = domNode.enclosingElementOrSelf();
+ if (!targetElement) {
+ throw new Error(`Element with uid "${uid}" is not an element node and has no parent element.`);
+ }
+ const matchedStyles = await cssModel.getMatchedStyles(targetElement.id);
+ if (!matchedStyles) {
+ throw new Error(`Could not retrieve matched styles for element with uid "${uid}".`);
+ }
+ return matchedStyles;
}
- if (!domNode || !cssModel) {
- throw new Error(`Element with uid "${uid}" was detached or no longer exists on the page. Please take a new snapshot with take_snapshot.`);
- }
- const targetElement = domNode.enclosingElementOrSelf();
- if (!targetElement) {
- throw new Error(`Element with uid "${uid}" is not an element node and has no parent element.`);
+ catch (e_3) {
+ env_3.error = e_3;
+ env_3.hasError = true;
}
- const matchedStyles = await cssModel.getMatchedStyles(targetElement.id);
- if (!matchedStyles) {
- throw new Error(`Could not retrieve matched styles for element with uid "${uid}".`);
+ finally {
+ __disposeResources(env_3);
}
- return matchedStyles;
}
async getDevToolsData() {
try {
diff --git a/build/src/OPENCLAW_PATCH_NOTICE.md b/build/src/OPENCLAW_PATCH_NOTICE.md
new file mode 100644
index 0000000000000000000000000000000000000000..7543bd478e184a709e45b54db944df3dd8231336
index 0000000000000000000000000000000000000000..abdbc42e09793bf885493afc41be15a28d0fe432
--- /dev/null
+++ b/build/src/OPENCLAW_PATCH_NOTICE.md
@@ -0,0 +1,20 @@
@@ -0,0 +1,27 @@
+# Temporary OpenClaw snapshot identity patch
+
+This package remains `chrome-devtools-mcp@1.9.0`. OpenClaw modifies three
+This package remains `chrome-devtools-mcp@1.10.1`. OpenClaw modifies two
+published runtime files to backport the snapshot identity repair proposed in
+https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/2788.
+
+The reviewed upstream source is commit
+`06c8d4bc44f68bde8bd3fcd97dcc47375df81fe9`.
+`06c8d4bc44f68bde8bd3fcd97dcc47375df81fe9`, forward-ported onto the
+`chrome-devtools-mcp-v1.10.1` source tag at
+`e52c6b59b476c5e04d8dd9fd4bd017ba3b3d65df`.
+
+- `TextSnapshot.js` carries that reviewed snapshot-owner implementation.
+- `McpPage.js` supplies the known element frame for DOM-result reverse lookup.
+- `third_party/index.js` exports its already-bundled `CdpFrame` class, required
+ by the backport. No bundled dependency implementation is replaced.
+- `TextSnapshot.js` carries the reviewed snapshot-owner implementation.
+- `McpPage.js` supplies the known element frame for DOM-result reverse lookup
+ and resolves CSS-style UIDs through the same guarded snapshot handle. CSS
+ lookup stays within the captured renderer and fails closed when the embedded
+ DevTools target cannot represent a cross-renderer frame.
+
+The original package is the published npm 1.9.0 tarball with integrity
+`sha512-RnzXoJiUQ44hpOihWk90uOhLD/CnwDkDy0ldHMZONJ2nYQ+dWN1fq1luHHqyd+7FuYnyIlCY6uTThbN5ut9kSQ==`.
+The original `LICENSE` and `third_party/THIRD_PARTY_NOTICES` remain unchanged.
+Version 1.10.1 already exports its bundled `CdpFrame` implementation, so this
+patch does not modify third-party bundle code.
+
+The original package is the published npm 1.10.1 tarball with integrity
+`sha512-Klw6HWDqHC/XS1JwZldd2r49aUhbUJN9m9Mvcx4SEueIPXtzuQX+QelxAViobv8YUkDZ7HWDrmViR6LeYK0wAw==`.
+The original `LICENSE` and `build/src/third_party/THIRD_PARTY_NOTICES` remain
+unchanged.
+
+Remove this patch and notice after adopting a published upstream release that
+contains the repair and passes the same snapshot/stdio regression proof.
@ -447,18 +560,3 @@ index fe2bae7bc287e43d8a7f41f5886496a4f82c0cd7..5b2671a4b416633710886c9089762e0b
reorgInfo.push({ extraNode, attachTarget, descendantIds });
}
for (const { extraNode, attachTarget, descendantIds } of reorgInfo) {
diff --git a/build/src/third_party/index.js b/build/src/third_party/index.js
index 5bce2352d7dd5950547fbb83e1c7d495605d9de5..6a86c23c58dc18ca620977357f1c06220e602b6c 100644
--- a/build/src/third_party/index.js
+++ b/build/src/third_party/index.js
@@ -1,3 +1,4 @@
+// Modified by OpenClaw: expose existing CdpFrame for the snapshot backport; see ../OPENCLAW_PATCH_NOTICE.md.
import childProcess, { execSync, execFile, spawnSync, spawn as spawn$1 } from 'node:child_process';
import fs, { readdirSync as readdirSync$1, readFileSync as readFileSync$1, accessSync, existsSync, constants as constants$2 } from 'node:fs';
import os, { tmpdir } from 'node:os';
@@ -181481,4 +181482,4 @@ const snapshot = snapshot$1;
const navigation = navigation$1;
const generateReport = generateReport$1;
-export { AsyncDisposableStack, Browser as BrowserEnum, CDPSessionEvent, CdpPage, Client, mcp as DevTools, DisposableStack, KnownDevices, ListRootsRequestSchema, ListRootsResultSchema, Locator, McpServer, Mutex$2 as Mutex, PipeTransport, PredefinedNetworkConditions, RootsListChangedNotificationSchema, ScreenRecorder, SetLevelRequestSchema, StdioClientTransport, StdioServerTransport, SuppressedError$1 as SuppressedError, ajv, detectBrowserPlatform, generateReport, getGcfEncode, getToonEncode, hideBin, navigation, puppeteer, resolveDefaultUserDataDir, index as semver, snapshot, Yargs as yargs, z$2 as zod };
+export { AsyncDisposableStack, Browser as BrowserEnum, CDPSessionEvent, CdpFrame, CdpPage, Client, mcp as DevTools, DisposableStack, KnownDevices, ListRootsRequestSchema, ListRootsResultSchema, Locator, McpServer, Mutex$2 as Mutex, PipeTransport, PredefinedNetworkConditions, RootsListChangedNotificationSchema, ScreenRecorder, SetLevelRequestSchema, StdioClientTransport, StdioServerTransport, SuppressedError$1 as SuppressedError, ajv, detectBrowserPlatform, generateReport, getGcfEncode, getToonEncode, hideBin, navigation, puppeteer, resolveDefaultUserDataDir, index as semver, snapshot, Yargs as yargs, z$2 as zod };

16
pnpm-lock.yaml generated
View file

@ -218,7 +218,7 @@ patchedDependencies:
'@novnc/novnc@1.7.0': bfde0e1bda172da3525f9f5014d85ad28073325b74f09609084598a65d2f412d
'@openclaw/proxyline@0.3.12': 9e0969d2dc0abb32610053fba342756afb56f4996c90adfdc34f21ad090fbb0f
baileys@7.0.0-rc14: 03ae85550381d1bda7d014c9aa9f544ad421d35d745d1167fd5d33f7f715dafb
chrome-devtools-mcp@1.9.0: 832ce1d2ff002b44edb93bae88858d6edd8bc833acc87dd0fe82454d8834e340
chrome-devtools-mcp@1.10.1: d31d6e7e187ea9fd4dad87ed3ad08073c77ffcfddd52bc4761b39a2dfce0ac1e
ghostty-web@0.4.0: eb0a0b91bbf843ba8dceeade968072a6c7a6be402fdd1e80d466e54241b62fa6
matrix-js-sdk@42.4.0: 12d9bb9bdc53b7b96d8d887d0bea6b3072d1fef488b51102caec19fb651c8e92
vitest@5.0.1: 90ba2969491e095cc2e92a4d38256dfcf64f85078ec29e1762b9429a00b35901
@ -294,8 +294,8 @@ importers:
specifier: 6.0.0
version: 6.0.0
chrome-devtools-mcp:
specifier: 1.9.0
version: 1.9.0(patch_hash=832ce1d2ff002b44edb93bae88858d6edd8bc833acc87dd0fe82454d8834e340)
specifier: 1.10.1
version: 1.10.1(patch_hash=d31d6e7e187ea9fd4dad87ed3ad08073c77ffcfddd52bc4761b39a2dfce0ac1e)
clawpdf:
specifier: 0.3.2
version: 0.3.2
@ -799,8 +799,8 @@ importers:
specifier: 1.30.0
version: 1.30.0(supports-color@10.2.2)(zod@4.6.5)
chrome-devtools-mcp:
specifier: 1.9.0
version: 1.9.0(patch_hash=832ce1d2ff002b44edb93bae88858d6edd8bc833acc87dd0fe82454d8834e340)
specifier: 1.10.1
version: 1.10.1(patch_hash=d31d6e7e187ea9fd4dad87ed3ad08073c77ffcfddd52bc4761b39a2dfce0ac1e)
express:
specifier: 5.2.1
version: 5.2.1(supports-color@10.2.2)
@ -6702,8 +6702,8 @@ packages:
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'}
chrome-devtools-mcp@1.9.0:
resolution: {integrity: sha512-RnzXoJiUQ44hpOihWk90uOhLD/CnwDkDy0ldHMZONJ2nYQ+dWN1fq1luHHqyd+7FuYnyIlCY6uTThbN5ut9kSQ==}
chrome-devtools-mcp@1.10.1:
resolution: {integrity: sha512-Klw6HWDqHC/XS1JwZldd2r49aUhbUJN9m9Mvcx4SEueIPXtzuQX+QelxAViobv8YUkDZ7HWDrmViR6LeYK0wAw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=23}
hasBin: true
peerDependencies:
@ -14313,7 +14313,7 @@ snapshots:
chownr@3.0.0: {}
chrome-devtools-mcp@1.9.0(patch_hash=832ce1d2ff002b44edb93bae88858d6edd8bc833acc87dd0fe82454d8834e340): {}
chrome-devtools-mcp@1.10.1(patch_hash=d31d6e7e187ea9fd4dad87ed3ad08073c77ffcfddd52bc4761b39a2dfce0ac1e): {}
cjs-module-lexer@2.2.1: {}

View file

@ -116,10 +116,10 @@ packageExtensions:
patchedDependencies:
"baileys@7.0.0-rc14": patches/baileys@7.0.0-rc14.patch
"chrome-devtools-mcp@1.9.0": patches/chrome-devtools-mcp@1.9.0.patch
"matrix-js-sdk@42.4.0": patches/matrix-js-sdk@42.4.0.patch
"@novnc/novnc@1.7.0": patches/@novnc__novnc@1.7.0.patch
vitest@5.0.1: patches/vitest@5.0.1.patch
"@awesome.me/webawesome@3.13.0": patches/@awesome.me__webawesome@3.13.0.patch
"@openclaw/proxyline@0.3.12": patches/@openclaw__proxyline@0.3.12.patch
ghostty-web@0.4.0: patches/ghostty-web@0.4.0.patch
chrome-devtools-mcp@1.10.1: patches/chrome-devtools-mcp@1.10.1.patch

View file

@ -11,7 +11,7 @@ import { runAsScript } from "./lib/ts-guard-utils.mts";
const ALLOWED_PATCHED_DEPENDENCIES = new Map([
["@openclaw/proxyline@0.3.12", "patches/@openclaw__proxyline@0.3.12.patch"],
["chrome-devtools-mcp@1.9.0", "patches/chrome-devtools-mcp@1.9.0.patch"],
["chrome-devtools-mcp@1.10.1", "patches/chrome-devtools-mcp@1.10.1.patch"],
["@awesome.me/webawesome@3.13.0", "patches/@awesome.me__webawesome@3.13.0.patch"],
["@novnc/novnc@1.7.0", "patches/@novnc__novnc@1.7.0.patch"],
["vitest@5.0.1", "patches/vitest@5.0.1.patch"],

View file

@ -64,6 +64,34 @@ const MCP_FILE_HASHES = new Map<string, ReadonlyMap<string, string>>([
],
]),
],
[
"1.10.1",
new Map([
[PATCHED_MCP_CLI, "9f380d06e1ac05b257e27e708c0cc4b4ba190e285ed6eb6c8aa50978d98a12c5"],
[
"build/src/bin/chrome-devtools-mcp-main.js",
"10603ea8c2ac9f69a42791100701795018ebfaa522a7c93d783ed583cce5cce4",
],
["LICENSE", "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd"],
[
"build/src/third_party/THIRD_PARTY_NOTICES",
"6ae0ce181dbc9ba4217b6aad679d7503ed3ab56c45e6f3647e9ab753aa97b67b",
],
[
"build/src/TextSnapshot.js",
"299833ad0e4cfc171a417afaec41df594e4862fe53a7ada6ba160409f979788b",
],
["build/src/McpPage.js", "47aa13c6b28cc11e1b0883532edea97cfde7563d78d143035850852d09809975"],
[
"build/src/third_party/index.js",
"c988e0684584b75e87ae04b768c4f8ae7064401afe5187ec0d4878b2c6833f12",
],
[
"build/src/OPENCLAW_PATCH_NOTICE.md",
"4bf44b52a80b5860b2160bc83407a5f0dd09f1801c85d0a2b6e4fec26bd7045d",
],
]),
],
]);
const REQUIRED_MCP_FILES = [
"build/src/third_party/devtools-formatter-worker.js",
@ -80,7 +108,7 @@ export function isSupportedPatchedMcpVersion(version: unknown): version is strin
export function collectPatchedMcpArtifactErrors({
// The node-bootstrap producer checks the current runtime; frozen package
// consumers pass their independently checked exact dependency pin.
declaredVersion = "1.9.0",
declaredVersion = "1.10.1",
manifest,
files,
sha256,

View file

@ -34,7 +34,7 @@ const MCP_PROCESS_TIMEOUT_MS = 180_000;
const MCP_PACKAGE_TEST_TIMEOUT_MS = MCP_PROCESS_TIMEOUT_MS + 60_000;
const packageJson = {
files: ["dist"],
dependencies: { [MCP_NAME]: "1.9.0" },
dependencies: { [MCP_NAME]: "1.10.1" },
bundleDependencies: [MCP_NAME],
};
@ -81,7 +81,7 @@ function installPatchedMcp(packageRoot: string) {
JSON.stringify({
packages: ["."],
autoInstallPeers: false,
overrides: { [MCP_NAME]: `file:${join(fixtureRoot, `${MCP_NAME}-1.9.0.tgz`)}` },
overrides: { [MCP_NAME]: `file:${join(fixtureRoot, `${MCP_NAME}-1.10.1.tgz`)}` },
}),
);
const pnpm = resolvePnpmRunner({
@ -215,7 +215,7 @@ describe("bundled browser MCP package", () => {
},
);
expectPackageCommandSuccess(cli, "read bundled browser MCP version");
expect(cli.stdout.trim()).toBe("1.9.0");
expect(cli.stdout.trim()).toBe("1.10.1");
},
undefined,
{
@ -241,7 +241,7 @@ describe("bundled browser MCP package", () => {
},
{
name: "unpinned dependency",
manifest: { ...packageJson, dependencies: { [MCP_NAME]: "^1.9.0" } },
manifest: { ...packageJson, dependencies: { [MCP_NAME]: "^1.10.1" } },
error: "must be pinned to a supported patched version",
},
{
@ -298,7 +298,7 @@ describe("bundled browser MCP package", () => {
{
file: "package.json",
change: "modify",
error: "bundled chrome-devtools-mcp must be ESM version 1.9.0",
error: "bundled chrome-devtools-mcp must be ESM version 1.10.1",
},
...[
"build/src/TextSnapshot.js",

View file

@ -1,8 +1,8 @@
import { describe, expect, it } from "vitest";
import { collectPatchedMcpArtifactErrors } from "../../scripts/lib/package-bundled-mcp.mts";
// Independent expectations from v2026.9.6 (eb377ac59e6) and the 1.9.0 upgrade (7dbfab8c2c7).
const CONTRACT_HASHES: Record<"1.8.0" | "1.9.0", Record<string, string>> = {
// Independent expectations from v2026.9.6 (eb377ac59e6) through the 1.10.1 upgrade.
const CONTRACT_HASHES: Record<"1.8.0" | "1.9.0" | "1.10.1", Record<string, string>> = {
"1.8.0": {
"build/src/bin/chrome-devtools-mcp.js":
"9f380d06e1ac05b257e27e708c0cc4b4ba190e285ed6eb6c8aa50978d98a12c5",
@ -33,18 +33,33 @@ const CONTRACT_HASHES: Record<"1.8.0" | "1.9.0", Record<string, string>> = {
"build/src/OPENCLAW_PATCH_NOTICE.md":
"0e53a04f337a3760f2f1adab9c20e3b4f07019795f503266c0b68e0f46d55a6c",
},
"1.10.1": {
"build/src/bin/chrome-devtools-mcp.js":
"9f380d06e1ac05b257e27e708c0cc4b4ba190e285ed6eb6c8aa50978d98a12c5",
"build/src/bin/chrome-devtools-mcp-main.js":
"10603ea8c2ac9f69a42791100701795018ebfaa522a7c93d783ed583cce5cce4",
LICENSE: "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd",
"build/src/third_party/THIRD_PARTY_NOTICES":
"6ae0ce181dbc9ba4217b6aad679d7503ed3ab56c45e6f3647e9ab753aa97b67b",
"build/src/TextSnapshot.js": "299833ad0e4cfc171a417afaec41df594e4862fe53a7ada6ba160409f979788b",
"build/src/McpPage.js": "47aa13c6b28cc11e1b0883532edea97cfde7563d78d143035850852d09809975",
"build/src/third_party/index.js":
"c988e0684584b75e87ae04b768c4f8ae7064401afe5187ec0d4878b2c6833f12",
"build/src/OPENCLAW_PATCH_NOTICE.md":
"4bf44b52a80b5860b2160bc83407a5f0dd09f1801c85d0a2b6e4fec26bd7045d",
},
};
it("preserves the bootstrap producer's current-runtime default", () => {
for (const version of ["1.8.0", "1.9.0"] as const) {
for (const version of ["1.8.0", "1.9.0", "1.10.1"] as const) {
const { declaredVersion: _declaredVersion, ...input } = fixture(
version,
CONTRACT_HASHES[version],
);
const errors = collectPatchedMcpArtifactErrors(input);
if (version === "1.9.0") {
if (version === "1.10.1") {
expect(errors).toEqual([]);
} else {
expect(errors).toContain("bundled chrome-devtools-mcp must be ESM version 1.9.0");
expect(errors).toContain("bundled chrome-devtools-mcp must be ESM version 1.10.1");
}
}
});
@ -74,7 +89,7 @@ describe.each(Object.entries(CONTRACT_HASHES))("patched MCP %s contract", (versi
it("binds the bundled manifest to the exact declared pin", () => {
const input = fixture(version, hashes);
input.manifest.version = version === "1.8.0" ? "1.9.0" : "1.8.0";
input.manifest.version = version === "1.10.1" ? "1.9.0" : "1.10.1";
expect(collectPatchedMcpArtifactErrors(input)).toContain(
"bundled chrome-devtools-mcp must be ESM version " + version,
);
@ -99,8 +114,11 @@ describe.each(Object.entries(CONTRACT_HASHES))("patched MCP %s contract", (versi
});
it("rejects mixed-version byte contracts", () => {
const other = CONTRACT_HASHES[version === "1.8.0" ? "1.9.0" : "1.8.0"];
expect(collectPatchedMcpArtifactErrors(fixture(version, other))).toHaveLength(5);
const other = Object.entries(CONTRACT_HASHES).find(([candidate]) => candidate !== version)?.[1];
expect(other).toBeDefined();
expect(collectPatchedMcpArtifactErrors(fixture(version, other ?? {}))).toContain(
"bundled chrome-devtools-mcp has unpatched or changed runtime entry build/src/bin/chrome-devtools-mcp-main.js",
);
});
it("does not trust artifact-supplied replacement hashes", () => {