Skip to content

Commit 7aac9b4

Browse files
authored
chore: organize client folders (microsoft#39535)
1 parent 6aaaa2c commit 7aac9b4

80 files changed

Lines changed: 340 additions & 434 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/playwright-dev/mcp-dev.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
### Step 1: Create the Tool File
66

7-
Create `packages/playwright/src/mcp/browser/tools/<your-tool>.ts`.
7+
Create `packages/playwright/src/tools/<your-tool>.ts`.
88

99
Import zod from the MCP bundle and use `defineTool` or `defineTabTool`:
1010

@@ -115,7 +115,7 @@ export type ToolCapability =
115115

116116
### Step 3: Register the Tool
117117

118-
In `packages/playwright/src/mcp/browser/tools.ts`:
118+
In `packages/playwright/src/tools/tools.ts`:
119119

120120
```typescript
121121
import myTool from './tools/myTool';
@@ -331,7 +331,7 @@ export type Config = {
331331
};
332332
```
333333

334-
### 2. CLI options type: `packages/playwright/src/mcp/browser/config.ts`
334+
### 2. CLI options type: `packages/playwright/src/mcp/config.ts`
335335

336336
Add to `CLIOptions` type:
337337

packages/playwright-core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"./lib/cli/client/program": "./lib/cli/client/program.js",
2828
"./lib/mcpBundle": "./lib/mcpBundle.js",
2929
"./lib/mcp/exports": "./lib/mcp/exports.js",
30+
"./lib/tools/exports": "./lib/tools/exports.js",
3031
"./lib/mcp/index": "./lib/mcp/index.js",
3132
"./lib/remote/playwrightServer": "./lib/remote/playwrightServer.js",
3233
"./lib/server": "./lib/server/index.js",

packages/playwright-core/src/cli/client/DEPS.list

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,3 @@
1313

1414
[registry.ts]
1515
"strict"
16-
17-
[devtoolsApp.ts]
18-
../../../
19-
../../server/registry/index.ts
20-
../../server/utils/
21-
../../utils/

packages/playwright-core/src/cli/client/program.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import path from 'path';
2626
import { createClientInfo, Registry, resolveSessionName } from './registry';
2727
import { Session, renderResolvedConfig } from './session';
2828

29-
import type { Config } from '../../mcp/config';
29+
import type { Config } from '../../mcp/config.d';
3030
import type { ClientInfo, SessionFile } from './registry';
3131

3232
type MinimistArgs = {
@@ -171,7 +171,7 @@ export async function program(options?: { embedderVersion?: string}) {
171171
await installBrowser();
172172
return;
173173
case 'show': {
174-
const daemonScript = path.join(__dirname, 'devtoolsApp.js');
174+
const daemonScript = require.resolve('../../devtools/devtoolsApp.js');
175175
const child = spawn(process.execPath, [daemonScript], {
176176
detached: true,
177177
stdio: 'ignore',
@@ -294,7 +294,7 @@ async function killAllDaemons(): Promise<void> {
294294
const result = execSync(
295295
`powershell -NoProfile -NonInteractive -Command `
296296
+ `"Get-CimInstance Win32_Process `
297-
+ `| Where-Object { $_.CommandLine -like '*-server*' -and $_.CommandLine -like '*--daemon-dir*' } `
297+
+ `| Where-Object { $_.CommandLine -like '*-server*' -and $_.CommandLine -like '*--daemon-*' } `
298298
+ `| ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue; $_.ProcessId }"`,
299299
{ encoding: 'utf-8' }
300300
);
@@ -308,7 +308,7 @@ async function killAllDaemons(): Promise<void> {
308308
const result = execSync('ps aux', { encoding: 'utf-8' });
309309
const lines = result.split('\n');
310310
for (const line of lines) {
311-
if ((line.includes('-server')) && line.includes('--daemon-dir')) {
311+
if ((line.includes('-server')) && line.includes('--daemon-')) {
312312
const parts = line.trim().split(/\s+/);
313313
const pid = parts[1];
314314
if (pid && /^\d+$/.test(pid)) {
@@ -385,8 +385,8 @@ async function renderSessionStatus(clientInfo: ClientInfo, session: Session) {
385385
text.push(` - status: ${canConnect ? 'open' : 'closed'}`);
386386
if (canConnect && !session.isCompatible(clientInfo))
387387
text.push(` - version: v${config.version} [incompatible please re-open]`);
388-
if (config.resolvedConfig)
389-
text.push(...renderResolvedConfig(config.resolvedConfig));
388+
if (config.browser)
389+
text.push(...renderResolvedConfig(config));
390390
return text.join('\n');
391391
}
392392

packages/playwright-core/src/cli/client/registry.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import fs from 'fs';
1919
import os from 'os';
2020
import path from 'path';
2121

22-
import type { FullConfig } from '../../mcp/browser/config';
22+
import type * as playwright from '../../..';
2323

2424
export type ClientInfo = {
2525
version: string;
@@ -37,7 +37,11 @@ export type SessionConfig = {
3737
persistent?: boolean;
3838
};
3939
workspaceDir?: string;
40-
resolvedConfig?: FullConfig;
40+
browser: {
41+
browserName: string;
42+
launchOptions: playwright.LaunchOptions;
43+
userDataDir?: string;
44+
};
4145
};
4246

4347
export type SessionFile = {

packages/playwright-core/src/cli/client/session.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import path from 'path';
2525
import { compareSemver, SocketConnection } from './socketConnection';
2626
import { resolveSessionName } from './registry';
2727

28-
import type { FullConfig } from '../../mcp/browser/config';
2928
import type { SessionConfig, ClientInfo, SessionFile } from './registry';
3029

3130
type MinimistArgs = {
@@ -219,16 +218,16 @@ export class Session {
219218
}
220219
}
221220

222-
export function renderResolvedConfig(resolvedConfig: FullConfig) {
223-
const channel = resolvedConfig.browser.launchOptions.channel ?? resolvedConfig.browser.browserName;
221+
export function renderResolvedConfig(config: SessionConfig) {
222+
const channel = config.browser.launchOptions.channel ?? config.browser.browserName;
224223
const lines = [];
225224
if (channel)
226225
lines.push(` - browser-type: ${channel}`);
227-
if (resolvedConfig.browser.isolated)
226+
if (!config.cli.persistent)
228227
lines.push(` - user-data-dir: <in-memory>`);
229228
else
230-
lines.push(` - user-data-dir: ${resolvedConfig.browser.userDataDir}`);
231-
lines.push(` - headed: ${!resolvedConfig.browser.launchOptions.headless}`);
229+
lines.push(` - user-data-dir: ${config.browser.userDataDir}`);
230+
lines.push(` - headed: ${!config.browser.launchOptions.headless}`);
232231
return lines;
233232
}
234233

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[*]
2-
../../mcp/browser/**
3-
../../mcp/extension/**
42
../client/socketConnection.ts
53
../client/registry.ts
4+
../../tools/
65
../../utilsBundle.ts
76
../../utils/
87
../../mcpBundle.ts
8+
../../mcp/
99
../../server/utils/

packages/playwright-core/src/cli/daemon/commands.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -754,15 +754,6 @@ const tracingStop = declareCommand({
754754
toolParams: () => ({}),
755755
});
756756

757-
const tracingShow = declareCommand({
758-
name: 'tracing-show',
759-
description: 'Open trace viewer for the recorded trace',
760-
category: 'devtools',
761-
args: z.object({}),
762-
toolName: 'browser_show_tracing',
763-
toolParams: () => ({}),
764-
});
765-
766757
const videoStart = declareCommand({
767758
name: 'video-start',
768759
description: 'Start video recording',
@@ -974,7 +965,6 @@ const commandsArray: AnyCommandSchema[] = [
974965
networkRequests,
975966
tracingStart,
976967
tracingStop,
977-
tracingShow,
978968
videoStart,
979969
videoStop,
980970
devtoolsShow,

packages/playwright-core/src/cli/daemon/daemon.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,24 @@ import fs from 'fs';
1818
import net from 'net';
1919
import os from 'os';
2020
import path from 'path';
21-
import url from 'url';
2221

2322
import { calculateSha1 } from '../../utils';
2423
import { debug } from '../../utilsBundle';
2524
import { decorateServer } from '../../server/utils/network';
2625
import { gracefullyProcessExitDoNotHang } from '../../server/utils/processLauncher';
2726

28-
import { BrowserServerBackend } from '../../mcp/browser/browserServerBackend';
29-
import { browserTools } from '../../mcp/browser/tools';
27+
import { BrowserServerBackend } from '../../tools/browserServerBackend';
28+
import { browserTools } from '../../tools/tools';
3029
import { SocketConnection } from '../client/socketConnection';
3130
import { commands } from './commands';
3231
import { parseCommand } from './command';
3332
import { createClientInfo } from '../client/registry';
3433

3534
import type * as playwright from '../../..';
35+
import type * as tools from '../../tools/exports';
3636
import type * as mcp from '../../mcp/exports';
3737
import type { SessionConfig, ClientInfo } from '../client/registry';
38+
import type { BrowserContext } from '../../client/browserContext';
3839

3940
const daemonDebug = debug('pw:daemon');
4041

@@ -51,15 +52,15 @@ async function socketExists(socketPath: string): Promise<boolean> {
5152
export async function startMcpDaemonServer(
5253
sessionName: string,
5354
browserContext: playwright.BrowserContext,
54-
mcpConfig: mcp.FullConfig,
55+
mcpConfig: tools.ContextConfig,
5556
clientInfo = createClientInfo(),
5657
persistent?: boolean,
5758
): Promise<string> {
58-
const sessionConfig = createSessionConfig(clientInfo, sessionName, persistent);
59+
const sessionConfig = createSessionConfig(clientInfo, sessionName, browserContext, persistent);
5960
const { socketPath } = sessionConfig;
6061

6162
// Clean up existing socket file on Unix
62-
if (os.platform() !== 'win32' && await socketExists(socketPath)) {
63+
if (process.platform !== 'win32' && await socketExists(socketPath)) {
6364
daemonDebug(`Socket already exists, removing: ${socketPath}`);
6465
try {
6566
await fs.promises.unlink(socketPath);
@@ -70,15 +71,7 @@ export async function startMcpDaemonServer(
7071
}
7172

7273
const backend = new BrowserServerBackend(mcpConfig, browserContext, browserTools);
73-
await backend.initialize({
74-
name: 'playwright-cli',
75-
version: sessionConfig.version,
76-
roots: [{
77-
uri: url.pathToFileURL(process.cwd()).href,
78-
name: 'cwd',
79-
}],
80-
timestamp: Date.now(),
81-
});
74+
await backend.initialize({ cwd: process.cwd() });
8275

8376
await fs.promises.mkdir(path.dirname(socketPath), { recursive: true });
8477

@@ -129,7 +122,6 @@ export async function startMcpDaemonServer(
129122
server.listen(socketPath, () => resolve());
130123
});
131124

132-
sessionConfig.resolvedConfig = mcpConfig;
133125
await saveSessionFile(clientInfo, sessionConfig);
134126
return socketPath;
135127
}
@@ -167,13 +159,19 @@ function daemonSocketPath(clientInfo: ClientInfo, sessionName: string): string {
167159
return path.join(socketsDir, clientInfo.workspaceDirHash, socketName);
168160
}
169161

170-
function createSessionConfig(clientInfo: ClientInfo, sessionName: string, persistent?: boolean): SessionConfig {
162+
function createSessionConfig(clientInfo: ClientInfo, sessionName: string, browserContext: playwright.BrowserContext, persistent?: boolean): SessionConfig {
163+
const bc = browserContext as BrowserContext;
171164
return {
172165
name: sessionName,
173166
version: clientInfo.version,
174167
timestamp: Date.now(),
175168
socketPath: daemonSocketPath(clientInfo, sessionName),
176169
workspaceDir: clientInfo.workspaceDir,
177170
cli: { persistent },
171+
browser: {
172+
browserName: bc.browser()!.browserType().name(),
173+
launchOptions: bc.browser()!._options,
174+
userDataDir: bc.browser()?._userDataDir,
175+
},
178176
};
179177
}

packages/playwright-core/src/cli/daemon/program.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,18 @@
1717
/* eslint-disable no-console */
1818

1919
import fs from 'fs';
20-
import url from 'url';
2120
import path from 'path';
2221

2322
import { startMcpDaemonServer } from './daemon';
24-
import { setupExitWatchdog } from '../../mcp/browser/watchdog';
25-
import { contextFactory } from '../../mcp/browser/browserContextFactory';
26-
import { ExtensionContextFactory } from '../../mcp/extension/extensionContextFactory';
27-
import * as configUtils from '../../mcp/browser/config';
23+
import { setupExitWatchdog } from '../../mcp/watchdog';
24+
import { contextFactory } from '../../mcp/browserContextFactory';
25+
import { ExtensionContextFactory } from '../../mcp/extensionContextFactory';
26+
import * as configUtils from '../../mcp/config';
2827
import { gracefullyProcessExitDoNotHang } from '../../utils';
2928
import { ClientInfo, createClientInfo } from '../client/registry';
3029

3130
import type { Command } from '../../utilsBundle';
32-
import type { FullConfig } from '../../mcp/browser/config';
31+
import type { FullConfig } from '../../mcp/config';
3332

3433
export function decorateCLICommand(command: Command, version: string) {
3534
command
@@ -46,15 +45,7 @@ export function decorateCLICommand(command: Command, version: string) {
4645
setupExitWatchdog();
4746
const clientInfo = createClientInfo();
4847
const mcpConfig = await resolveCLIConfig(clientInfo, sessionName, options);
49-
const mcpClientInfo = {
50-
name: 'playwright-cli',
51-
version: require('../../../package.json').version,
52-
roots: [{
53-
uri: url.pathToFileURL(process.cwd()).href,
54-
name: 'cwd'
55-
}],
56-
timestamp: Date.now(),
57-
};
48+
const mcpClientInfo = { cwd: process.cwd() };
5849

5950
try {
6051
const extensionContextFactory = new ExtensionContextFactory(mcpConfig.browser.launchOptions.channel || 'chrome', mcpConfig.browser.userDataDir, mcpConfig.browser.launchOptions.executablePath);

0 commit comments

Comments
 (0)