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.
Files changed (50) hide show
  1. package/README.md +60 -0
  2. package/bin.js +3 -0
  3. package/dist/browser-config.d.ts +2 -0
  4. package/dist/browser-config.d.ts.map +1 -0
  5. package/dist/browser-config.js +59 -0
  6. package/dist/browser-config.js.map +1 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +2 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/index.test.d.ts +2 -0
  12. package/dist/index.test.d.ts.map +1 -0
  13. package/dist/index.test.js +8 -0
  14. package/dist/index.test.js.map +1 -0
  15. package/dist/mcp-client.d.ts +16 -0
  16. package/dist/mcp-client.d.ts.map +1 -0
  17. package/dist/mcp-client.js +52 -0
  18. package/dist/mcp-client.js.map +1 -0
  19. package/dist/mcp.d.ts +2 -0
  20. package/dist/mcp.d.ts.map +1 -0
  21. package/dist/mcp.js +596 -0
  22. package/dist/mcp.js.map +1 -0
  23. package/dist/mcp.test.d.ts +2 -0
  24. package/dist/mcp.test.d.ts.map +1 -0
  25. package/dist/mcp.test.js +205 -0
  26. package/dist/mcp.test.js.map +1 -0
  27. package/dist/playwriter.d.ts +5 -0
  28. package/dist/playwriter.d.ts.map +1 -0
  29. package/dist/playwriter.js +177 -0
  30. package/dist/playwriter.js.map +1 -0
  31. package/dist/profiles.d.ts +16 -0
  32. package/dist/profiles.d.ts.map +1 -0
  33. package/dist/profiles.js +76 -0
  34. package/dist/profiles.js.map +1 -0
  35. package/dist/profiles.test.d.ts +2 -0
  36. package/dist/profiles.test.d.ts.map +1 -0
  37. package/dist/profiles.test.js +169 -0
  38. package/dist/profiles.test.js.map +1 -0
  39. package/package.json +22 -6
  40. package/src/browser-config.ts +66 -0
  41. package/src/mcp-client.ts +73 -0
  42. package/src/mcp.test.ts +240 -0
  43. package/src/mcp.ts +751 -0
  44. package/src/prompt.md +539 -0
  45. package/src/snapshots/hacker-news-focused-accessibility.md +202 -0
  46. package/src/snapshots/hacker-news-initial-accessibility.md +202 -0
  47. package/src/snapshots/hacker-news-tabbed-accessibility.md +202 -0
  48. package/src/snapshots/shadcn-ui-accessibility.md +553 -0
  49. package/src/index.test.ts +0 -9
  50. 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,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import './dist/mcp.js';
@@ -0,0 +1,2 @@
1
+ export declare function getBrowserExecutablePath(): string;
2
+ //# sourceMappingURL=browser-config.d.ts.map
@@ -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"}
@@ -0,0 +1,2 @@
1
+ export { startPlaywriter } from './playwriter';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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,2 @@
1
+ export { startPlaywriter } from './playwriter';
2
+ //# sourceMappingURL=index.js.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import { test, expect } from 'vitest';
2
+ test('ready', () => {
3
+ expect(true).toBe(true);
4
+ });
5
+ test('two', () => {
6
+ expect(true).toBe(true);
7
+ });
8
+ //# sourceMappingURL=index.test.js.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":""}