agent-browser 0.17.1 → 0.19.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 +194 -62
- package/bin/agent-browser-darwin-arm64 +0 -0
- package/bin/agent-browser-darwin-x64 +0 -0
- package/bin/agent-browser-linux-arm64 +0 -0
- package/bin/agent-browser-linux-x64 +0 -0
- package/bin/agent-browser-win32-x64.exe +0 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +108 -45
- package/dist/actions.js.map +1 -1
- package/dist/browser.d.ts +50 -4
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +245 -38
- package/dist/browser.js.map +1 -1
- package/dist/daemon.d.ts +5 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +62 -3
- package/dist/daemon.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect-server.d.ts +26 -0
- package/dist/inspect-server.d.ts.map +1 -0
- package/dist/inspect-server.js +218 -0
- package/dist/inspect-server.js.map +1 -0
- package/dist/protocol.d.ts +3 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +7 -3
- package/dist/protocol.js.map +1 -1
- package/dist/types.d.ts +10 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -2
- package/skills/agent-browser/SKILL.md +116 -14
- package/skills/agent-browser/references/authentication.md +101 -0
- package/skills/agent-browser/references/commands.md +2 -0
- package/skills/vercel-sandbox/SKILL.md +280 -0
package/dist/actions.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import { exec } from 'node:child_process';
|
|
3
4
|
import { mkdirSync } from 'node:fs';
|
|
4
5
|
import { getAppDir } from './daemon.js';
|
|
5
6
|
import { checkPolicy, describeAction, getActionCategory, loadPolicyFile, initPolicyReloader, reloadPolicyIfChanged, } from './action-policy.js';
|
|
@@ -229,6 +230,10 @@ async function dispatchAction(command, browser) {
|
|
|
229
230
|
return await handleReload(command, browser);
|
|
230
231
|
case 'url':
|
|
231
232
|
return await handleUrl(command, browser);
|
|
233
|
+
case 'cdp_url':
|
|
234
|
+
return handleCdpUrl(command, browser);
|
|
235
|
+
case 'inspect':
|
|
236
|
+
return await handleInspect(command, browser);
|
|
232
237
|
case 'title':
|
|
233
238
|
return await handleTitle(command, browser);
|
|
234
239
|
case 'getattribute':
|
|
@@ -406,19 +411,11 @@ async function handleLaunch(command, browser) {
|
|
|
406
411
|
return successResponse(command.id, { launched: true });
|
|
407
412
|
}
|
|
408
413
|
async function handleNavigate(command, browser) {
|
|
409
|
-
browser.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (command.headers && Object.keys(command.headers).length > 0) {
|
|
413
|
-
await browser.setScopedHeaders(command.url, command.headers);
|
|
414
|
-
}
|
|
415
|
-
await page.goto(command.url, {
|
|
416
|
-
waitUntil: command.waitUntil ?? 'load',
|
|
417
|
-
});
|
|
418
|
-
return successResponse(command.id, {
|
|
419
|
-
url: page.url(),
|
|
420
|
-
title: await page.title(),
|
|
414
|
+
const result = await browser.navigate(command.url, {
|
|
415
|
+
headers: command.headers,
|
|
416
|
+
waitUntil: command.waitUntil,
|
|
421
417
|
});
|
|
418
|
+
return successResponse(command.id, result);
|
|
422
419
|
}
|
|
423
420
|
async function handleClick(command, browser) {
|
|
424
421
|
// Support both refs (@e1) and regular selectors
|
|
@@ -508,7 +505,7 @@ async function handleScreenshot(command, browser) {
|
|
|
508
505
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
509
506
|
const random = Math.random().toString(36).substring(2, 8);
|
|
510
507
|
const filename = `screenshot-${timestamp}-${random}.${ext}`;
|
|
511
|
-
const screenshotDir = path.join(getAppDir(), 'tmp', 'screenshots');
|
|
508
|
+
const screenshotDir = command.screenshotDir ?? path.join(getAppDir(), 'tmp', 'screenshots');
|
|
512
509
|
mkdirSync(screenshotDir, { recursive: true });
|
|
513
510
|
savePath = path.join(screenshotDir, filename);
|
|
514
511
|
}
|
|
@@ -691,7 +688,10 @@ async function handleEvaluate(command, browser) {
|
|
|
691
688
|
}
|
|
692
689
|
async function handleWait(command, browser) {
|
|
693
690
|
const page = browser.getPage();
|
|
694
|
-
if (command.
|
|
691
|
+
if (command.text) {
|
|
692
|
+
await page.waitForFunction(`(document.body.innerText || '').includes(${JSON.stringify(command.text)})`, { timeout: command.timeout });
|
|
693
|
+
}
|
|
694
|
+
else if (command.selector) {
|
|
695
695
|
await page.waitForSelector(command.selector, {
|
|
696
696
|
state: command.state ?? 'visible',
|
|
697
697
|
timeout: command.timeout,
|
|
@@ -701,7 +701,6 @@ async function handleWait(command, browser) {
|
|
|
701
701
|
await page.waitForTimeout(command.timeout);
|
|
702
702
|
}
|
|
703
703
|
else {
|
|
704
|
-
// Default: wait for load state
|
|
705
704
|
await page.waitForLoadState('load');
|
|
706
705
|
}
|
|
707
706
|
return successResponse(command.id, { waited: true });
|
|
@@ -767,7 +766,8 @@ async function handleContent(command, browser) {
|
|
|
767
766
|
const page = browser.getPage();
|
|
768
767
|
let html;
|
|
769
768
|
if (command.selector) {
|
|
770
|
-
|
|
769
|
+
const locator = browser.getLocator(command.selector);
|
|
770
|
+
html = await locator.innerHTML();
|
|
771
771
|
}
|
|
772
772
|
else {
|
|
773
773
|
html = await page.content();
|
|
@@ -1145,6 +1145,62 @@ async function handleUrl(command, browser) {
|
|
|
1145
1145
|
const page = browser.getPage();
|
|
1146
1146
|
return successResponse(command.id, { url: page.url() });
|
|
1147
1147
|
}
|
|
1148
|
+
function handleCdpUrl(command, browser) {
|
|
1149
|
+
const cdpUrl = browser.getCdpUrl();
|
|
1150
|
+
if (!cdpUrl) {
|
|
1151
|
+
return errorResponse(command.id, 'CDP URL not available (browser may not be launched)');
|
|
1152
|
+
}
|
|
1153
|
+
return successResponse(command.id, { cdpUrl });
|
|
1154
|
+
}
|
|
1155
|
+
async function handleInspect(command, browser) {
|
|
1156
|
+
const cdpUrl = browser.getCdpUrl();
|
|
1157
|
+
if (!cdpUrl) {
|
|
1158
|
+
return errorResponse(command.id, 'CDP URL not available (browser may not be launched)');
|
|
1159
|
+
}
|
|
1160
|
+
// Shut down any existing inspect server so we always target the current page
|
|
1161
|
+
browser.stopInspectServer();
|
|
1162
|
+
const stripped = cdpUrl.replace(/^(wss?|https?):\/\//, '');
|
|
1163
|
+
const hostPort = stripped.split('/')[0];
|
|
1164
|
+
// Get the target ID so the inspect server can create its own dedicated CDP session
|
|
1165
|
+
const page = browser.getPage();
|
|
1166
|
+
const context = page.context();
|
|
1167
|
+
const tmpCdp = await context.newCDPSession(page);
|
|
1168
|
+
let targetId = '';
|
|
1169
|
+
try {
|
|
1170
|
+
const info = await tmpCdp.send('Target.getTargetInfo');
|
|
1171
|
+
targetId = info?.targetInfo?.targetId || '';
|
|
1172
|
+
}
|
|
1173
|
+
catch (err) {
|
|
1174
|
+
console.error('[inspect] getTargetInfo failed:', err);
|
|
1175
|
+
}
|
|
1176
|
+
await tmpCdp.detach();
|
|
1177
|
+
if (!targetId) {
|
|
1178
|
+
return errorResponse(command.id, 'Could not determine target ID for active page');
|
|
1179
|
+
}
|
|
1180
|
+
const { InspectServer } = await import('./inspect-server.js');
|
|
1181
|
+
const server = new InspectServer({
|
|
1182
|
+
chromeHostPort: hostPort,
|
|
1183
|
+
targetId,
|
|
1184
|
+
chromeWsUrl: cdpUrl,
|
|
1185
|
+
});
|
|
1186
|
+
await server.start();
|
|
1187
|
+
browser.setInspectServer(server);
|
|
1188
|
+
const url = `http://127.0.0.1:${server.port}`;
|
|
1189
|
+
openUrlInBrowser(url);
|
|
1190
|
+
return successResponse(command.id, { opened: true, url });
|
|
1191
|
+
}
|
|
1192
|
+
function openUrlInBrowser(url) {
|
|
1193
|
+
const platform = process.platform;
|
|
1194
|
+
const cmd = platform === 'darwin'
|
|
1195
|
+
? `open "${url}"`
|
|
1196
|
+
: platform === 'win32'
|
|
1197
|
+
? `start "" "${url}"`
|
|
1198
|
+
: `xdg-open "${url}"`;
|
|
1199
|
+
exec(cmd, (err) => {
|
|
1200
|
+
if (err)
|
|
1201
|
+
console.error('[inspect] Failed to open browser:', err.message);
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1148
1204
|
async function handleTitle(command, browser) {
|
|
1149
1205
|
const page = browser.getPage();
|
|
1150
1206
|
const title = await page.title();
|
|
@@ -1159,7 +1215,8 @@ async function handleGetAttribute(command, browser) {
|
|
|
1159
1215
|
async function handleGetText(command, browser) {
|
|
1160
1216
|
const page = browser.getPage();
|
|
1161
1217
|
const locator = browser.getLocator(command.selector);
|
|
1162
|
-
const
|
|
1218
|
+
const inner = await locator.innerText();
|
|
1219
|
+
const text = inner || (await locator.textContent()) || '';
|
|
1163
1220
|
return successResponse(command.id, { text, origin: page.url() });
|
|
1164
1221
|
}
|
|
1165
1222
|
async function handleIsVisible(command, browser) {
|
|
@@ -1178,13 +1235,13 @@ async function handleIsChecked(command, browser) {
|
|
|
1178
1235
|
return successResponse(command.id, { checked });
|
|
1179
1236
|
}
|
|
1180
1237
|
async function handleCount(command, browser) {
|
|
1181
|
-
const
|
|
1182
|
-
const count = await
|
|
1238
|
+
const locator = browser.getLocator(command.selector);
|
|
1239
|
+
const count = await locator.count();
|
|
1183
1240
|
return successResponse(command.id, { count });
|
|
1184
1241
|
}
|
|
1185
1242
|
async function handleBoundingBox(command, browser) {
|
|
1186
|
-
const
|
|
1187
|
-
const box = await
|
|
1243
|
+
const locator = browser.getLocator(command.selector);
|
|
1244
|
+
const box = await locator.boundingBox();
|
|
1188
1245
|
return successResponse(command.id, { box });
|
|
1189
1246
|
}
|
|
1190
1247
|
async function handleStyles(command, browser) {
|
|
@@ -1303,8 +1360,6 @@ async function handleStateLoad(command, browser) {
|
|
|
1303
1360
|
return errorResponse(command.id, `State file not found: ${command.path}`);
|
|
1304
1361
|
}
|
|
1305
1362
|
await browser.launch({
|
|
1306
|
-
id: command.id,
|
|
1307
|
-
action: 'launch',
|
|
1308
1363
|
headless: true,
|
|
1309
1364
|
autoStateFilePath: command.path,
|
|
1310
1365
|
});
|
|
@@ -1472,7 +1527,7 @@ async function handleKeyboard(command, browser) {
|
|
|
1472
1527
|
async function handleWheel(command, browser) {
|
|
1473
1528
|
const page = browser.getPage();
|
|
1474
1529
|
if (command.selector) {
|
|
1475
|
-
const element =
|
|
1530
|
+
const element = browser.getLocator(command.selector);
|
|
1476
1531
|
await element.hover();
|
|
1477
1532
|
}
|
|
1478
1533
|
await page.mouse.wheel(command.deltaX ?? 0, command.deltaY ?? 0);
|
|
@@ -1487,41 +1542,50 @@ async function handleClipboard(command, browser) {
|
|
|
1487
1542
|
const page = browser.getPage();
|
|
1488
1543
|
switch (command.operation) {
|
|
1489
1544
|
case 'copy':
|
|
1490
|
-
await page.keyboard.press('
|
|
1545
|
+
await page.keyboard.press('ControlOrMeta+c');
|
|
1491
1546
|
return successResponse(command.id, { copied: true });
|
|
1492
1547
|
case 'paste':
|
|
1493
|
-
await page.keyboard.press('
|
|
1548
|
+
await page.keyboard.press('ControlOrMeta+v');
|
|
1494
1549
|
return successResponse(command.id, { pasted: true });
|
|
1495
|
-
case 'read':
|
|
1550
|
+
case 'read': {
|
|
1496
1551
|
const text = await page.evaluate('navigator.clipboard.readText()');
|
|
1497
1552
|
return successResponse(command.id, { text });
|
|
1553
|
+
}
|
|
1554
|
+
case 'write': {
|
|
1555
|
+
if (!command.text) {
|
|
1556
|
+
return errorResponse(command.id, "Missing 'text' parameter for clipboard write");
|
|
1557
|
+
}
|
|
1558
|
+
await page.evaluate(`navigator.clipboard.writeText(${JSON.stringify(command.text)})`);
|
|
1559
|
+
return successResponse(command.id, { written: command.text });
|
|
1560
|
+
}
|
|
1498
1561
|
default:
|
|
1499
1562
|
return errorResponse(command.id, 'Unknown clipboard operation');
|
|
1500
1563
|
}
|
|
1501
1564
|
}
|
|
1502
1565
|
async function handleHighlight(command, browser) {
|
|
1503
|
-
const
|
|
1504
|
-
await
|
|
1566
|
+
const locator = browser.getLocator(command.selector);
|
|
1567
|
+
await locator.highlight();
|
|
1505
1568
|
return successResponse(command.id, { highlighted: true });
|
|
1506
1569
|
}
|
|
1507
1570
|
async function handleClear(command, browser) {
|
|
1508
|
-
const
|
|
1509
|
-
await
|
|
1571
|
+
const locator = browser.getLocator(command.selector);
|
|
1572
|
+
await locator.clear();
|
|
1510
1573
|
return successResponse(command.id, { cleared: true });
|
|
1511
1574
|
}
|
|
1512
1575
|
async function handleSelectAll(command, browser) {
|
|
1513
|
-
const
|
|
1514
|
-
await
|
|
1576
|
+
const locator = browser.getLocator(command.selector);
|
|
1577
|
+
await locator.selectText();
|
|
1515
1578
|
return successResponse(command.id, { selected: true });
|
|
1516
1579
|
}
|
|
1517
1580
|
async function handleInnerText(command, browser) {
|
|
1518
|
-
const
|
|
1519
|
-
const text = await
|
|
1581
|
+
const locator = browser.getLocator(command.selector);
|
|
1582
|
+
const text = await locator.innerText();
|
|
1520
1583
|
return successResponse(command.id, { text });
|
|
1521
1584
|
}
|
|
1522
1585
|
async function handleInnerHtml(command, browser) {
|
|
1523
1586
|
const page = browser.getPage();
|
|
1524
|
-
const
|
|
1587
|
+
const locator = browser.getLocator(command.selector);
|
|
1588
|
+
const html = await locator.innerHTML();
|
|
1525
1589
|
return successResponse(command.id, { html, origin: page.url() });
|
|
1526
1590
|
}
|
|
1527
1591
|
async function handleInputValue(command, browser) {
|
|
@@ -1531,13 +1595,13 @@ async function handleInputValue(command, browser) {
|
|
|
1531
1595
|
return successResponse(command.id, { value, origin: page.url() });
|
|
1532
1596
|
}
|
|
1533
1597
|
async function handleSetValue(command, browser) {
|
|
1534
|
-
const
|
|
1535
|
-
await
|
|
1598
|
+
const locator = browser.getLocator(command.selector);
|
|
1599
|
+
await locator.fill(command.value);
|
|
1536
1600
|
return successResponse(command.id, { set: true });
|
|
1537
1601
|
}
|
|
1538
1602
|
async function handleDispatch(command, browser) {
|
|
1539
|
-
const
|
|
1540
|
-
await
|
|
1603
|
+
const locator = browser.getLocator(command.selector);
|
|
1604
|
+
await locator.dispatchEvent(command.event, command.eventInit);
|
|
1541
1605
|
return successResponse(command.id, { dispatched: command.event });
|
|
1542
1606
|
}
|
|
1543
1607
|
async function handleEvalHandle(command, browser) {
|
|
@@ -1643,8 +1707,7 @@ async function handleGetByTestId(command, browser) {
|
|
|
1643
1707
|
}
|
|
1644
1708
|
}
|
|
1645
1709
|
async function handleNth(command, browser) {
|
|
1646
|
-
const
|
|
1647
|
-
const base = page.locator(command.selector);
|
|
1710
|
+
const base = browser.getLocator(command.selector);
|
|
1648
1711
|
const locator = command.index === -1 ? base.last() : base.nth(command.index);
|
|
1649
1712
|
switch (command.subaction) {
|
|
1650
1713
|
case 'click':
|
|
@@ -1754,8 +1817,8 @@ async function handleInsertText(command, browser) {
|
|
|
1754
1817
|
return successResponse(command.id, { inserted: true });
|
|
1755
1818
|
}
|
|
1756
1819
|
async function handleMultiSelect(command, browser) {
|
|
1757
|
-
const
|
|
1758
|
-
const selected = await
|
|
1820
|
+
const locator = browser.getLocator(command.selector);
|
|
1821
|
+
const selected = await locator.selectOption(command.values);
|
|
1759
1822
|
return successResponse(command.id, { selected });
|
|
1760
1823
|
}
|
|
1761
1824
|
async function handleWaitForDownload(command, browser) {
|
|
@@ -1903,7 +1966,7 @@ async function handleDiffScreenshot(command, browser) {
|
|
|
1903
1966
|
const page = browser.getPage();
|
|
1904
1967
|
let screenshotBuffer;
|
|
1905
1968
|
if (command.selector) {
|
|
1906
|
-
const locator = browser.
|
|
1969
|
+
const locator = browser.getLocator(command.selector);
|
|
1907
1970
|
screenshotBuffer = await locator.screenshot({ type: 'png' });
|
|
1908
1971
|
}
|
|
1909
1972
|
else {
|