豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit ec895f1

Browse files
authored
refactor: use puppeteer Extension API (#1911)
This PR refactor the extension usages using the new Puppeteer API. Requires puppeteer release before merging
1 parent 562c308 commit ec895f1

File tree

14 files changed

+137
-161
lines changed

14 files changed

+137
-161
lines changed

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"globals": "^17.0.0",
7272
"lighthouse": "13.1.0",
7373
"prettier": "^3.6.2",
74-
"puppeteer": "24.41.0",
74+
"puppeteer": "24.42.0",
7575
"rollup": "4.60.2",
7676
"rollup-plugin-cleanup": "^3.2.1",
7777
"rollup-plugin-license": "^3.6.0",

scripts/test.mjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const nodeArgs = [
7777
...files,
7878
];
7979

80-
function installChrome(version) {
80+
function _installChrome(version) {
8181
try {
8282
return execSync(
8383
`npx puppeteer browsers install chrome@${version} --format "{{path}}"`,
@@ -112,9 +112,6 @@ async function runTests(attempt) {
112112
});
113113
}
114114

115-
const chromePath = installChrome('146.0.7680.31');
116-
process.env.CHROME_M146_EXECUTABLE_PATH = chromePath;
117-
118115
const maxAttempts = shouldRetry ? 3 : 1;
119116
let exitCode = 1;
120117

src/McpContext.ts

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
SerializedAXNode,
2929
Viewport,
3030
Target,
31+
Extension,
3132
} from './third_party/index.js';
3233
import type {DevTools} from './third_party/index.js';
3334
import {Locator} from './third_party/index.js';
@@ -47,10 +48,6 @@ import type {
4748
TextSnapshotNode,
4849
ExtensionServiceWorker,
4950
} from './types.js';
50-
import {
51-
ExtensionRegistry,
52-
type InstalledExtension,
53-
} from './utils/ExtensionRegistry.js';
5451
import {ensureExtension, saveTemporaryFile} from './utils/files.js';
5552
import {getNetworkMultiplierFromString} from './WaitForHelper.js';
5653

@@ -83,7 +80,6 @@ export class McpContext implements Context {
8380
#networkCollector: NetworkCollector;
8481
#consoleCollector: ConsoleCollector;
8582
#devtoolsUniverseManager: UniverseManager;
86-
#extensionRegistry = new ExtensionRegistry();
8783

8884
#isRunningTrace = false;
8985
#screenRecorderData: {recorder: ScreenRecorder; filePath: string} | null =
@@ -882,38 +878,30 @@ export class McpContext implements Context {
882878

883879
async installExtension(extensionPath: string): Promise<string> {
884880
const id = await this.browser.installExtension(extensionPath);
885-
await this.#extensionRegistry.registerExtension(id, extensionPath);
886881
return id;
887882
}
888883

889884
async uninstallExtension(id: string): Promise<void> {
890885
await this.browser.uninstallExtension(id);
891-
this.#extensionRegistry.remove(id);
892886
}
893887

894888
async triggerExtensionAction(id: string): Promise<void> {
895-
const page = this.getSelectedPptrPage();
896-
// @ts-expect-error internal puppeteer api is needed since we don't have a way to get
897-
// a tab id at the moment
898-
const theTarget = page._tabId;
899-
const session = await this.browser.target().createCDPSession();
900-
901-
try {
902-
await session.send('Extensions.triggerAction', {
903-
id,
904-
targetId: theTarget,
905-
});
906-
} finally {
907-
await session.detach();
889+
const extensions = await this.browser.extensions();
890+
const extension = extensions.get(id);
891+
if (!extension) {
892+
throw new Error(`Extension with ID ${id} not found.`);
908893
}
894+
const page = this.getSelectedPptrPage();
895+
await extension.triggerAction(page);
909896
}
910897

911-
listExtensions(): InstalledExtension[] {
912-
return this.#extensionRegistry.list();
898+
listExtensions(): Promise<Map<string, Extension>> {
899+
return this.browser.extensions();
913900
}
914901

915-
getExtension(id: string): InstalledExtension | undefined {
916-
return this.#extensionRegistry.getById(id);
902+
async getExtension(id: string): Promise<Extension | undefined> {
903+
const pptrExtensions = await this.browser.extensions();
904+
return pptrExtensions.get(id);
917905
}
918906

919907
async getHeapSnapshotAggregates(

src/McpResponse.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
ResourceType,
2424
TextContent,
2525
JSONSchema7Definition,
26+
Extension,
2627
} from './third_party/index.js';
2728
import type {ToolGroup, ToolDefinition} from './tools/inPage.js';
2829
import {handleDialog} from './tools/pages.js';
@@ -35,7 +36,6 @@ import type {
3536
} from './tools/ToolDefinition.js';
3637
import type {InsightName, TraceResult} from './trace-processing/parse.js';
3738
import {getInsightOutput, getTraceSummary} from './trace-processing/parse.js';
38-
import type {InstalledExtension} from './utils/ExtensionRegistry.js';
3939
import {paginate} from './utils/pagination.js';
4040
import type {PaginationOptions} from './utils/types.js';
4141

@@ -527,9 +527,9 @@ export class McpResponse implements Response {
527527
}
528528
}
529529

530-
let extensions: InstalledExtension[] | undefined;
530+
let extensions: Map<string, Extension> | undefined;
531531
if (this.#listExtensions) {
532-
extensions = context.listExtensions();
532+
extensions = await context.listExtensions();
533533
}
534534

535535
let inPageTools: ToolGroup<ToolDefinition> | undefined;
@@ -665,7 +665,7 @@ export class McpResponse implements Response {
665665
networkRequests?: NetworkFormatter[];
666666
traceSummary?: TraceResult;
667667
traceInsight?: TraceInsightData;
668-
extensions?: InstalledExtension[];
668+
extensions?: Map<string, Extension>;
669669
lighthouseResult?: LighthouseData;
670670
inPageTools?: ToolGroup<ToolDefinition>;
671671
webmcpTools?: WebMCPTool[];
@@ -947,14 +947,15 @@ Call ${handleDialog.name} to handle it before continuing.`);
947947
}
948948

949949
if (data.extensions) {
950-
structuredContent.extensions = data.extensions;
950+
const extensionArray = Array.from(data.extensions.values());
951+
structuredContent.extensions = extensionArray;
951952
response.push('## Extensions');
952-
if (data.extensions.length === 0) {
953+
if (extensionArray.length === 0) {
953954
response.push('No extensions installed.');
954955
} else {
955-
const extensionsMessage = data.extensions
956+
const extensionsMessage = extensionArray
956957
.map(extension => {
957-
return `id=${extension.id} "${extension.name}" v${extension.version} ${extension.isEnabled ? 'Enabled' : 'Disabled'}`;
958+
return `id=${extension.id} "${extension.name}" v${extension.version} ${extension.enabled ? 'Enabled' : 'Disabled'}`;
958959
})
959960
.join('\n');
960961
response.push(extensionsMessage);

src/tools/ToolDefinition.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {zod} from '../third_party/index.js';
1010
import type {
1111
Dialog,
1212
ElementHandle,
13+
Extension,
1314
Page,
1415
ScreenRecorder,
1516
Viewport,
@@ -21,7 +22,6 @@ import type {
2122
GeolocationOptions,
2223
ExtensionServiceWorker,
2324
} from '../types.js';
24-
import type {InstalledExtension} from '../utils/ExtensionRegistry.js';
2525
import type {PaginationOptions} from '../utils/types.js';
2626

2727
import type {ToolCategory} from './categories.js';
@@ -218,8 +218,8 @@ export type Context = Readonly<{
218218
installExtension(path: string): Promise<string>;
219219
uninstallExtension(id: string): Promise<void>;
220220
triggerExtensionAction(id: string): Promise<void>;
221-
listExtensions(): InstalledExtension[];
222-
getExtension(id: string): InstalledExtension | undefined;
221+
listExtensions(): Promise<Map<string, Extension>>;
222+
getExtension(id: string): Promise<Extension | undefined>;
223223
getSelectedMcpPage(): McpPage;
224224
getExtensionServiceWorkers(): ExtensionServiceWorker[];
225225
getExtensionServiceWorkerId(

src/tools/extensions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export const reloadExtension = defineTool({
7777
},
7878
handler: async (request, response, context) => {
7979
const {id} = request.params;
80-
const extension = context.getExtension(id);
80+
const extension = await context.getExtension(id);
8181
if (!extension) {
8282
throw new Error(`Extension with ID ${id} not found.`);
8383
}

src/utils/ExtensionRegistry.ts

Lines changed: 0 additions & 53 deletions
This file was deleted.

tests/McpResponse.test.js.snapshot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,14 +1192,14 @@ exports[`extensions > lists extensions 2`] = `
11921192
"id": "id1",
11931193
"name": "Extension 1",
11941194
"version": "1.0",
1195-
"isEnabled": true,
1195+
"enabled": true,
11961196
"path": "/path/to/ext1"
11971197
},
11981198
{
11991199
"id": "id2",
12001200
"name": "Extension 2",
12011201
"version": "2.0",
1202-
"isEnabled": false,
1202+
"enabled": false,
12031203
"path": "/path/to/ext2"
12041204
}
12051205
]

tests/McpResponse.test.ts

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ import type {ParsedArguments} from '../src/bin/chrome-devtools-mcp-cli-options.j
1616
import type {McpContext} from '../src/McpContext.js';
1717
import type {McpResponse} from '../src/McpResponse.js';
1818
import {replaceHtmlElementsWithUids} from '../src/McpResponse.js';
19-
import type {JSONSchema7Definition} from '../src/third_party/index.js';
19+
import type {
20+
Extension,
21+
JSONSchema7Definition,
22+
} from '../src/third_party/index.js';
2023
import {
2124
closePage,
2225
listPages,
@@ -955,22 +958,31 @@ describe('extensions', () => {
955958

956959
response.resetResponseLineForTesting();
957960
// Testing with extensions
958-
context.listExtensions = () => [
959-
{
960-
id: 'id1',
961-
name: 'Extension 1',
962-
version: '1.0',
963-
isEnabled: true,
964-
path: '/path/to/ext1',
965-
},
966-
{
967-
id: 'id2',
968-
name: 'Extension 2',
969-
version: '2.0',
970-
isEnabled: false,
971-
path: '/path/to/ext2',
972-
},
973-
];
961+
context.listExtensions = async () =>
962+
Promise.resolve(
963+
new Map<string, Extension>([
964+
[
965+
'id1',
966+
{
967+
id: 'id1',
968+
name: 'Extension 1',
969+
version: '1.0',
970+
enabled: true,
971+
path: '/path/to/ext1',
972+
} as Extension,
973+
],
974+
[
975+
'id2',
976+
{
977+
id: 'id2',
978+
name: 'Extension 2',
979+
version: '2.0',
980+
enabled: false,
981+
path: '/path/to/ext2',
982+
} as Extension,
983+
],
984+
]),
985+
);
974986
response.setListExtensions();
975987
const {content, structuredContent} = await response.handle(
976988
'test',

0 commit comments

Comments
 (0)