@dyyz1993/agent-browser 0.13.2 → 0.23.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/bin/agent-browser-linux-x64 +0 -0
- package/dist/__tests__/e2e/utils/test-helpers.d.ts +1 -0
- package/dist/__tests__/e2e/utils/test-helpers.d.ts.map +1 -1
- package/dist/__tests__/e2e/utils/test-helpers.js +14 -1
- package/dist/__tests__/e2e/utils/test-helpers.js.map +1 -1
- package/dist/__tests__/utils/parseCli.d.ts.map +1 -1
- package/dist/__tests__/utils/parseCli.js +83 -1
- package/dist/__tests__/utils/parseCli.js.map +1 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +269 -0
- package/dist/actions.js.map +1 -1
- package/dist/browser.d.ts +11 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +63 -2
- package/dist/browser.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +165 -1
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/connection.d.ts +13 -0
- package/dist/cli/connection.d.ts.map +1 -1
- package/dist/cli/connection.js +51 -1
- package/dist/cli/connection.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +39 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli.js +20 -1
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +1 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +22 -0
- package/dist/daemon.js.map +1 -1
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +1 -1
- package/dist/diff.js.map +1 -1
- package/dist/flow/exporters/index.d.ts +4 -0
- package/dist/flow/exporters/index.d.ts.map +1 -0
- package/dist/flow/exporters/index.js +3 -0
- package/dist/flow/exporters/index.js.map +1 -0
- package/dist/flow/exporters/playwright.d.ts +20 -0
- package/dist/flow/exporters/playwright.d.ts.map +1 -0
- package/dist/flow/exporters/playwright.js +175 -0
- package/dist/flow/exporters/playwright.js.map +1 -0
- package/dist/flow/exporters/python.d.ts +20 -0
- package/dist/flow/exporters/python.d.ts.map +1 -0
- package/dist/flow/exporters/python.js +163 -0
- package/dist/flow/exporters/python.js.map +1 -0
- package/dist/flow/exporters/types.d.ts +13 -0
- package/dist/flow/exporters/types.d.ts.map +1 -0
- package/dist/flow/exporters/types.js +2 -0
- package/dist/flow/exporters/types.js.map +1 -0
- package/dist/flow/flow-executor.d.ts +55 -0
- package/dist/flow/flow-executor.d.ts.map +1 -0
- package/dist/flow/flow-executor.js +1169 -0
- package/dist/flow/flow-executor.js.map +1 -0
- package/dist/flow/index.d.ts +15 -0
- package/dist/flow/index.d.ts.map +1 -0
- package/dist/flow/index.js +10 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/flow/output.d.ts +11 -0
- package/dist/flow/output.d.ts.map +1 -0
- package/dist/flow/output.js +84 -0
- package/dist/flow/output.js.map +1 -0
- package/dist/flow/plugin-system.d.ts +48 -0
- package/dist/flow/plugin-system.d.ts.map +1 -0
- package/dist/flow/plugin-system.js +132 -0
- package/dist/flow/plugin-system.js.map +1 -0
- package/dist/flow/plugins/file-output-plugin.d.ts +8 -0
- package/dist/flow/plugins/file-output-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/file-output-plugin.js +31 -0
- package/dist/flow/plugins/file-output-plugin.js.map +1 -0
- package/dist/flow/plugins/index.d.ts +4 -0
- package/dist/flow/plugins/index.d.ts.map +1 -0
- package/dist/flow/plugins/index.js +4 -0
- package/dist/flow/plugins/index.js.map +1 -0
- package/dist/flow/plugins/logging-plugin.d.ts +7 -0
- package/dist/flow/plugins/logging-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/logging-plugin.js +40 -0
- package/dist/flow/plugins/logging-plugin.js.map +1 -0
- package/dist/flow/plugins/webhook-plugin.d.ts +7 -0
- package/dist/flow/plugins/webhook-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/webhook-plugin.js +24 -0
- package/dist/flow/plugins/webhook-plugin.js.map +1 -0
- package/dist/flow/presets/index.d.ts +10 -0
- package/dist/flow/presets/index.d.ts.map +1 -0
- package/dist/flow/presets/index.js +29 -0
- package/dist/flow/presets/index.js.map +1 -0
- package/dist/flow/recorder-to-flow.d.ts +70 -0
- package/dist/flow/recorder-to-flow.d.ts.map +1 -0
- package/dist/flow/recorder-to-flow.js +392 -0
- package/dist/flow/recorder-to-flow.js.map +1 -0
- package/dist/flow/site-manager.d.ts +24 -0
- package/dist/flow/site-manager.d.ts.map +1 -0
- package/dist/flow/site-manager.js +125 -0
- package/dist/flow/site-manager.js.map +1 -0
- package/dist/flow/types.d.ts +181 -0
- package/dist/flow/types.d.ts.map +1 -0
- package/dist/flow/types.js +2 -0
- package/dist/flow/types.js.map +1 -0
- package/dist/flow/yaml-parser.d.ts +15 -0
- package/dist/flow/yaml-parser.d.ts.map +1 -0
- package/dist/flow/yaml-parser.js +214 -0
- package/dist/flow/yaml-parser.js.map +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +15 -0
- package/dist/protocol.js.map +1 -1
- package/dist/recorder/inject.js +730 -332
- package/dist/snapshot-store.d.ts +77 -0
- package/dist/snapshot-store.d.ts.map +1 -0
- package/dist/snapshot-store.js +97 -0
- package/dist/snapshot-store.js.map +1 -0
- package/dist/snapshot.d.ts +6 -7
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/snapshot.js +437 -1
- package/dist/snapshot.js.map +1 -1
- package/dist/types.d.ts +13 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer-script.js +4 -4
- package/dist/viewer-script.js.map +1 -1
- package/package.json +7 -3
- package/skills/agent-browser/SKILL.md +102 -3
package/dist/actions.js
CHANGED
|
@@ -7,6 +7,10 @@ import { getViewerUrl, getViewerWsUrl, getViewerPort, getMessageBridgeUrl, getEx
|
|
|
7
7
|
import { detectMainContent, generateContentTips } from './content-detection.js';
|
|
8
8
|
import { humanClick, humanType, humanMoveTo, humanWander, getHumanConfigFromEnv, } from './human-mouse.js';
|
|
9
9
|
import { successResponse, errorResponse } from './protocol.js';
|
|
10
|
+
import { parseYamlSiteFile, loadSitesFromDirectory, loadAllSites, findFlow, validateYamlFile, } from './flow/yaml-parser.js';
|
|
11
|
+
import { recorderToFlowFromFile, siteToYamlString } from './flow/recorder-to-flow.js';
|
|
12
|
+
import { FlowExecutor } from './flow/flow-executor.js';
|
|
13
|
+
import { PlaywrightExporter, PythonExporter } from './flow/exporters/index.js';
|
|
10
14
|
// Callback for screencast frames - will be set by the daemon when streaming is active
|
|
11
15
|
let screencastFrameCallback = null;
|
|
12
16
|
/**
|
|
@@ -98,6 +102,9 @@ export function toAIFriendlyError(error, selector) {
|
|
|
98
102
|
*/
|
|
99
103
|
export async function executeCommand(command, browser) {
|
|
100
104
|
try {
|
|
105
|
+
if (command.action === 'flow') {
|
|
106
|
+
return await handleFlowAction(command, browser);
|
|
107
|
+
}
|
|
101
108
|
const cmd = command;
|
|
102
109
|
switch (cmd.action) {
|
|
103
110
|
case 'launch':
|
|
@@ -366,6 +373,12 @@ export async function executeCommand(command, browser) {
|
|
|
366
373
|
return handleConfig(cmd);
|
|
367
374
|
case 'history':
|
|
368
375
|
return await handleHistory(cmd, browser);
|
|
376
|
+
case 'selector-for':
|
|
377
|
+
return await handleSelectorFor(cmd, browser);
|
|
378
|
+
case 'selectors-of':
|
|
379
|
+
return await handleSelectorsOf(cmd, browser);
|
|
380
|
+
case 'validate':
|
|
381
|
+
return await handleValidate(cmd, browser);
|
|
369
382
|
default: {
|
|
370
383
|
const unknownCommand = cmd;
|
|
371
384
|
return errorResponse(unknownCommand.id, `Unknown action: ${unknownCommand.action}`);
|
|
@@ -2370,4 +2383,260 @@ async function handleHistory(command, browser) {
|
|
|
2370
2383
|
const history = browser.getHistory(command.filter);
|
|
2371
2384
|
return successResponse(command.id, { history });
|
|
2372
2385
|
}
|
|
2386
|
+
async function handleSelectorFor(command, browser) {
|
|
2387
|
+
const store = browser.getSnapshotStore();
|
|
2388
|
+
const colonIndex = command.target.indexOf(':');
|
|
2389
|
+
if (colonIndex === -1) {
|
|
2390
|
+
return errorResponse(command.id, `Invalid target format: "${command.target}". Expected "snapshotId:refOrIndex" (e.g., "snap_3:@e1" or "snap_3:1").`);
|
|
2391
|
+
}
|
|
2392
|
+
const snapshotId = command.target.substring(0, colonIndex);
|
|
2393
|
+
const refOrIndex = command.target.substring(colonIndex + 1);
|
|
2394
|
+
await browser.ensureSelectorsGenerated(snapshotId);
|
|
2395
|
+
const element = store.getElement(snapshotId, refOrIndex);
|
|
2396
|
+
if (!element) {
|
|
2397
|
+
return errorResponse(command.id, `Element not found: "${refOrIndex}" in snapshot "${snapshotId}". Run 'snapshot' to get fresh snapshot data.`);
|
|
2398
|
+
}
|
|
2399
|
+
return successResponse(command.id, {
|
|
2400
|
+
snapshotId,
|
|
2401
|
+
ref: element.ref,
|
|
2402
|
+
index: element.index,
|
|
2403
|
+
role: element.role,
|
|
2404
|
+
name: element.name,
|
|
2405
|
+
cssSelector: element.cssSelector,
|
|
2406
|
+
xpath: element.xpath,
|
|
2407
|
+
});
|
|
2408
|
+
}
|
|
2409
|
+
async function handleSelectorsOf(command, browser) {
|
|
2410
|
+
const store = browser.getSnapshotStore();
|
|
2411
|
+
await browser.ensureSelectorsGenerated(command.target);
|
|
2412
|
+
const elements = store.getElements(command.target);
|
|
2413
|
+
if (!elements) {
|
|
2414
|
+
return errorResponse(command.id, `Snapshot "${command.target}" not found. Run 'snapshot' to create a new snapshot.`);
|
|
2415
|
+
}
|
|
2416
|
+
return successResponse(command.id, {
|
|
2417
|
+
snapshotId: command.target,
|
|
2418
|
+
elements: elements.map((el) => ({
|
|
2419
|
+
ref: el.ref,
|
|
2420
|
+
index: el.index,
|
|
2421
|
+
role: el.role,
|
|
2422
|
+
name: el.name,
|
|
2423
|
+
cssSelector: el.cssSelector,
|
|
2424
|
+
xpath: el.xpath,
|
|
2425
|
+
})),
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
async function handleValidate(command, browser) {
|
|
2429
|
+
const store = browser.getSnapshotStore();
|
|
2430
|
+
await browser.ensureSelectorsGenerated(command.target);
|
|
2431
|
+
const elements = store.getElements(command.target);
|
|
2432
|
+
if (!elements) {
|
|
2433
|
+
return errorResponse(command.id, `Snapshot "${command.target}" not found. Run 'snapshot' to create a new snapshot.`);
|
|
2434
|
+
}
|
|
2435
|
+
const page = browser.getPage();
|
|
2436
|
+
const selectors = elements.map((el) => el.cssSelector);
|
|
2437
|
+
const matchCounts = await page.evaluate((sels) => {
|
|
2438
|
+
return sels.map((sel) => {
|
|
2439
|
+
try {
|
|
2440
|
+
return document.querySelectorAll(sel).length;
|
|
2441
|
+
}
|
|
2442
|
+
catch {
|
|
2443
|
+
return -1;
|
|
2444
|
+
}
|
|
2445
|
+
});
|
|
2446
|
+
}, selectors);
|
|
2447
|
+
const results = elements.map((el, i) => {
|
|
2448
|
+
const matchCount = matchCounts[i];
|
|
2449
|
+
let status;
|
|
2450
|
+
if (matchCount === -1) {
|
|
2451
|
+
status = 'invalid_selector';
|
|
2452
|
+
}
|
|
2453
|
+
else if (matchCount === 0) {
|
|
2454
|
+
status = 'not_found';
|
|
2455
|
+
}
|
|
2456
|
+
else if (matchCount === 1) {
|
|
2457
|
+
status = 'valid';
|
|
2458
|
+
}
|
|
2459
|
+
else {
|
|
2460
|
+
status = 'ambiguous';
|
|
2461
|
+
}
|
|
2462
|
+
return {
|
|
2463
|
+
ref: el.ref,
|
|
2464
|
+
index: el.index,
|
|
2465
|
+
cssSelector: el.cssSelector,
|
|
2466
|
+
status,
|
|
2467
|
+
matchCount,
|
|
2468
|
+
};
|
|
2469
|
+
});
|
|
2470
|
+
const failedCount = results.filter((r) => r.status === 'not_found' || r.status === 'invalid_selector').length;
|
|
2471
|
+
let newSnapshotId;
|
|
2472
|
+
if (failedCount > 0) {
|
|
2473
|
+
const newSnapshot = await browser.getSnapshot({ interactive: true });
|
|
2474
|
+
newSnapshotId = newSnapshot.snapshotId;
|
|
2475
|
+
}
|
|
2476
|
+
return successResponse(command.id, {
|
|
2477
|
+
snapshotId: command.target,
|
|
2478
|
+
results,
|
|
2479
|
+
newSnapshotId,
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
async function handleFlowAction(command, browser) {
|
|
2483
|
+
const cmd = command;
|
|
2484
|
+
const subcommand = cmd.subcommand;
|
|
2485
|
+
switch (subcommand) {
|
|
2486
|
+
case 'run':
|
|
2487
|
+
return await handleFlowRun(cmd, browser);
|
|
2488
|
+
case 'list':
|
|
2489
|
+
return handleFlowList(cmd);
|
|
2490
|
+
case 'show':
|
|
2491
|
+
return handleFlowShow(cmd);
|
|
2492
|
+
case 'validate':
|
|
2493
|
+
return handleFlowValidate(cmd);
|
|
2494
|
+
case 'from-recorder':
|
|
2495
|
+
return handleFlowFromRecorder(cmd);
|
|
2496
|
+
case 'export':
|
|
2497
|
+
return handleFlowExport(cmd);
|
|
2498
|
+
default:
|
|
2499
|
+
return errorResponse(command.id, `Unknown flow subcommand: ${subcommand}`);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
function handleFlowList(command) {
|
|
2503
|
+
const sites = command.sitesDir ? loadSitesFromDirectory(command.sitesDir) : loadAllSites();
|
|
2504
|
+
const siteList = [];
|
|
2505
|
+
for (const [name, site] of sites) {
|
|
2506
|
+
siteList.push({
|
|
2507
|
+
name,
|
|
2508
|
+
description: site.description,
|
|
2509
|
+
flows: Object.keys(site.flows),
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
return successResponse(command.id, { sites: siteList });
|
|
2513
|
+
}
|
|
2514
|
+
function handleFlowShow(command) {
|
|
2515
|
+
const sites = command.sitesDir ? loadSitesFromDirectory(command.sitesDir) : loadAllSites();
|
|
2516
|
+
const ref = command.siteFlow || '';
|
|
2517
|
+
const result = findFlow(sites, ref);
|
|
2518
|
+
if (!result) {
|
|
2519
|
+
return errorResponse(command.id, `Flow "${ref}" not found`);
|
|
2520
|
+
}
|
|
2521
|
+
return successResponse(command.id, {
|
|
2522
|
+
site: {
|
|
2523
|
+
name: result.site.name,
|
|
2524
|
+
description: result.site.description,
|
|
2525
|
+
baseUrl: result.site.baseUrl,
|
|
2526
|
+
},
|
|
2527
|
+
flow: result.flow,
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2530
|
+
function handleFlowValidate(command) {
|
|
2531
|
+
const filePath = command.filePath || '';
|
|
2532
|
+
if (!filePath) {
|
|
2533
|
+
return errorResponse(command.id, 'Missing file path for validate');
|
|
2534
|
+
}
|
|
2535
|
+
const result = validateYamlFile(filePath);
|
|
2536
|
+
return successResponse(command.id, result);
|
|
2537
|
+
}
|
|
2538
|
+
function handleFlowFromRecorder(command) {
|
|
2539
|
+
const recorderFile = command.recorderFile;
|
|
2540
|
+
if (!recorderFile) {
|
|
2541
|
+
return errorResponse(command.id, 'Missing recorder YAML file path');
|
|
2542
|
+
}
|
|
2543
|
+
try {
|
|
2544
|
+
const result = recorderToFlowFromFile(recorderFile, {
|
|
2545
|
+
flowId: command.flowId,
|
|
2546
|
+
description: command.description,
|
|
2547
|
+
baseUrl: command.baseUrl,
|
|
2548
|
+
siteName: command.siteName,
|
|
2549
|
+
maxPaginateIterations: command.maxPaginateIterations,
|
|
2550
|
+
});
|
|
2551
|
+
const yamlString = siteToYamlString(result.site);
|
|
2552
|
+
if (command.outputFile) {
|
|
2553
|
+
writeFileSync(path.resolve(command.outputFile), yamlString, 'utf-8');
|
|
2554
|
+
return successResponse(command.id, {
|
|
2555
|
+
siteName: result.site.name,
|
|
2556
|
+
flowId: Object.keys(result.site.flows)[0],
|
|
2557
|
+
outputFile: command.outputFile,
|
|
2558
|
+
warnings: result.warnings,
|
|
2559
|
+
});
|
|
2560
|
+
}
|
|
2561
|
+
return successResponse(command.id, {
|
|
2562
|
+
siteName: result.site.name,
|
|
2563
|
+
flowId: Object.keys(result.site.flows)[0],
|
|
2564
|
+
yaml: yamlString,
|
|
2565
|
+
warnings: result.warnings,
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
catch (e) {
|
|
2569
|
+
return errorResponse(command.id, `Failed to convert recorder YAML: ${e instanceof Error ? e.message : String(e)}`);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
async function handleFlowRun(command, browser) {
|
|
2573
|
+
const ref = command.siteFlow || '';
|
|
2574
|
+
const sites = command.sitesDir ? loadSitesFromDirectory(command.sitesDir) : loadAllSites();
|
|
2575
|
+
const result = findFlow(sites, ref);
|
|
2576
|
+
if (!result) {
|
|
2577
|
+
return errorResponse(command.id, `Flow "${ref}" not found. Available sites: ${[...sites.keys()].join(', ')}`);
|
|
2578
|
+
}
|
|
2579
|
+
const typedParams = {};
|
|
2580
|
+
if (result.flow.params) {
|
|
2581
|
+
for (const param of result.flow.params) {
|
|
2582
|
+
const raw = command.params?.[param.name];
|
|
2583
|
+
if (raw !== undefined) {
|
|
2584
|
+
switch (param.type) {
|
|
2585
|
+
case 'number':
|
|
2586
|
+
typedParams[param.name] = Number(raw);
|
|
2587
|
+
break;
|
|
2588
|
+
case 'boolean':
|
|
2589
|
+
typedParams[param.name] = raw === 'true' || raw === '1';
|
|
2590
|
+
break;
|
|
2591
|
+
default:
|
|
2592
|
+
typedParams[param.name] = raw;
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
const executor = new FlowExecutor(browser);
|
|
2598
|
+
const flowResult = await executor.execute(result.site, result.flowName, typedParams);
|
|
2599
|
+
return successResponse(command.id, flowResult);
|
|
2600
|
+
}
|
|
2601
|
+
function handleFlowExport(command) {
|
|
2602
|
+
const filePath = command.filePath;
|
|
2603
|
+
if (!filePath) {
|
|
2604
|
+
return errorResponse(command.id, 'Missing file path for export');
|
|
2605
|
+
}
|
|
2606
|
+
let site;
|
|
2607
|
+
try {
|
|
2608
|
+
site = parseYamlSiteFile(filePath);
|
|
2609
|
+
}
|
|
2610
|
+
catch (e) {
|
|
2611
|
+
return errorResponse(command.id, `Failed to parse YAML file: ${e instanceof Error ? e.message : String(e)}`);
|
|
2612
|
+
}
|
|
2613
|
+
const flowEntries = Object.entries(site.flows);
|
|
2614
|
+
if (flowEntries.length === 0) {
|
|
2615
|
+
return errorResponse(command.id, 'No flows found in YAML file');
|
|
2616
|
+
}
|
|
2617
|
+
const flow = flowEntries[0][1];
|
|
2618
|
+
const format = command.format || 'playwright';
|
|
2619
|
+
const exporterMap = {
|
|
2620
|
+
playwright: new PlaywrightExporter(),
|
|
2621
|
+
python: new PythonExporter(),
|
|
2622
|
+
};
|
|
2623
|
+
const exporter = exporterMap[format];
|
|
2624
|
+
if (!exporter) {
|
|
2625
|
+
return errorResponse(command.id, `Unknown export format: "${format}". Available: ${Object.keys(exporterMap).join(', ')}`);
|
|
2626
|
+
}
|
|
2627
|
+
try {
|
|
2628
|
+
const script = exporter.export(flow.steps, {
|
|
2629
|
+
baseUrl: command.baseUrl || site.baseUrl,
|
|
2630
|
+
headless: command.headless,
|
|
2631
|
+
});
|
|
2632
|
+
return successResponse(command.id, {
|
|
2633
|
+
format: exporter.format,
|
|
2634
|
+
extension: exporter.extension,
|
|
2635
|
+
script,
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
catch (e) {
|
|
2639
|
+
return errorResponse(command.id, `Export failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2373
2642
|
//# sourceMappingURL=actions.js.map
|