@ai2qa/local-agent 0.1.0
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 +254 -0
- package/bin/ai2qa-agent +12 -0
- package/dist/browser/connection.d.ts +80 -0
- package/dist/browser/connection.d.ts.map +1 -0
- package/dist/browser/connection.js +165 -0
- package/dist/browser/connection.js.map +1 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +231 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +56 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +387 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/click.d.ts +12 -0
- package/dist/tools/click.d.ts.map +1 -0
- package/dist/tools/click.js +61 -0
- package/dist/tools/click.js.map +1 -0
- package/dist/tools/evaluate.d.ts +9 -0
- package/dist/tools/evaluate.d.ts.map +1 -0
- package/dist/tools/evaluate.js +77 -0
- package/dist/tools/evaluate.js.map +1 -0
- package/dist/tools/fill.d.ts +9 -0
- package/dist/tools/fill.d.ts.map +1 -0
- package/dist/tools/fill.js +48 -0
- package/dist/tools/fill.js.map +1 -0
- package/dist/tools/hover.d.ts +9 -0
- package/dist/tools/hover.d.ts.map +1 -0
- package/dist/tools/hover.js +44 -0
- package/dist/tools/hover.js.map +1 -0
- package/dist/tools/index.d.ts +18 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +51 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/knowledge.d.ts +56 -0
- package/dist/tools/knowledge.d.ts.map +1 -0
- package/dist/tools/knowledge.js +98 -0
- package/dist/tools/knowledge.js.map +1 -0
- package/dist/tools/navigate.d.ts +9 -0
- package/dist/tools/navigate.d.ts.map +1 -0
- package/dist/tools/navigate.js +48 -0
- package/dist/tools/navigate.js.map +1 -0
- package/dist/tools/press-key.d.ts +9 -0
- package/dist/tools/press-key.d.ts.map +1 -0
- package/dist/tools/press-key.js +38 -0
- package/dist/tools/press-key.js.map +1 -0
- package/dist/tools/report.d.ts +29 -0
- package/dist/tools/report.d.ts.map +1 -0
- package/dist/tools/report.js +92 -0
- package/dist/tools/report.js.map +1 -0
- package/dist/tools/screenshot.d.ts +9 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +54 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/snapshot.d.ts +13 -0
- package/dist/tools/snapshot.d.ts.map +1 -0
- package/dist/tools/snapshot.js +134 -0
- package/dist/tools/snapshot.js.map +1 -0
- package/dist/tools/types.d.ts +329 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +102 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/wait.d.ts +9 -0
- package/dist/tools/wait.d.ts.map +1 -0
- package/dist/tools/wait.js +64 -0
- package/dist/tools/wait.js.map +1 -0
- package/dist/transports/index.d.ts +8 -0
- package/dist/transports/index.d.ts.map +1 -0
- package/dist/transports/index.js +14 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/transports/stdio.d.ts +8 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +12 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/transports/websocket.d.ts +87 -0
- package/dist/transports/websocket.d.ts.map +1 -0
- package/dist/transports/websocket.js +200 -0
- package/dist/transports/websocket.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# AI2QA Local Agent
|
|
2
|
+
|
|
3
|
+
Universal MCP Server for browser automation. Enables both local AI tools (Claude Code, Cursor, Antigravity) and AI2QA cloud to control browsers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Sidecar Mode**: Attach to existing Chrome sessions (preserves cookies, auth, VPN access)
|
|
8
|
+
- **MCP Protocol**: Standard Model Context Protocol for AI tool integration
|
|
9
|
+
- **9 Browser Tools**: navigate, click, fill, hover, press-key, screenshot, snapshot, wait, evaluate
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cd ai2qa-local-agent
|
|
17
|
+
npm install
|
|
18
|
+
npm run build
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 2. Start Chrome with Remote Debugging
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# macOS
|
|
25
|
+
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
|
|
26
|
+
|
|
27
|
+
# Linux
|
|
28
|
+
google-chrome --remote-debugging-port=9222
|
|
29
|
+
|
|
30
|
+
# Windows
|
|
31
|
+
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. Start the Agent
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Sidecar mode (attach to existing Chrome)
|
|
38
|
+
npm start -- start --sidecar
|
|
39
|
+
|
|
40
|
+
# Or with custom port
|
|
41
|
+
npm start -- start --sidecar --port 9222
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## CLI Commands
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Start with stdio (for local AI tools like Claude Code)
|
|
48
|
+
ai2qa-agent start
|
|
49
|
+
|
|
50
|
+
# Start with sidecar mode (default) with custom CDP port
|
|
51
|
+
ai2qa-agent start --sidecar --port 9222
|
|
52
|
+
|
|
53
|
+
# Start in headless mode (no visible browser window)
|
|
54
|
+
ai2qa-agent start --headless
|
|
55
|
+
|
|
56
|
+
# Login to AI2QA cloud (for remote orchestration)
|
|
57
|
+
ai2qa-agent login <token>
|
|
58
|
+
|
|
59
|
+
# Start connected to AI2QA cloud
|
|
60
|
+
ai2qa-agent start --cloud
|
|
61
|
+
|
|
62
|
+
# Check agent status
|
|
63
|
+
ai2qa-agent status
|
|
64
|
+
|
|
65
|
+
# Logout and clear credentials
|
|
66
|
+
ai2qa-agent logout
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Claude Code Integration
|
|
70
|
+
|
|
71
|
+
Add to `~/.config/claude/claude_desktop_config.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"ai2qa": {
|
|
77
|
+
"command": "node",
|
|
78
|
+
"args": ["/path/to/ai2qa-local-agent/dist/index.js", "start", "--sidecar"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or after global install:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm install -g @ai2qa/local-agent
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Then configure:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"mcpServers": {
|
|
95
|
+
"ai2qa": {
|
|
96
|
+
"command": "ai2qa-agent",
|
|
97
|
+
"args": ["start", "--sidecar"]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## AI2QA Cloud Integration
|
|
104
|
+
|
|
105
|
+
To connect your local agent to AI2QA cloud for remote test orchestration:
|
|
106
|
+
|
|
107
|
+
1. **Generate a device token** from the AI2QA web UI at `https://ai2qa.com/agents`
|
|
108
|
+
|
|
109
|
+
2. **Login with your token**:
|
|
110
|
+
```bash
|
|
111
|
+
ai2qa-agent login <your-token>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
3. **Start in cloud mode**:
|
|
115
|
+
```bash
|
|
116
|
+
ai2qa-agent start --cloud
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The agent will connect to AI2QA cloud and be available for running test runs from the web interface. This enables testing on internal applications behind VPNs using your local browser session.
|
|
120
|
+
|
|
121
|
+
## Available Tools
|
|
122
|
+
|
|
123
|
+
### navigate_page
|
|
124
|
+
Navigate to a URL or perform navigation actions.
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"url": "https://example.com",
|
|
129
|
+
"type": "goto" // goto, reload, back, forward
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### click
|
|
134
|
+
Click on an element by selector or ref.
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"selector": "button#submit"
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### fill
|
|
143
|
+
Fill an input field with text.
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"selector": "input[name='email']",
|
|
148
|
+
"value": "test@example.com"
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### hover
|
|
153
|
+
Hover over an element.
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"selector": ".menu-trigger"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### press_key
|
|
162
|
+
Press a keyboard key.
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"key": "Enter",
|
|
167
|
+
"modifiers": ["Control"]
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### take_screenshot
|
|
172
|
+
Capture a screenshot.
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"fullPage": true,
|
|
177
|
+
"format": "png"
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### take_snapshot
|
|
182
|
+
Get accessibility tree/DOM snapshot for AI analysis.
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"verbose": true,
|
|
187
|
+
"mode": "accessibility"
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### wait_for
|
|
192
|
+
Wait for element, text, or duration.
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"selector": ".loaded",
|
|
197
|
+
"state": "visible",
|
|
198
|
+
"timeout": 5000
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### evaluate
|
|
203
|
+
Execute JavaScript in page context.
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"script": "document.title"
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Build
|
|
215
|
+
npm run build
|
|
216
|
+
|
|
217
|
+
# Watch mode
|
|
218
|
+
npm run dev
|
|
219
|
+
|
|
220
|
+
# Run tests
|
|
221
|
+
npm test
|
|
222
|
+
|
|
223
|
+
# Lint
|
|
224
|
+
npm run lint
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Architecture
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
┌─────────────────────────────────────────────────────────┐
|
|
231
|
+
│ AI2QA Local Agent │
|
|
232
|
+
│ │
|
|
233
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │
|
|
234
|
+
│ │ Stdio │ │ MCP Server │ │ WebSocket │ │
|
|
235
|
+
│ │ Transport │───►│ (9 tools) │◄───│ Transport │ │
|
|
236
|
+
│ └─────────────┘ └──────┬───────┘ └────────────┘ │
|
|
237
|
+
│ ▲ │ ▲ │
|
|
238
|
+
│ │ ▼ │ │
|
|
239
|
+
│ [Claude Code] ┌──────────────┐ [AI2QA Cloud] │
|
|
240
|
+
│ [Cursor] │ Playwright │ │
|
|
241
|
+
│ │ CDP Bridge │ │
|
|
242
|
+
│ └──────┬───────┘ │
|
|
243
|
+
└────────────────────────────┼────────────────────────────┘
|
|
244
|
+
│
|
|
245
|
+
▼
|
|
246
|
+
┌────────────────────────────────────────────────────────┐
|
|
247
|
+
│ Chrome (--remote-debugging-port=9222) │
|
|
248
|
+
│ [Already logged into VPN, SSO, internal apps] │
|
|
249
|
+
└────────────────────────────────────────────────────────┘
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
MIT
|
package/bin/ai2qa-agent
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AI2QA Local Agent CLI Entry Point
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import('../dist/index.js').catch((err) => {
|
|
8
|
+
console.error('Failed to start ai2qa-agent:', err.message);
|
|
9
|
+
console.error('');
|
|
10
|
+
console.error('If you see "Cannot find module", run: npm run build');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Connection Manager
|
|
3
|
+
*
|
|
4
|
+
* Handles two connection modes:
|
|
5
|
+
* 1. Sidecar Mode: Attach to existing Chrome via CDP (for cookie/auth bypass)
|
|
6
|
+
* 2. Launch Mode: Start new browser instance (for CI/CD)
|
|
7
|
+
*/
|
|
8
|
+
import { Page } from 'playwright';
|
|
9
|
+
/** Connection mode for the browser */
|
|
10
|
+
export type ConnectionMode = 'sidecar' | 'launch';
|
|
11
|
+
/** Configuration for browser connection */
|
|
12
|
+
export interface BrowserConfig {
|
|
13
|
+
readonly mode: ConnectionMode;
|
|
14
|
+
readonly cdpUrl?: string;
|
|
15
|
+
readonly headless?: boolean;
|
|
16
|
+
readonly viewport?: {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Result type for operations that can fail */
|
|
22
|
+
export type Result<T, E = Error> = {
|
|
23
|
+
readonly success: true;
|
|
24
|
+
readonly value: T;
|
|
25
|
+
} | {
|
|
26
|
+
readonly success: false;
|
|
27
|
+
readonly error: E;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Browser Connection Manager
|
|
31
|
+
* Manages browser lifecycle and provides access to the active page.
|
|
32
|
+
*/
|
|
33
|
+
export declare class BrowserConnection {
|
|
34
|
+
private state;
|
|
35
|
+
private readonly config;
|
|
36
|
+
constructor(config?: Partial<BrowserConfig>);
|
|
37
|
+
/**
|
|
38
|
+
* Connect to browser based on configured mode.
|
|
39
|
+
* Returns Result to avoid throwing exceptions.
|
|
40
|
+
*/
|
|
41
|
+
connect(): Promise<Result<Page>>;
|
|
42
|
+
/**
|
|
43
|
+
* Sidecar mode: Attach to existing Chrome via CDP.
|
|
44
|
+
* Chrome must be started with: --remote-debugging-port=9222
|
|
45
|
+
*/
|
|
46
|
+
private connectSidecar;
|
|
47
|
+
/**
|
|
48
|
+
* Launch mode: Start new browser instance.
|
|
49
|
+
*/
|
|
50
|
+
private launchBrowser;
|
|
51
|
+
/**
|
|
52
|
+
* Get the active page, connecting if necessary.
|
|
53
|
+
*/
|
|
54
|
+
getPage(): Promise<Result<Page>>;
|
|
55
|
+
/**
|
|
56
|
+
* Check if connected to a browser.
|
|
57
|
+
*/
|
|
58
|
+
isConnected(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Get current page URL, or empty string if not connected.
|
|
61
|
+
*/
|
|
62
|
+
getCurrentUrl(): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Disconnect from browser.
|
|
65
|
+
* In sidecar mode, only disconnects (doesn't close Chrome).
|
|
66
|
+
* In launch mode, closes the browser.
|
|
67
|
+
*/
|
|
68
|
+
disconnect(): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Create a new page in the current context.
|
|
71
|
+
*/
|
|
72
|
+
newPage(): Promise<Result<Page>>;
|
|
73
|
+
/**
|
|
74
|
+
* Close current page and switch to another if available.
|
|
75
|
+
*/
|
|
76
|
+
closePage(): Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
/** Factory function for creating browser connections */
|
|
79
|
+
export declare function createBrowserConnection(config?: Partial<BrowserConfig>): BrowserConnection;
|
|
80
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/browser/connection.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAqC,IAAI,EAAE,MAAM,YAAY,CAAC;AAErE,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAElD,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED,+CAA+C;AAC/C,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,IACzB;IAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC7C;IAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAYrD;;;GAGG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,KAAK,CAIX;IACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;IAS/C;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IA0BtC;;;OAGG;YACW,cAAc;IAM5B;;OAEG;YACW,aAAa;IAO3B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAOtC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAMtC;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBjC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IActC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAenC;AAED,wDAAwD;AACxD,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,iBAAiB,CAE1F"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Browser Connection Manager
|
|
4
|
+
*
|
|
5
|
+
* Handles two connection modes:
|
|
6
|
+
* 1. Sidecar Mode: Attach to existing Chrome via CDP (for cookie/auth bypass)
|
|
7
|
+
* 2. Launch Mode: Start new browser instance (for CI/CD)
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.BrowserConnection = void 0;
|
|
11
|
+
exports.createBrowserConnection = createBrowserConnection;
|
|
12
|
+
const playwright_1 = require("playwright");
|
|
13
|
+
const DEFAULT_VIEWPORT = { width: 1920, height: 1080 };
|
|
14
|
+
const DEFAULT_CDP_URL = 'http://localhost:9222';
|
|
15
|
+
/**
|
|
16
|
+
* Browser Connection Manager
|
|
17
|
+
* Manages browser lifecycle and provides access to the active page.
|
|
18
|
+
*/
|
|
19
|
+
class BrowserConnection {
|
|
20
|
+
state = {
|
|
21
|
+
browser: null,
|
|
22
|
+
context: null,
|
|
23
|
+
page: null,
|
|
24
|
+
};
|
|
25
|
+
config;
|
|
26
|
+
constructor(config = {}) {
|
|
27
|
+
this.config = {
|
|
28
|
+
mode: config.mode ?? 'sidecar',
|
|
29
|
+
cdpUrl: config.cdpUrl ?? DEFAULT_CDP_URL,
|
|
30
|
+
headless: config.headless ?? false,
|
|
31
|
+
viewport: config.viewport ?? DEFAULT_VIEWPORT,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Connect to browser based on configured mode.
|
|
36
|
+
* Returns Result to avoid throwing exceptions.
|
|
37
|
+
*/
|
|
38
|
+
async connect() {
|
|
39
|
+
try {
|
|
40
|
+
const browser = this.config.mode === 'sidecar'
|
|
41
|
+
? await this.connectSidecar()
|
|
42
|
+
: await this.launchBrowser();
|
|
43
|
+
this.state.browser = browser;
|
|
44
|
+
// Get or create context and page
|
|
45
|
+
const contexts = browser.contexts();
|
|
46
|
+
this.state.context = contexts.length > 0
|
|
47
|
+
? contexts[0]
|
|
48
|
+
: await browser.newContext({ viewport: this.config.viewport });
|
|
49
|
+
const pages = this.state.context.pages();
|
|
50
|
+
this.state.page = pages.length > 0
|
|
51
|
+
? pages[0]
|
|
52
|
+
: await this.state.context.newPage();
|
|
53
|
+
return { success: true, value: this.state.page };
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
57
|
+
return { success: false, error };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Sidecar mode: Attach to existing Chrome via CDP.
|
|
62
|
+
* Chrome must be started with: --remote-debugging-port=9222
|
|
63
|
+
*/
|
|
64
|
+
async connectSidecar() {
|
|
65
|
+
const cdpUrl = this.config.cdpUrl ?? DEFAULT_CDP_URL;
|
|
66
|
+
console.error(`[BrowserConnection] Connecting to Chrome via CDP: ${cdpUrl}`);
|
|
67
|
+
return playwright_1.chromium.connectOverCDP(cdpUrl);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Launch mode: Start new browser instance.
|
|
71
|
+
*/
|
|
72
|
+
async launchBrowser() {
|
|
73
|
+
console.error(`[BrowserConnection] Launching new browser (headless: ${this.config.headless})`);
|
|
74
|
+
return playwright_1.chromium.launch({
|
|
75
|
+
headless: this.config.headless,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the active page, connecting if necessary.
|
|
80
|
+
*/
|
|
81
|
+
async getPage() {
|
|
82
|
+
if (this.state.page && !this.state.page.isClosed()) {
|
|
83
|
+
return { success: true, value: this.state.page };
|
|
84
|
+
}
|
|
85
|
+
return this.connect();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if connected to a browser.
|
|
89
|
+
*/
|
|
90
|
+
isConnected() {
|
|
91
|
+
return this.state.browser !== null && this.state.browser.isConnected();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get current page URL, or empty string if not connected.
|
|
95
|
+
*/
|
|
96
|
+
async getCurrentUrl() {
|
|
97
|
+
const result = await this.getPage();
|
|
98
|
+
if (!result.success)
|
|
99
|
+
return '';
|
|
100
|
+
return result.value.url();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Disconnect from browser.
|
|
104
|
+
* In sidecar mode, only disconnects (doesn't close Chrome).
|
|
105
|
+
* In launch mode, closes the browser.
|
|
106
|
+
*/
|
|
107
|
+
async disconnect() {
|
|
108
|
+
try {
|
|
109
|
+
if (this.state.browser) {
|
|
110
|
+
if (this.config.mode === 'launch') {
|
|
111
|
+
await this.state.browser.close();
|
|
112
|
+
}
|
|
113
|
+
// Sidecar mode: browser.close() just disconnects without closing Chrome
|
|
114
|
+
// For CDP connections, close() is safe and doesn't terminate the browser
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
console.error('[BrowserConnection] Error during disconnect:', err);
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
this.state = { browser: null, context: null, page: null };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Create a new page in the current context.
|
|
126
|
+
*/
|
|
127
|
+
async newPage() {
|
|
128
|
+
if (!this.state.context) {
|
|
129
|
+
return { success: false, error: new Error('Not connected to browser') };
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const page = await this.state.context.newPage();
|
|
133
|
+
this.state.page = page;
|
|
134
|
+
return { success: true, value: page };
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
138
|
+
return { success: false, error };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Close current page and switch to another if available.
|
|
143
|
+
*/
|
|
144
|
+
async closePage() {
|
|
145
|
+
if (!this.state.page)
|
|
146
|
+
return;
|
|
147
|
+
try {
|
|
148
|
+
await this.state.page.close();
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Page might already be closed
|
|
152
|
+
}
|
|
153
|
+
// Switch to another page if available
|
|
154
|
+
if (this.state.context) {
|
|
155
|
+
const pages = this.state.context.pages();
|
|
156
|
+
this.state.page = pages.length > 0 ? pages[0] : null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
exports.BrowserConnection = BrowserConnection;
|
|
161
|
+
/** Factory function for creating browser connections */
|
|
162
|
+
function createBrowserConnection(config) {
|
|
163
|
+
return new BrowserConnection(config);
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/browser/connection.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Management
|
|
3
|
+
*
|
|
4
|
+
* Handles loading/saving agent configuration including:
|
|
5
|
+
* - Cloud connection settings
|
|
6
|
+
* - Device token storage
|
|
7
|
+
* - Agent identity
|
|
8
|
+
*/
|
|
9
|
+
/** Agent configuration */
|
|
10
|
+
export interface AgentConfig {
|
|
11
|
+
/** Unique agent identifier */
|
|
12
|
+
agentId: string;
|
|
13
|
+
/** Device name for identification */
|
|
14
|
+
deviceName: string;
|
|
15
|
+
/** AI2QA cloud WebSocket URL */
|
|
16
|
+
cloudUrl: string;
|
|
17
|
+
/** Encrypted device token */
|
|
18
|
+
encryptedToken?: string;
|
|
19
|
+
/** Token expiration timestamp */
|
|
20
|
+
tokenExpiresAt?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Load agent configuration from disk.
|
|
24
|
+
*/
|
|
25
|
+
export declare function loadConfig(): AgentConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Save agent configuration to disk.
|
|
28
|
+
*/
|
|
29
|
+
export declare function saveConfig(config: Partial<AgentConfig>): void;
|
|
30
|
+
/**
|
|
31
|
+
* Store device token securely.
|
|
32
|
+
*/
|
|
33
|
+
export declare function storeToken(token: string, expiresAt?: Date): void;
|
|
34
|
+
/**
|
|
35
|
+
* Retrieve stored device token.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getToken(): string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Check if agent is logged in (has valid token).
|
|
40
|
+
*/
|
|
41
|
+
export declare function isLoggedIn(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Clear stored token (logout).
|
|
44
|
+
*/
|
|
45
|
+
export declare function clearToken(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Get cloud connection config.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getCloudConfig(): {
|
|
50
|
+
url: string;
|
|
51
|
+
token: string;
|
|
52
|
+
agentId: string;
|
|
53
|
+
} | null;
|
|
54
|
+
/**
|
|
55
|
+
* Set cloud URL.
|
|
56
|
+
*/
|
|
57
|
+
export declare function setCloudUrl(url: string): void;
|
|
58
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,0BAA0B;AAC1B,MAAM,WAAW,WAAW;IACxB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAwFD;;GAEG;AACH,wBAAgB,UAAU,IAAI,WAAW,CAkBxC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAO7D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAShE;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAwBxC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAKjC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAavF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE7C"}
|