playwriter 0.0.0 โ 0.0.1
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 +60 -0
- package/bin.js +3 -0
- package/dist/browser-config.d.ts +2 -0
- package/dist/browser-config.d.ts.map +1 -0
- package/dist/browser-config.js +59 -0
- package/dist/browser-config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +8 -0
- package/dist/index.test.js.map +1 -0
- package/dist/mcp-client.d.ts +16 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +52 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/mcp.d.ts +2 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +596 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mcp.test.d.ts +2 -0
- package/dist/mcp.test.d.ts.map +1 -0
- package/dist/mcp.test.js +205 -0
- package/dist/mcp.test.js.map +1 -0
- package/dist/playwriter.d.ts +5 -0
- package/dist/playwriter.d.ts.map +1 -0
- package/dist/playwriter.js +177 -0
- package/dist/playwriter.js.map +1 -0
- package/dist/profiles.d.ts +16 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +76 -0
- package/dist/profiles.js.map +1 -0
- package/dist/profiles.test.d.ts +2 -0
- package/dist/profiles.test.d.ts.map +1 -0
- package/dist/profiles.test.js +169 -0
- package/dist/profiles.test.js.map +1 -0
- package/package.json +22 -6
- package/src/browser-config.ts +66 -0
- package/src/mcp-client.ts +73 -0
- package/src/mcp.test.ts +240 -0
- package/src/mcp.ts +751 -0
- package/src/prompt.md +539 -0
- package/src/snapshots/hacker-news-focused-accessibility.md +202 -0
- package/src/snapshots/hacker-news-initial-accessibility.md +202 -0
- package/src/snapshots/hacker-news-tabbed-accessibility.md +202 -0
- package/src/snapshots/shadcn-ui-accessibility.md +553 -0
- package/src/index.test.ts +0 -9
- package/src/index.ts +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# PlayWriter MCP
|
|
2
|
+
|
|
3
|
+
A powerful browser automation MCP (Model Context Protocol) server that provides persistent browser sessions with advanced automation capabilities through Playwright.
|
|
4
|
+
|
|
5
|
+
## Key Differences from playwright-mcp
|
|
6
|
+
|
|
7
|
+
### ๐ Persistent Data Directory
|
|
8
|
+
PlayWriter MCP maintains a persistent user data directory between runs. This enables:
|
|
9
|
+
- Login sessions with Google and other OAuth providers
|
|
10
|
+
- Website authentication that persists across sessions
|
|
11
|
+
- Test automation without repeated logins
|
|
12
|
+
- Preserved cookies, local storage, and browser state
|
|
13
|
+
|
|
14
|
+
### ๐ก๏ธ Anti-Detection Features
|
|
15
|
+
Built-in detection prevention mechanisms allow automation on websites with bot protection:
|
|
16
|
+
- Works seamlessly with Google and other major platforms
|
|
17
|
+
- User-agent rotation
|
|
18
|
+
- Automation flag removal
|
|
19
|
+
- Realistic browser fingerprinting
|
|
20
|
+
|
|
21
|
+
### ๐ Shared Chrome Instance
|
|
22
|
+
- Single Chrome instance shared between all agents
|
|
23
|
+
- Each agent operates in its own tab
|
|
24
|
+
- Can reuse existing pages/tabs via `context.pages()` in the execute tool
|
|
25
|
+
- Find and switch between pages by URL or other criteria
|
|
26
|
+
- Efficient resource usage
|
|
27
|
+
- Better performance for multi-agent workflows
|
|
28
|
+
|
|
29
|
+
### ๐ Single Powerful Execute Tool
|
|
30
|
+
Instead of many granular tools, PlayWriter provides one flexible `execute` tool:
|
|
31
|
+
- Direct access to Playwright `page` and `context` objects
|
|
32
|
+
- Write complex automation logic with loops and conditions
|
|
33
|
+
- Full JavaScript execution capabilities
|
|
34
|
+
- Custom wait conditions and complex interactions
|
|
35
|
+
|
|
36
|
+
Example:
|
|
37
|
+
```javascript
|
|
38
|
+
// Complex wait logic with custom conditions
|
|
39
|
+
while (!(await page.isVisible('.success-message'))) {
|
|
40
|
+
await page.click('.retry-button');
|
|
41
|
+
await page.waitForTimeout(1000);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### ๐ง Additional Tools
|
|
46
|
+
- `new_page` - Create a new browser tab/page
|
|
47
|
+
- `accessibility_snapshot` - Get page structure as JSON
|
|
48
|
+
- `console_logs` - Retrieve browser console messages
|
|
49
|
+
- `network_history` - Monitor network requests
|
|
50
|
+
|
|
51
|
+
## Roadmap
|
|
52
|
+
|
|
53
|
+
- โ๏ธ Cloud service integration for shared persistent state
|
|
54
|
+
- ๐งช Quality assertion tests in CI/CD pipelines
|
|
55
|
+
- ๐ค Multi-agent collaboration features
|
|
56
|
+
- ๐ Advanced debugging and monitoring capabilities
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
See the main project documentation for installation and setup instructions.
|
package/bin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-config.d.ts","sourceRoot":"","sources":["../src/browser-config.ts"],"names":[],"mappings":"AAKA,wBAAgB,wBAAwB,IAAI,MAAM,CAejD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
// Function to get the browser executable path
|
|
4
|
+
// Can be overridden by environment variable PLAYWRITER_BROWSER_PATH
|
|
5
|
+
export function getBrowserExecutablePath() {
|
|
6
|
+
// Check environment variable first
|
|
7
|
+
const envPath = process.env.PLAYWRITER_BROWSER_PATH;
|
|
8
|
+
if (envPath && fs.existsSync(envPath)) {
|
|
9
|
+
return envPath;
|
|
10
|
+
}
|
|
11
|
+
// Check for Ghost Browser on macOS
|
|
12
|
+
// const ghostBrowserPath = '/Applications/Ghost Browser.app/Contents/MacOS/Ghost Browser'
|
|
13
|
+
// if (fs.existsSync(ghostBrowserPath)) {
|
|
14
|
+
// return ghostBrowserPath
|
|
15
|
+
// }
|
|
16
|
+
// Fall back to finding Chrome
|
|
17
|
+
return findChromeExecutablePath();
|
|
18
|
+
}
|
|
19
|
+
// Original Chrome finding logic
|
|
20
|
+
function findChromeExecutablePath() {
|
|
21
|
+
const osPlatform = os.platform();
|
|
22
|
+
const paths = (() => {
|
|
23
|
+
if (osPlatform === 'darwin') {
|
|
24
|
+
return [
|
|
25
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
26
|
+
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
|
|
27
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
28
|
+
'~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
if (osPlatform === 'win32') {
|
|
32
|
+
return [
|
|
33
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
34
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
35
|
+
`${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
36
|
+
`${process.env.PROGRAMFILES}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
37
|
+
`${process.env['PROGRAMFILES(X86)']}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
38
|
+
].filter(Boolean);
|
|
39
|
+
}
|
|
40
|
+
// Linux
|
|
41
|
+
return [
|
|
42
|
+
'/usr/bin/google-chrome',
|
|
43
|
+
'/usr/bin/google-chrome-stable',
|
|
44
|
+
'/usr/bin/chromium',
|
|
45
|
+
'/usr/bin/chromium-browser',
|
|
46
|
+
'/snap/bin/chromium',
|
|
47
|
+
];
|
|
48
|
+
})();
|
|
49
|
+
for (const path of paths) {
|
|
50
|
+
const resolvedPath = path.startsWith('~')
|
|
51
|
+
? path.replace('~', process.env.HOME || '')
|
|
52
|
+
: path;
|
|
53
|
+
if (fs.existsSync(resolvedPath)) {
|
|
54
|
+
return resolvedPath;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
throw new Error('Could not find Chrome executable. Please install Google Chrome or set PLAYWRITER_BROWSER_PATH environment variable.');
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=browser-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-config.js","sourceRoot":"","sources":["../src/browser-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,EAAE,MAAM,SAAS,CAAA;AAExB,8CAA8C;AAC9C,oEAAoE;AACpE,MAAM,UAAU,wBAAwB;IACpC,mCAAmC;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAA;IACnD,IAAI,OAAO,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,OAAO,CAAA;IAClB,CAAC;IAED,mCAAmC;IACnC,0FAA0F;IAC1F,yCAAyC;IACzC,8BAA8B;IAC9B,IAAI;IAEJ,8BAA8B;IAC9B,OAAO,wBAAwB,EAAE,CAAA;AACrC,CAAC;AAED,gCAAgC;AAChC,SAAS,wBAAwB;IAC7B,MAAM,UAAU,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAA;IAChC,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE;QAChB,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO;gBACH,8DAA8D;gBAC9D,4EAA4E;gBAC5E,oDAAoD;gBACpD,+DAA+D;aAClE,CAAA;QACL,CAAC;QACD,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;YACzB,OAAO;gBACH,4DAA4D;gBAC5D,kEAAkE;gBAClE,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,2CAA2C;gBACtE,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,2CAA2C;gBACtE,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,2CAA2C;aACjF,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACrB,CAAC;QACD,QAAQ;QACR,OAAO;YACH,wBAAwB;YACxB,+BAA+B;YAC/B,mBAAmB;YACnB,2BAA2B;YAC3B,oBAAoB;SACvB,CAAA;IACL,CAAC,CAAC,EAAE,CAAA;IAEJ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YACrC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;YAC3C,CAAC,CAAC,IAAI,CAAA;QACV,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,OAAO,YAAY,CAAA;QACvB,CAAC;IACL,CAAC;IAED,MAAM,IAAI,KAAK,CACX,qHAAqH,CACxH,CAAA;AACL,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAErC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;IACf,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE;IACb,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
3
|
+
import { Stream } from 'node:stream';
|
|
4
|
+
export interface CreateTransportOptions {
|
|
5
|
+
clientName?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createTransport(args: string[]): Promise<{
|
|
8
|
+
transport: Transport;
|
|
9
|
+
stderr: Stream | null;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function createMCPClient(options?: CreateTransportOptions): Promise<{
|
|
12
|
+
client: Client;
|
|
13
|
+
stderr: string;
|
|
14
|
+
cleanup: () => Promise<void>;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=mcp-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAElE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAA;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAMpC,MAAM,WAAW,sBAAsB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3D,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB,CAAC,CAkBD;AAED,wBAAsB,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC;IAC7E,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/B,CAAC,CAgCD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import url from 'node:url';
|
|
5
|
+
const __filename = url.fileURLToPath(import.meta.url);
|
|
6
|
+
export async function createTransport(args) {
|
|
7
|
+
const transport = new StdioClientTransport({
|
|
8
|
+
command: 'pnpm',
|
|
9
|
+
args: ['vite-node', path.join(path.dirname(__filename), 'mcp.ts'), ...args],
|
|
10
|
+
cwd: path.join(path.dirname(__filename), '..'),
|
|
11
|
+
stderr: 'pipe',
|
|
12
|
+
env: {
|
|
13
|
+
...process.env,
|
|
14
|
+
DEBUG: 'playwriter:mcp:test',
|
|
15
|
+
DEBUG_COLORS: '0',
|
|
16
|
+
DEBUG_HIDE_DATE: '1',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
transport,
|
|
21
|
+
stderr: transport.stderr,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function createMCPClient(options) {
|
|
25
|
+
const client = new Client({
|
|
26
|
+
name: options?.clientName ?? 'test',
|
|
27
|
+
version: '1.0.0'
|
|
28
|
+
});
|
|
29
|
+
const { transport, stderr } = await createTransport([]);
|
|
30
|
+
let stderrBuffer = '';
|
|
31
|
+
stderr?.on('data', (data) => {
|
|
32
|
+
process.stderr.write(data);
|
|
33
|
+
stderrBuffer += data.toString();
|
|
34
|
+
});
|
|
35
|
+
await client.connect(transport);
|
|
36
|
+
await client.ping();
|
|
37
|
+
const cleanup = async () => {
|
|
38
|
+
try {
|
|
39
|
+
await client.close();
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
console.error('Error during MCP client cleanup:', e);
|
|
43
|
+
// Ignore errors during cleanup
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
client,
|
|
48
|
+
stderr: stderrBuffer,
|
|
49
|
+
cleanup,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=mcp-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAGhF,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,GAAG,MAAM,UAAU,CAAA;AAE1B,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAMrD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAc;IAIhD,MAAM,SAAS,GAAG,IAAI,oBAAoB,CAAC;QACvC,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC;QAC3E,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;QAC9C,MAAM,EAAE,MAAM;QACd,GAAG,EAAE;YACD,GAAG,OAAO,CAAC,GAAG;YACd,KAAK,EAAE,qBAAqB;YAC5B,YAAY,EAAE,GAAG;YACjB,eAAe,EAAE,GAAG;SACvB;KACJ,CAAC,CAAA;IAEF,OAAO;QACH,SAAS;QACT,MAAM,EAAE,SAAS,CAAC,MAAO;KAC5B,CAAA;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAgC;IAKlE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACtB,IAAI,EAAE,OAAO,EAAE,UAAU,IAAI,MAAM;QACnC,OAAO,EAAE,OAAO;KACnB,CAAC,CAAA;IAEF,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,EAAE,CAAC,CAAA;IAEvD,IAAI,YAAY,GAAG,EAAE,CAAA;IACrB,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAE1B,YAAY,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC/B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;IAEnB,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;QACvB,IAAI,CAAC;YACD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,CAAC,CAAC,CAAA;YAClD,+BAA+B;QACnC,CAAC;IACL,CAAC,CAAA;IAED,OAAO;QACH,MAAM;QACN,MAAM,EAAE,YAAY;QACpB,OAAO;KACV,CAAA;AACL,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":""}
|