e2e-pilot 0.0.69

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 (152) hide show
  1. package/bin.js +3 -0
  2. package/dist/aria-snapshot.d.ts +95 -0
  3. package/dist/aria-snapshot.d.ts.map +1 -0
  4. package/dist/aria-snapshot.js +490 -0
  5. package/dist/aria-snapshot.js.map +1 -0
  6. package/dist/bippy.js +971 -0
  7. package/dist/cdp-relay.d.ts +16 -0
  8. package/dist/cdp-relay.d.ts.map +1 -0
  9. package/dist/cdp-relay.js +715 -0
  10. package/dist/cdp-relay.js.map +1 -0
  11. package/dist/cdp-session.d.ts +42 -0
  12. package/dist/cdp-session.d.ts.map +1 -0
  13. package/dist/cdp-session.js +154 -0
  14. package/dist/cdp-session.js.map +1 -0
  15. package/dist/cdp-types.d.ts +63 -0
  16. package/dist/cdp-types.d.ts.map +1 -0
  17. package/dist/cdp-types.js +91 -0
  18. package/dist/cdp-types.js.map +1 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +213 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/create-logger.d.ts +9 -0
  24. package/dist/create-logger.d.ts.map +1 -0
  25. package/dist/create-logger.js +25 -0
  26. package/dist/create-logger.js.map +1 -0
  27. package/dist/debugger-api.md +458 -0
  28. package/dist/debugger-examples-types.d.ts +24 -0
  29. package/dist/debugger-examples-types.d.ts.map +1 -0
  30. package/dist/debugger-examples-types.js +2 -0
  31. package/dist/debugger-examples-types.js.map +1 -0
  32. package/dist/debugger-examples.d.ts +6 -0
  33. package/dist/debugger-examples.d.ts.map +1 -0
  34. package/dist/debugger-examples.js +53 -0
  35. package/dist/debugger-examples.js.map +1 -0
  36. package/dist/debugger.d.ts +381 -0
  37. package/dist/debugger.d.ts.map +1 -0
  38. package/dist/debugger.js +633 -0
  39. package/dist/debugger.js.map +1 -0
  40. package/dist/editor-api.md +364 -0
  41. package/dist/editor-examples.d.ts +11 -0
  42. package/dist/editor-examples.d.ts.map +1 -0
  43. package/dist/editor-examples.js +124 -0
  44. package/dist/editor-examples.js.map +1 -0
  45. package/dist/editor.d.ts +203 -0
  46. package/dist/editor.d.ts.map +1 -0
  47. package/dist/editor.js +336 -0
  48. package/dist/editor.js.map +1 -0
  49. package/dist/execute.d.ts +50 -0
  50. package/dist/execute.d.ts.map +1 -0
  51. package/dist/execute.js +576 -0
  52. package/dist/execute.js.map +1 -0
  53. package/dist/index.d.ts +11 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +7 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/mcp-client.d.ts +20 -0
  58. package/dist/mcp-client.d.ts.map +1 -0
  59. package/dist/mcp-client.js +56 -0
  60. package/dist/mcp-client.js.map +1 -0
  61. package/dist/mcp.d.ts +5 -0
  62. package/dist/mcp.d.ts.map +1 -0
  63. package/dist/mcp.js +720 -0
  64. package/dist/mcp.js.map +1 -0
  65. package/dist/mcp.test.d.ts +10 -0
  66. package/dist/mcp.test.d.ts.map +1 -0
  67. package/dist/mcp.test.js +2999 -0
  68. package/dist/mcp.test.js.map +1 -0
  69. package/dist/network-capture.d.ts +23 -0
  70. package/dist/network-capture.d.ts.map +1 -0
  71. package/dist/network-capture.js +98 -0
  72. package/dist/network-capture.js.map +1 -0
  73. package/dist/protocol.d.ts +54 -0
  74. package/dist/protocol.d.ts.map +1 -0
  75. package/dist/protocol.js +2 -0
  76. package/dist/protocol.js.map +1 -0
  77. package/dist/react-source.d.ts +13 -0
  78. package/dist/react-source.d.ts.map +1 -0
  79. package/dist/react-source.js +68 -0
  80. package/dist/react-source.js.map +1 -0
  81. package/dist/scoped-fs.d.ts +94 -0
  82. package/dist/scoped-fs.d.ts.map +1 -0
  83. package/dist/scoped-fs.js +356 -0
  84. package/dist/scoped-fs.js.map +1 -0
  85. package/dist/selector-generator.js +8126 -0
  86. package/dist/start-relay-server.d.ts +6 -0
  87. package/dist/start-relay-server.d.ts.map +1 -0
  88. package/dist/start-relay-server.js +33 -0
  89. package/dist/start-relay-server.js.map +1 -0
  90. package/dist/styles-api.md +117 -0
  91. package/dist/styles-examples.d.ts +8 -0
  92. package/dist/styles-examples.d.ts.map +1 -0
  93. package/dist/styles-examples.js +64 -0
  94. package/dist/styles-examples.js.map +1 -0
  95. package/dist/styles.d.ts +27 -0
  96. package/dist/styles.d.ts.map +1 -0
  97. package/dist/styles.js +234 -0
  98. package/dist/styles.js.map +1 -0
  99. package/dist/trace-utils.d.ts +14 -0
  100. package/dist/trace-utils.d.ts.map +1 -0
  101. package/dist/trace-utils.js +21 -0
  102. package/dist/trace-utils.js.map +1 -0
  103. package/dist/utils.d.ts +20 -0
  104. package/dist/utils.d.ts.map +1 -0
  105. package/dist/utils.js +75 -0
  106. package/dist/utils.js.map +1 -0
  107. package/dist/wait-for-page-load.d.ts +16 -0
  108. package/dist/wait-for-page-load.d.ts.map +1 -0
  109. package/dist/wait-for-page-load.js +127 -0
  110. package/dist/wait-for-page-load.js.map +1 -0
  111. package/package.json +67 -0
  112. package/src/aria-snapshot.ts +610 -0
  113. package/src/assets/aria-labels-github-snapshot.txt +605 -0
  114. package/src/assets/aria-labels-github.png +0 -0
  115. package/src/assets/aria-labels-google-snapshot.txt +49 -0
  116. package/src/assets/aria-labels-google.png +0 -0
  117. package/src/assets/aria-labels-hacker-news-snapshot.txt +1023 -0
  118. package/src/assets/aria-labels-hacker-news.png +0 -0
  119. package/src/cdp-relay.ts +925 -0
  120. package/src/cdp-session.ts +203 -0
  121. package/src/cdp-timing.md +128 -0
  122. package/src/cdp-types.ts +155 -0
  123. package/src/cli.ts +250 -0
  124. package/src/create-logger.ts +36 -0
  125. package/src/debugger-examples-types.ts +13 -0
  126. package/src/debugger-examples.ts +66 -0
  127. package/src/debugger.md +453 -0
  128. package/src/debugger.ts +713 -0
  129. package/src/editor-examples.ts +148 -0
  130. package/src/editor.ts +390 -0
  131. package/src/execute.ts +763 -0
  132. package/src/index.ts +10 -0
  133. package/src/mcp-client.ts +78 -0
  134. package/src/mcp.test.ts +3596 -0
  135. package/src/mcp.ts +876 -0
  136. package/src/network-capture.ts +140 -0
  137. package/src/prompt.bak.md +323 -0
  138. package/src/prompt.md +7 -0
  139. package/src/protocol.ts +63 -0
  140. package/src/react-source.ts +94 -0
  141. package/src/resource.md +436 -0
  142. package/src/scoped-fs.ts +411 -0
  143. package/src/snapshots/hacker-news-focused-accessibility.md +202 -0
  144. package/src/snapshots/hacker-news-initial-accessibility.md +11 -0
  145. package/src/snapshots/hacker-news-tabbed-accessibility.md +202 -0
  146. package/src/snapshots/shadcn-ui-accessibility.md +11 -0
  147. package/src/start-relay-server.ts +43 -0
  148. package/src/styles-examples.ts +77 -0
  149. package/src/styles.ts +345 -0
  150. package/src/trace-utils.ts +43 -0
  151. package/src/utils.ts +91 -0
  152. package/src/wait-for-page-load.ts +174 -0
