@sparkleideas/browser 3.0.0-alpha.3
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 +730 -0
- package/agents/architect.yaml +11 -0
- package/agents/coder.yaml +11 -0
- package/agents/reviewer.yaml +10 -0
- package/agents/security-architect.yaml +10 -0
- package/agents/tester.yaml +10 -0
- package/docker/Dockerfile +22 -0
- package/docker/docker-compose.yml +52 -0
- package/docker/test-fixtures/index.html +61 -0
- package/package.json +56 -0
- package/skills/browser/SKILL.md +204 -0
- package/src/agent/index.ts +35 -0
- package/src/application/browser-service.ts +570 -0
- package/src/domain/types.ts +324 -0
- package/src/index.ts +156 -0
- package/src/infrastructure/agent-browser-adapter.ts +654 -0
- package/src/infrastructure/hooks-integration.ts +170 -0
- package/src/infrastructure/memory-integration.ts +449 -0
- package/src/infrastructure/reasoningbank-adapter.ts +282 -0
- package/src/infrastructure/security-integration.ts +528 -0
- package/src/infrastructure/workflow-templates.ts +479 -0
- package/src/mcp-tools/browser-tools.ts +1210 -0
- package/src/mcp-tools/index.ts +6 -0
- package/src/skill/index.ts +24 -0
- package/tests/agent-browser-adapter.test.ts +328 -0
- package/tests/browser-service.test.ts +137 -0
- package/tests/e2e/browser-e2e.test.ts +175 -0
- package/tests/memory-integration.test.ts +277 -0
- package/tests/reasoningbank-adapter.test.ts +219 -0
- package/tests/security-integration.test.ts +194 -0
- package/tests/workflow-templates.test.ts +231 -0
- package/tmp.json +0 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sparkleideas/browser - Agent Browser Adapter
|
|
3
|
+
* Wraps agent-browser CLI for programmatic access
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { spawn, execSync } from 'child_process';
|
|
7
|
+
import type {
|
|
8
|
+
ActionResult,
|
|
9
|
+
Snapshot,
|
|
10
|
+
SnapshotOptions,
|
|
11
|
+
OpenInput,
|
|
12
|
+
ClickInput,
|
|
13
|
+
FillInput,
|
|
14
|
+
TypeInput,
|
|
15
|
+
ScreenshotInput,
|
|
16
|
+
WaitInput,
|
|
17
|
+
EvalInput,
|
|
18
|
+
GetInput,
|
|
19
|
+
BrowserSession,
|
|
20
|
+
NetworkRouteInput,
|
|
21
|
+
} from '../domain/types.js';
|
|
22
|
+
|
|
23
|
+
export interface AgentBrowserAdapterOptions {
|
|
24
|
+
session?: string;
|
|
25
|
+
timeout?: number;
|
|
26
|
+
headless?: boolean;
|
|
27
|
+
executablePath?: string;
|
|
28
|
+
proxy?: string;
|
|
29
|
+
viewport?: { width: number; height: number };
|
|
30
|
+
debug?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class AgentBrowserAdapter {
|
|
34
|
+
private session: string;
|
|
35
|
+
private timeout: number;
|
|
36
|
+
private headless: boolean;
|
|
37
|
+
private executablePath?: string;
|
|
38
|
+
private proxy?: string;
|
|
39
|
+
private viewport?: { width: number; height: number };
|
|
40
|
+
private debug: boolean;
|
|
41
|
+
|
|
42
|
+
constructor(options: AgentBrowserAdapterOptions = {}) {
|
|
43
|
+
this.session = options.session || 'default';
|
|
44
|
+
this.timeout = options.timeout || 30000;
|
|
45
|
+
this.headless = options.headless !== false;
|
|
46
|
+
this.executablePath = options.executablePath;
|
|
47
|
+
this.proxy = options.proxy;
|
|
48
|
+
this.viewport = options.viewport;
|
|
49
|
+
this.debug = options.debug || false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ===========================================================================
|
|
53
|
+
// Core Command Execution
|
|
54
|
+
// ===========================================================================
|
|
55
|
+
|
|
56
|
+
private async exec<T = unknown>(args: string[], jsonOutput = true): Promise<ActionResult<T>> {
|
|
57
|
+
const startTime = Date.now();
|
|
58
|
+
const fullArgs = [
|
|
59
|
+
'--session', this.session,
|
|
60
|
+
...(this.timeout ? ['--timeout', String(this.timeout)] : []),
|
|
61
|
+
...(!this.headless ? ['--headed'] : []),
|
|
62
|
+
...(this.executablePath ? ['--executable-path', this.executablePath] : []),
|
|
63
|
+
...(this.proxy ? ['--proxy-server', this.proxy] : []),
|
|
64
|
+
...(jsonOutput ? ['--json'] : []),
|
|
65
|
+
...args,
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
if (this.debug) {
|
|
69
|
+
console.log(`[agent-browser] ${fullArgs.join(' ')}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
try {
|
|
74
|
+
const result = execSync(`agent-browser ${fullArgs.join(' ')}`, {
|
|
75
|
+
encoding: 'utf-8',
|
|
76
|
+
timeout: this.timeout + 5000,
|
|
77
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const duration = Date.now() - startTime;
|
|
81
|
+
|
|
82
|
+
if (jsonOutput) {
|
|
83
|
+
try {
|
|
84
|
+
const parsed = JSON.parse(result);
|
|
85
|
+
resolve({
|
|
86
|
+
success: parsed.success !== false,
|
|
87
|
+
data: (parsed.data || parsed) as T,
|
|
88
|
+
duration,
|
|
89
|
+
});
|
|
90
|
+
} catch {
|
|
91
|
+
resolve({ success: true, data: result.trim() as T, duration });
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
resolve({ success: true, data: result.trim() as T, duration });
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const duration = Date.now() - startTime;
|
|
98
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
99
|
+
resolve({ success: false, error: message, duration });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ===========================================================================
|
|
105
|
+
// Navigation Commands
|
|
106
|
+
// ===========================================================================
|
|
107
|
+
|
|
108
|
+
async open(input: OpenInput): Promise<ActionResult> {
|
|
109
|
+
const args = ['open', input.url];
|
|
110
|
+
if (input.waitUntil) args.push('--wait', input.waitUntil);
|
|
111
|
+
if (input.headers) args.push('--headers', JSON.stringify(input.headers));
|
|
112
|
+
return this.exec(args);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async back(): Promise<ActionResult> {
|
|
116
|
+
return this.exec(['back']);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async forward(): Promise<ActionResult> {
|
|
120
|
+
return this.exec(['forward']);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async reload(): Promise<ActionResult> {
|
|
124
|
+
return this.exec(['reload']);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async close(): Promise<ActionResult> {
|
|
128
|
+
return this.exec(['close']);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ===========================================================================
|
|
132
|
+
// Interaction Commands
|
|
133
|
+
// ===========================================================================
|
|
134
|
+
|
|
135
|
+
async click(input: ClickInput): Promise<ActionResult> {
|
|
136
|
+
const args = ['click', input.target];
|
|
137
|
+
if (input.button) args.push('--button', input.button);
|
|
138
|
+
if (input.clickCount) args.push('--click-count', String(input.clickCount));
|
|
139
|
+
if (input.force) args.push('--force');
|
|
140
|
+
return this.exec(args);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async dblclick(target: string): Promise<ActionResult> {
|
|
144
|
+
return this.exec(['dblclick', target]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async fill(input: FillInput): Promise<ActionResult> {
|
|
148
|
+
return this.exec(['fill', input.target, input.value]);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async type(input: TypeInput): Promise<ActionResult> {
|
|
152
|
+
const args = ['type', input.target, input.text];
|
|
153
|
+
if (input.delay) args.push('--delay', String(input.delay));
|
|
154
|
+
return this.exec(args);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async press(key: string, delay?: number): Promise<ActionResult> {
|
|
158
|
+
const args = ['press', key];
|
|
159
|
+
if (delay) args.push('--delay', String(delay));
|
|
160
|
+
return this.exec(args);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async hover(target: string): Promise<ActionResult> {
|
|
164
|
+
return this.exec(['hover', target]);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async focus(target: string): Promise<ActionResult> {
|
|
168
|
+
return this.exec(['focus', target]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async select(target: string, value: string): Promise<ActionResult> {
|
|
172
|
+
return this.exec(['select', target, value]);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async check(target: string): Promise<ActionResult> {
|
|
176
|
+
return this.exec(['check', target]);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async uncheck(target: string): Promise<ActionResult> {
|
|
180
|
+
return this.exec(['uncheck', target]);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async scroll(direction: 'up' | 'down' | 'left' | 'right', pixels?: number): Promise<ActionResult> {
|
|
184
|
+
const args = ['scroll', direction];
|
|
185
|
+
if (pixels) args.push(String(pixels));
|
|
186
|
+
return this.exec(args);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async scrollIntoView(target: string): Promise<ActionResult> {
|
|
190
|
+
return this.exec(['scrollintoview', target]);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async drag(source: string, target: string): Promise<ActionResult> {
|
|
194
|
+
return this.exec(['drag', source, target]);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async upload(target: string, files: string[]): Promise<ActionResult> {
|
|
198
|
+
return this.exec(['upload', target, ...files]);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ===========================================================================
|
|
202
|
+
// Information Retrieval
|
|
203
|
+
// ===========================================================================
|
|
204
|
+
|
|
205
|
+
async get(input: GetInput): Promise<ActionResult> {
|
|
206
|
+
const args = ['get', input.type];
|
|
207
|
+
if (input.target) args.push(input.target);
|
|
208
|
+
if (input.attribute && input.type === 'attr') args.push(input.attribute);
|
|
209
|
+
return this.exec(args);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async getText(target: string): Promise<ActionResult<string>> {
|
|
213
|
+
return this.exec<string>(['get', 'text', target]);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async getHtml(target: string): Promise<ActionResult<string>> {
|
|
217
|
+
return this.exec<string>(['get', 'html', target]);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async getValue(target: string): Promise<ActionResult<string>> {
|
|
221
|
+
return this.exec<string>(['get', 'value', target]);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async getAttr(target: string, attribute: string): Promise<ActionResult<string>> {
|
|
225
|
+
return this.exec<string>(['get', 'attr', target, attribute]);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async getTitle(): Promise<ActionResult<string>> {
|
|
229
|
+
return this.exec<string>(['get', 'title']);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async getUrl(): Promise<ActionResult<string>> {
|
|
233
|
+
return this.exec<string>(['get', 'url']);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async getCount(selector: string): Promise<ActionResult<number>> {
|
|
237
|
+
return this.exec<number>(['get', 'count', selector]);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async getBox(target: string): Promise<ActionResult<{ x: number; y: number; width: number; height: number }>> {
|
|
241
|
+
return this.exec<{ x: number; y: number; width: number; height: number }>(['get', 'box', target]);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ===========================================================================
|
|
245
|
+
// State Checks
|
|
246
|
+
// ===========================================================================
|
|
247
|
+
|
|
248
|
+
async isVisible(target: string): Promise<ActionResult<boolean>> {
|
|
249
|
+
return this.exec<boolean>(['is', 'visible', target]);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async isEnabled(target: string): Promise<ActionResult<boolean>> {
|
|
253
|
+
return this.exec<boolean>(['is', 'enabled', target]);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async isChecked(target: string): Promise<ActionResult<boolean>> {
|
|
257
|
+
return this.exec<boolean>(['is', 'checked', target]);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ===========================================================================
|
|
261
|
+
// Snapshot & Screenshot
|
|
262
|
+
// ===========================================================================
|
|
263
|
+
|
|
264
|
+
async snapshot(options: SnapshotOptions = {}): Promise<ActionResult<Snapshot>> {
|
|
265
|
+
const args = ['snapshot'];
|
|
266
|
+
if (options.interactive) args.push('-i');
|
|
267
|
+
if (options.compact) args.push('-c');
|
|
268
|
+
if (options.depth) args.push('-d', String(options.depth));
|
|
269
|
+
if (options.selector) args.push('-s', options.selector);
|
|
270
|
+
return this.exec<Snapshot>(args);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async screenshot(input: ScreenshotInput = {}): Promise<ActionResult<string>> {
|
|
274
|
+
const args = ['screenshot'];
|
|
275
|
+
if (input.path) args.push(input.path);
|
|
276
|
+
if (input.fullPage) args.push('--full');
|
|
277
|
+
return this.exec<string>(args);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async pdf(path: string): Promise<ActionResult> {
|
|
281
|
+
return this.exec(['pdf', path]);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ===========================================================================
|
|
285
|
+
// Wait Commands
|
|
286
|
+
// ===========================================================================
|
|
287
|
+
|
|
288
|
+
async wait(input: WaitInput): Promise<ActionResult> {
|
|
289
|
+
if (input.selector) {
|
|
290
|
+
return this.exec(['wait', input.selector]);
|
|
291
|
+
}
|
|
292
|
+
if (typeof input.timeout === 'number' && !input.text && !input.url && !input.load && !input.fn) {
|
|
293
|
+
return this.exec(['wait', String(input.timeout)]);
|
|
294
|
+
}
|
|
295
|
+
const args = ['wait'];
|
|
296
|
+
if (input.text) args.push('--text', input.text);
|
|
297
|
+
if (input.url) args.push('--url', input.url);
|
|
298
|
+
if (input.load) args.push('--load', input.load);
|
|
299
|
+
if (input.fn) args.push('--fn', input.fn);
|
|
300
|
+
return this.exec(args);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async waitForSelector(selector: string, timeout?: number): Promise<ActionResult> {
|
|
304
|
+
const args = ['wait', selector];
|
|
305
|
+
if (timeout) args.push('--timeout', String(timeout));
|
|
306
|
+
return this.exec(args);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async waitForText(text: string): Promise<ActionResult> {
|
|
310
|
+
return this.exec(['wait', '--text', text]);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async waitForUrl(pattern: string): Promise<ActionResult> {
|
|
314
|
+
return this.exec(['wait', '--url', pattern]);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async waitForLoad(state: 'load' | 'domcontentloaded' | 'networkidle'): Promise<ActionResult> {
|
|
318
|
+
return this.exec(['wait', '--load', state]);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async waitForFunction(fn: string): Promise<ActionResult> {
|
|
322
|
+
return this.exec(['wait', '--fn', fn]);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ===========================================================================
|
|
326
|
+
// JavaScript Execution
|
|
327
|
+
// ===========================================================================
|
|
328
|
+
|
|
329
|
+
async eval<T = unknown>(input: EvalInput): Promise<ActionResult<T>> {
|
|
330
|
+
return this.exec<T>(['eval', input.script]);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ===========================================================================
|
|
334
|
+
// Mouse Control
|
|
335
|
+
// ===========================================================================
|
|
336
|
+
|
|
337
|
+
async mouseMove(x: number, y: number): Promise<ActionResult> {
|
|
338
|
+
return this.exec(['mouse', 'move', String(x), String(y)]);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async mouseDown(button: 'left' | 'right' | 'middle' = 'left'): Promise<ActionResult> {
|
|
342
|
+
return this.exec(['mouse', 'down', button]);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async mouseUp(button: 'left' | 'right' | 'middle' = 'left'): Promise<ActionResult> {
|
|
346
|
+
return this.exec(['mouse', 'up', button]);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
async mouseWheel(deltaY: number, deltaX = 0): Promise<ActionResult> {
|
|
350
|
+
return this.exec(['mouse', 'wheel', String(deltaY), String(deltaX)]);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ===========================================================================
|
|
354
|
+
// Browser Settings
|
|
355
|
+
// ===========================================================================
|
|
356
|
+
|
|
357
|
+
async setViewport(width: number, height: number): Promise<ActionResult> {
|
|
358
|
+
return this.exec(['set', 'viewport', String(width), String(height)]);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async setDevice(device: string): Promise<ActionResult> {
|
|
362
|
+
return this.exec(['set', 'device', device]);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async setGeolocation(lat: number, lng: number): Promise<ActionResult> {
|
|
366
|
+
return this.exec(['set', 'geo', String(lat), String(lng)]);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async setOffline(enabled: boolean): Promise<ActionResult> {
|
|
370
|
+
return this.exec(['set', 'offline', enabled ? 'on' : 'off']);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async setHeaders(headers: Record<string, string>): Promise<ActionResult> {
|
|
374
|
+
return this.exec(['set', 'headers', JSON.stringify(headers)]);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
async setCredentials(username: string, password: string): Promise<ActionResult> {
|
|
378
|
+
return this.exec(['set', 'credentials', username, password]);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async setMedia(scheme: 'dark' | 'light'): Promise<ActionResult> {
|
|
382
|
+
return this.exec(['set', 'media', scheme]);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// ===========================================================================
|
|
386
|
+
// Cookies & Storage
|
|
387
|
+
// ===========================================================================
|
|
388
|
+
|
|
389
|
+
async getCookies(): Promise<ActionResult> {
|
|
390
|
+
return this.exec(['cookies']);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async setCookie(name: string, value: string): Promise<ActionResult> {
|
|
394
|
+
return this.exec(['cookies', 'set', name, value]);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async clearCookies(): Promise<ActionResult> {
|
|
398
|
+
return this.exec(['cookies', 'clear']);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
async getLocalStorage(key?: string): Promise<ActionResult> {
|
|
402
|
+
const args = ['storage', 'local'];
|
|
403
|
+
if (key) args.push(key);
|
|
404
|
+
return this.exec(args);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async setLocalStorage(key: string, value: string): Promise<ActionResult> {
|
|
408
|
+
return this.exec(['storage', 'local', 'set', key, value]);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async clearLocalStorage(): Promise<ActionResult> {
|
|
412
|
+
return this.exec(['storage', 'local', 'clear']);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
async getSessionStorage(key?: string): Promise<ActionResult> {
|
|
416
|
+
const args = ['storage', 'session'];
|
|
417
|
+
if (key) args.push(key);
|
|
418
|
+
return this.exec(args);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async setSessionStorage(key: string, value: string): Promise<ActionResult> {
|
|
422
|
+
return this.exec(['storage', 'session', 'set', key, value]);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async clearSessionStorage(): Promise<ActionResult> {
|
|
426
|
+
return this.exec(['storage', 'session', 'clear']);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// ===========================================================================
|
|
430
|
+
// Network
|
|
431
|
+
// ===========================================================================
|
|
432
|
+
|
|
433
|
+
async networkRoute(input: NetworkRouteInput): Promise<ActionResult> {
|
|
434
|
+
const args = ['network', 'route', input.urlPattern];
|
|
435
|
+
if (input.abort) args.push('--abort');
|
|
436
|
+
if (input.body) args.push('--body', typeof input.body === 'string' ? input.body : JSON.stringify(input.body));
|
|
437
|
+
if (input.status) args.push('--status', String(input.status));
|
|
438
|
+
if (input.headers) args.push('--headers', JSON.stringify(input.headers));
|
|
439
|
+
return this.exec(args);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async networkUnroute(urlPattern?: string): Promise<ActionResult> {
|
|
443
|
+
const args = ['network', 'unroute'];
|
|
444
|
+
if (urlPattern) args.push(urlPattern);
|
|
445
|
+
return this.exec(args);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
async networkRequests(filter?: string): Promise<ActionResult> {
|
|
449
|
+
const args = ['network', 'requests'];
|
|
450
|
+
if (filter) args.push('--filter', filter);
|
|
451
|
+
return this.exec(args);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ===========================================================================
|
|
455
|
+
// Tabs & Windows
|
|
456
|
+
// ===========================================================================
|
|
457
|
+
|
|
458
|
+
async listTabs(): Promise<ActionResult> {
|
|
459
|
+
return this.exec(['tab']);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async newTab(url?: string): Promise<ActionResult> {
|
|
463
|
+
const args = ['tab', 'new'];
|
|
464
|
+
if (url) args.push(url);
|
|
465
|
+
return this.exec(args);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async switchTab(index: number): Promise<ActionResult> {
|
|
469
|
+
return this.exec(['tab', String(index)]);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
async closeTab(index?: number): Promise<ActionResult> {
|
|
473
|
+
const args = ['tab', 'close'];
|
|
474
|
+
if (index !== undefined) args.push(String(index));
|
|
475
|
+
return this.exec(args);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async newWindow(): Promise<ActionResult> {
|
|
479
|
+
return this.exec(['window', 'new']);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// ===========================================================================
|
|
483
|
+
// Frames
|
|
484
|
+
// ===========================================================================
|
|
485
|
+
|
|
486
|
+
async switchFrame(selector: string): Promise<ActionResult> {
|
|
487
|
+
return this.exec(['frame', selector]);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async switchToMainFrame(): Promise<ActionResult> {
|
|
491
|
+
return this.exec(['frame', 'main']);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// ===========================================================================
|
|
495
|
+
// Dialogs
|
|
496
|
+
// ===========================================================================
|
|
497
|
+
|
|
498
|
+
async dialogAccept(text?: string): Promise<ActionResult> {
|
|
499
|
+
const args = ['dialog', 'accept'];
|
|
500
|
+
if (text) args.push(text);
|
|
501
|
+
return this.exec(args);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async dialogDismiss(): Promise<ActionResult> {
|
|
505
|
+
return this.exec(['dialog', 'dismiss']);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// ===========================================================================
|
|
509
|
+
// Debug & Trace
|
|
510
|
+
// ===========================================================================
|
|
511
|
+
|
|
512
|
+
async traceStart(path?: string): Promise<ActionResult> {
|
|
513
|
+
const args = ['trace', 'start'];
|
|
514
|
+
if (path) args.push(path);
|
|
515
|
+
return this.exec(args);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async traceStop(path?: string): Promise<ActionResult> {
|
|
519
|
+
const args = ['trace', 'stop'];
|
|
520
|
+
if (path) args.push(path);
|
|
521
|
+
return this.exec(args);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async getConsole(): Promise<ActionResult> {
|
|
525
|
+
return this.exec(['console']);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async clearConsole(): Promise<ActionResult> {
|
|
529
|
+
return this.exec(['console', '--clear']);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
async getErrors(): Promise<ActionResult> {
|
|
533
|
+
return this.exec(['errors']);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async clearErrors(): Promise<ActionResult> {
|
|
537
|
+
return this.exec(['errors', '--clear']);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async highlight(selector: string): Promise<ActionResult> {
|
|
541
|
+
return this.exec(['highlight', selector]);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
async saveState(path: string): Promise<ActionResult> {
|
|
545
|
+
return this.exec(['state', 'save', path]);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
async loadState(path: string): Promise<ActionResult> {
|
|
549
|
+
return this.exec(['state', 'load', path]);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// ===========================================================================
|
|
553
|
+
// Find Commands (Semantic Locators)
|
|
554
|
+
// ===========================================================================
|
|
555
|
+
|
|
556
|
+
async findByRole(role: string, action: string, options?: { name?: string; exact?: boolean }): Promise<ActionResult> {
|
|
557
|
+
const args = ['find', 'role', role, action];
|
|
558
|
+
if (options?.name) args.push('--name', options.name);
|
|
559
|
+
if (options?.exact) args.push('--exact');
|
|
560
|
+
return this.exec(args);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
async findByText(text: string, action: string): Promise<ActionResult> {
|
|
564
|
+
return this.exec(['find', 'text', text, action]);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
async findByLabel(label: string, action: string, value?: string): Promise<ActionResult> {
|
|
568
|
+
const args = ['find', 'label', label, action];
|
|
569
|
+
if (value) args.push(value);
|
|
570
|
+
return this.exec(args);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
async findByPlaceholder(placeholder: string, action: string, value?: string): Promise<ActionResult> {
|
|
574
|
+
const args = ['find', 'placeholder', placeholder, action];
|
|
575
|
+
if (value) args.push(value);
|
|
576
|
+
return this.exec(args);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async findByTestId(testId: string, action: string, value?: string): Promise<ActionResult> {
|
|
580
|
+
const args = ['find', 'testid', testId, action];
|
|
581
|
+
if (value) args.push(value);
|
|
582
|
+
return this.exec(args);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
async findFirst(selector: string, action: string, value?: string): Promise<ActionResult> {
|
|
586
|
+
const args = ['find', 'first', selector, action];
|
|
587
|
+
if (value) args.push(value);
|
|
588
|
+
return this.exec(args);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async findLast(selector: string, action: string, value?: string): Promise<ActionResult> {
|
|
592
|
+
const args = ['find', 'last', selector, action];
|
|
593
|
+
if (value) args.push(value);
|
|
594
|
+
return this.exec(args);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async findNth(n: number, selector: string, action: string, value?: string): Promise<ActionResult> {
|
|
598
|
+
const args = ['find', 'nth', String(n), selector, action];
|
|
599
|
+
if (value) args.push(value);
|
|
600
|
+
return this.exec(args);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// ===========================================================================
|
|
604
|
+
// Session Management
|
|
605
|
+
// ===========================================================================
|
|
606
|
+
|
|
607
|
+
async listSessions(): Promise<ActionResult> {
|
|
608
|
+
return this.exec(['session', 'list']);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
async getCurrentSession(): Promise<ActionResult> {
|
|
612
|
+
return this.exec(['session']);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
setSession(sessionId: string): void {
|
|
616
|
+
this.session = sessionId;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
getSession(): string {
|
|
620
|
+
return this.session;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// ===========================================================================
|
|
624
|
+
// CDP Connection
|
|
625
|
+
// ===========================================================================
|
|
626
|
+
|
|
627
|
+
async connect(port: number): Promise<ActionResult> {
|
|
628
|
+
return this.exec(['connect', String(port)]);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// ===========================================================================
|
|
632
|
+
// Setup
|
|
633
|
+
// ===========================================================================
|
|
634
|
+
|
|
635
|
+
static async install(withDeps = false): Promise<ActionResult> {
|
|
636
|
+
const args = ['install'];
|
|
637
|
+
if (withDeps) args.push('--with-deps');
|
|
638
|
+
|
|
639
|
+
return new Promise((resolve) => {
|
|
640
|
+
try {
|
|
641
|
+
const result = execSync(`agent-browser ${args.join(' ')}`, {
|
|
642
|
+
encoding: 'utf-8',
|
|
643
|
+
timeout: 300000, // 5 minutes for download
|
|
644
|
+
});
|
|
645
|
+
resolve({ success: true, data: result });
|
|
646
|
+
} catch (error) {
|
|
647
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
648
|
+
resolve({ success: false, error: message });
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
export default AgentBrowserAdapter;
|