package/src/cli.ts ADDED
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { cac } from 'cac'
4
+ import fs from 'node:fs'
5
+ import path from 'node:path'
6
+ import { spawn } from 'node:child_process'
7
+ import { fileURLToPath } from 'node:url'
8
+ import { chromium, Page } from 'playwright-core'
9
+ import { startE2EPilotCDPRelayServer } from './cdp-relay.js'
10
+ import { createFileLogger } from './create-logger.js'
11
+ import {
12
+ getCdpUrl,
13
+ VERSION,
14
+ sleep,
15
+ RELAY_PORT,
16
+ getServerVersion,
17
+ setDeviceScaleFactorForMacOS,
18
+ preserveSystemColorScheme,
19
+ } from './utils.js'
20
+ import { executeCode } from './execute.js'
21
+ import { CDPSession } from './cdp-session.js'
22
+
23
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
24
+
25
+ const cli = cac('e2e-pilot')
26
+
27
+ cli
28
+ .command('', 'Start the MCP server (default)')
29
+ .option('--host <host>', 'Remote relay server host to connect to (or use E2E_PILOT_HOST env var)')
30
+ .option('--token <token>', 'Authentication token (or use E2E_PILOT_TOKEN env var)')
31
+ .action(async (options: { host?: string; token?: string }) => {
32
+ const { startMcp } = await import('./mcp.js')
33
+ await startMcp({
34
+ host: options.host,
35
+ token: options.token,
36
+ })
37
+ })
38
+
39
+ cli
40
+ .command('serve', 'Start the CDP relay server for remote MCP connections')
41
+ .option('--host <host>', 'Host to bind to', { default: '0.0.0.0' })
42
+ .option('--token <token>', 'Authentication token (or use E2E_PILOT_TOKEN env var)')
43
+ .action(async (options: { host: string; token?: string }) => {
44
+ const token = options.token || process.env.E2E_PILOT_TOKEN
45
+ if (!token) {
46
+ console.error('Error: Authentication token is required.')
47
+ console.error('Provide --token <token> or set E2E_PILOT_TOKEN environment variable.')
48
+ process.exit(1)
49
+ }
50
+
51
+ const logger = createFileLogger()
52
+
53
+ process.title = 'e2e-pilot-serve'
54
+
55
+ process.on('uncaughtException', async (err) => {
56
+ await logger.error('Uncaught Exception:', err)
57
+ process.exit(1)
58
+ })
59
+
60
+ process.on('unhandledRejection', async (reason) => {
61
+ await logger.error('Unhandled Rejection:', reason)
62
+ process.exit(1)
63
+ })
64
+
65
+ const server = await startE2EPilotCDPRelayServer({
66
+ port: RELAY_PORT,
67
+ host: options.host,
68
+ token,
69
+ logger,
70
+ })
71
+
72
+ console.log('E2E Pilot CDP relay server started')
73
+ console.log(` Host: ${options.host}`)
74
+ console.log(` Port: ${RELAY_PORT}`)
75
+ console.log(` Token: (configured)`)
76
+ console.log(` Logs: ${logger.logFilePath}`)
77
+ console.log('')
78
+ console.log('Endpoints:')
79
+ console.log(` Extension: ws://${options.host}:${RELAY_PORT}/extension`)
80
+ console.log(` CDP: ws://${options.host}:${RELAY_PORT}/cdp/<client-id>?token=<token>`)
81
+ console.log('')
82
+ console.log('Press Ctrl+C to stop.')
83
+
84
+ process.on('SIGINT', () => {
85
+ console.log('\nShutting down...')
86
+ server.close()
87
+ process.exit(0)
88
+ })
89
+
90
+ process.on('SIGTERM', () => {
91
+ console.log('\nShutting down...')
92
+ server.close()
93
+ process.exit(0)
94
+ })
95
+ })
96
+
97
+ cli
98
+ .command('run [...files]', 'Execute Playwright code from file(s), --code, or stdin and exit')
99
+ .option('-c, --code <code>', 'Execute code passed as a string')
100
+ .option('--timeout <ms>', 'Execution timeout in milliseconds', { default: 30000 })
101
+ .option('--host <host>', 'Remote relay server host (or use E2E_PILOT_HOST env var)')
102
+ .option('--token <token>', 'Authentication token for remote (or use E2E_PILOT_TOKEN env var)')
103
+ .action(async (files: string[], options: { code?: string; timeout: number; host?: string; token?: string }) => {
104
+ // Priority: --code flag > stdin > files
105
+ const code: string = await (async () => {
106
+ if (options.code) {
107
+ return options.code
108
+ }
109
+ if (!process.stdin.isTTY) {
110
+ return await readStdin()
111
+ }
112
+ if (files.length > 0) {
113
+ const codeChunks: string[] = []
114
+ for (const file of files) {
115
+ const filePath = path.resolve(file)
116
+ if (!fs.existsSync(filePath)) {
117
+ console.error(`Error: File not found: ${filePath}`)
118
+ process.exit(1)
119
+ }
120
+ const content = fs.readFileSync(filePath, 'utf-8')
121
+ codeChunks.push(content)
122
+ }
123
+ return codeChunks.join('\n')
124
+ }
125
+ console.error('Error: Provide code via --code, stdin, or file path(s)')
126
+ console.error('Usage: e2e-pilot run -c "code" | e2e-pilot run <file.js> | echo "code" | e2e-pilot run')
127
+ process.exit(1)
128
+ })()
129
+
130
+ // Set up environment for remote connection if specified
131
+ const host = options.host || process.env.E2E_PILOT_HOST
132
+ const token = options.token || process.env.E2E_PILOT_TOKEN
133
+
134
+ try {
135
+ // Ensure relay server is running (for local mode)
136
+ if (!host) {
137
+ await ensureRelayServerForCli()
138
+ }
139
+
140
+ // Connect to browser
141
+ const cdpEndpoint = getCdpUrl(host ? { host, port: RELAY_PORT, token } : { port: RELAY_PORT })
142
+ console.error(`Connecting to CDP endpoint: ${cdpEndpoint}`)
143
+ const browser = await chromium.connectOverCDP(cdpEndpoint)
144
+ console.error('Connected to browser')
145
+
146
+ const contexts = browser.contexts()
147
+ const context = contexts.length > 0 ? contexts[0] : await browser.newContext()
148
+ const pages = context.pages()
149
+ if (pages.length === 0) {
150
+ console.error('Error: No browser tabs are connected.')
151
+ console.error('Please install and enable the E2E Pilot extension on at least one tab.')
152
+ process.exit(1)
153
+ }
154
+ const page = pages[0]
155
+
156
+ // Apply macOS device scale factor
157
+ await setDeviceScaleFactorForMacOS(context)
158
+ await preserveSystemColorScheme(context)
159
+
160
+ // Execute the code
161
+ const result = await executeCode({
162
+ code,
163
+ timeout: options.timeout,
164
+ deps: {
165
+ page,
166
+ context,
167
+ userState: {},
168
+ browserLogs: new Map(),
169
+ lastSnapshots: new WeakMap(),
170
+ cdpSessionCache: new WeakMap<Page, CDPSession>(),
171
+ getPageTargetId: async (p: Page) => (p as any)._guid || '',
172
+ getCdpUrl: () => getCdpUrl(host ? { host, port: RELAY_PORT, token } : { port: RELAY_PORT }),
173
+ resetConnection: async () => {
174
+ throw new Error('resetConnection is not supported in run mode')
175
+ },
176
+ logger: (...args) => {
177
+ console.error(...args)
178
+ },
179
+ sendLogToRelayServer: () => {},
180
+ },
181
+ })
182
+
183
+ // Output result
184
+ for (const item of result.content) {
185
+ if (item.type === 'text') {
186
+ console.log(item.text)
187
+ } else if (item.type === 'image') {
188
+ console.log(`[Image: ${item.mimeType}]`)
189
+ }
190
+ }
191
+
192
+ // Disconnect and exit
193
+ await browser.close().catch(() => {})
194
+ process.exit(result.isError ? 1 : 0)
195
+ } catch (error: any) {
196
+ console.error('Error:', error.message)
197
+ process.exit(1)
198
+ }
199
+ })
200
+
201
+ async function ensureRelayServerForCli(): Promise<void> {
202
+ const serverVersion = await getServerVersion()
203
+ if (serverVersion === VERSION) {
204
+ return
205
+ }
206
+
207
+ console.error('Starting CDP relay server...')
208
+
209
+ const dev = process.env.E2E_PILOT_NODE_ENV === 'development'
210
+ const scriptPath = dev
211
+ ? path.resolve(__dirname, '../src/start-relay-server.ts')
212
+ : path.resolve(__dirname, 'start-relay-server.js')
213
+
214
+ const serverProcess = spawn(dev ? 'tsx' : process.execPath, [scriptPath], {
215
+ detached: true,
216
+ stdio: 'ignore',
217
+ })
218
+ serverProcess.unref()
219
+
220
+ for (let i = 0; i < 10; i++) {
221
+ await sleep(500)
222
+ const newVersion = await getServerVersion()
223
+ if (newVersion === VERSION) {
224
+ console.error('CDP relay server started')
225
+ await sleep(1000)
226
+ return
227
+ }
228
+ }
229
+
230
+ throw new Error('Failed to start CDP relay server after 5 seconds')
231
+ }
232
+
233
+ async function readStdin(): Promise<string> {
234
+ return new Promise((resolve, reject) => {
235
+ let data = ''
236
+ process.stdin.setEncoding('utf-8')
237
+ process.stdin.on('data', (chunk) => {
238
+ data += chunk
239
+ })
240
+ process.stdin.on('end', () => {
241
+ resolve(data)
242
+ })
243
+ process.stdin.on('error', reject)
244
+ })
245
+ }
246
+
247
+ cli.help()
248
+ cli.version(VERSION)
249
+
250
+ cli.parse()
@@ -0,0 +1,36 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import util from 'node:util'
4
+ import stripAnsi from 'strip-ansi'
5
+ import { LOG_FILE_PATH } from './utils.js'
6
+
7
+ export type Logger = {
8
+ log(...args: unknown[]): Promise<void>
9
+ error(...args: unknown[]): Promise<void>
10
+ logFilePath: string
11
+ }
12
+
13
+ export function createFileLogger({ logFilePath }: { logFilePath?: string } = {}): Logger {
14
+ const resolvedLogFilePath = logFilePath || LOG_FILE_PATH
15
+ const logDir = path.dirname(resolvedLogFilePath)
16
+ if (!fs.existsSync(logDir)) {
17
+ fs.mkdirSync(logDir, { recursive: true })
18
+ }
19
+ fs.writeFileSync(resolvedLogFilePath, '')
20
+
21
+ let queue: Promise<void> = Promise.resolve()
22
+
23
+ const log = (...args: unknown[]): Promise<void> => {
24
+ const message = args.map(arg =>
25
+ typeof arg === 'string' ? arg : util.inspect(arg, { depth: null, colors: false })
26
+ ).join(' ')
27
+ queue = queue.then(() => fs.promises.appendFile(resolvedLogFilePath, stripAnsi(message) + '\n'))
28
+ return queue
29
+ }
30
+
31
+ return {
32
+ log,
33
+ error: log,
34
+ logFilePath: resolvedLogFilePath,
35
+ }
36
+ }
@@ -0,0 +1,13 @@
1
+ import type { Page, Locator } from 'playwright-core'
2
+ import type { CDPSession } from './cdp-session.js'
3
+ import type { Debugger } from './debugger.js'
4
+ import type { Editor } from './editor.js'
5
+ import type { StylesResult } from './styles.js'
6
+
7
+ export declare const page: Page
8
+ export declare const getCDPSession: (options: { page: Page }) => Promise<CDPSession>
9
+ export declare const createDebugger: (options: { cdp: CDPSession }) => Debugger
10
+ export declare const createEditor: (options: { cdp: CDPSession }) => Editor
11
+ export declare const getStylesForLocator: (options: { locator: Locator; includeUserAgentStyles?: boolean }) => Promise<StylesResult>
12
+ export declare const formatStylesAsText: (styles: StylesResult) => string
13
+ export declare const console: { log: (...args: unknown[]) => void }
@@ -0,0 +1,66 @@
1
+ import { page, getCDPSession, createDebugger, console } from './debugger-examples-types.js'
2
+
3
+ // Example: List available scripts and set a breakpoint
4
+ async function listScriptsAndSetBreakpoint() {
5
+ const cdp = await getCDPSession({ page })
6
+ const dbg = createDebugger({ cdp })
7
+ await dbg.enable()
8
+
9
+ const scripts = await dbg.listScripts({ search: 'app' })
10
+ console.log(scripts)
11
+
12
+ if (scripts.length > 0) {
13
+ const bpId = await dbg.setBreakpoint({ file: scripts[0].url, line: 100 })
14
+ console.log('Breakpoint set:', bpId)
15
+ }
16
+ }
17
+
18
+ // Example: Inspect state when paused at a breakpoint
19
+ async function inspectWhenPaused() {
20
+ const cdp = await getCDPSession({ page })
21
+ const dbg = createDebugger({ cdp })
22
+ await dbg.enable()
23
+
24
+ if (dbg.isPaused()) {
25
+ const loc = await dbg.getLocation()
26
+ console.log('Paused at:', loc.url, 'line', loc.lineNumber)
27
+ console.log('Source:', loc.sourceContext)
28
+
29
+ const vars = await dbg.inspectLocalVariables()
30
+ console.log('Variables:', vars)
31
+
32
+ const result = await dbg.evaluate({ expression: 'myVar.length' })
33
+ console.log('myVar.length =', result.value)
34
+
35
+ await dbg.stepOver()
36
+ }
37
+ }
38
+
39
+ // Example: Step through code
40
+ async function stepThroughCode() {
41
+ const cdp = await getCDPSession({ page })
42
+ const dbg = createDebugger({ cdp })
43
+ await dbg.enable()
44
+
45
+ await dbg.setBreakpoint({ file: 'https://example.com/app.js', line: 42 })
46
+
47
+ if (dbg.isPaused()) {
48
+ await dbg.stepOver()
49
+ await dbg.stepInto()
50
+ await dbg.stepOut()
51
+ await dbg.resume()
52
+ }
53
+ }
54
+
55
+ // Example: Cleanup all breakpoints
56
+ async function cleanupBreakpoints() {
57
+ const cdp = await getCDPSession({ page })
58
+ const dbg = createDebugger({ cdp })
59
+
60
+ const breakpoints = dbg.listBreakpoints()
61
+ for (const bp of breakpoints) {
62
+ await dbg.deleteBreakpoint({ breakpointId: bp.id })
63
+ }
64
+ }
65
+
66
+ export { listScriptsAndSetBreakpoint, inspectWhenPaused, stepThroughCode, cleanupBreakpoints }