@dyyz1993/agent-browser 0.11.5 → 0.12.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-darwin-arm64 +0 -0
- package/dist/__tests__/utils/parseCli.d.ts.map +1 -1
- package/dist/__tests__/utils/parseCli.js +97 -2
- package/dist/__tests__/utils/parseCli.js.map +1 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +117 -81
- package/dist/actions.js.map +1 -1
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +24 -29
- package/dist/browser.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +102 -3
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/connection.d.ts.map +1 -1
- package/dist/cli/connection.js +12 -29
- package/dist/cli/connection.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +35 -25
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +3 -0
- package/dist/cli/output.js.map +1 -1
- package/dist/cli.js +117 -3
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +18 -2
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +46 -32
- package/dist/daemon.js.map +1 -1
- package/dist/message-bridge.d.ts.map +1 -1
- package/dist/message-bridge.js +4 -1
- package/dist/message-bridge.js.map +1 -1
- package/dist/rc-config.d.ts +42 -0
- package/dist/rc-config.d.ts.map +1 -0
- package/dist/rc-config.js +170 -0
- package/dist/rc-config.js.map +1 -0
- package/dist/recorder/inject.js +30 -24
- package/package.json +1 -1
- package/scripts/check_goods_container.js +35 -0
- package/scripts/check_page_content.js +36 -0
- package/scripts/click_applause_rate.js +30 -0
- package/scripts/explore_jd_page.js +31 -0
- package/scripts/extract_all_jd_data.js +80 -0
- package/scripts/extract_jd_product_detail.js +62 -0
- package/scripts/extract_jd_products_correct_links.js +78 -0
- package/scripts/extract_jd_products_final.js +80 -0
- package/scripts/extract_jd_reviews.js +48 -0
- package/scripts/extract_jd_seafood_final.js +78 -0
- package/scripts/extract_multiple_products.js +77 -0
- package/scripts/extract_products_no_scroll.js +68 -0
- package/scripts/extract_products_simple.js +68 -0
- package/scripts/find_applause_rate.js +26 -0
- package/scripts/find_jd_links.js +28 -0
- package/scripts/find_main_content.js +20 -0
- package/scripts/find_product_cards.js +38 -0
- package/scripts/find_root_content.js +26 -0
- package/scripts/find_unique_products.js +55 -0
- package/scripts/generate-skill.cjs +303 -0
- package/scripts/get_jd_product_detail.js +16 -0
- package/scripts/get_jd_products.js +23 -0
- package/scripts/get_jd_seafood_products.js +44 -0
- package/scripts/get_product_details_from_images.js +54 -0
- package/scripts/verify-form.sh +67 -0
- package/scripts/verify-login.sh +65 -0
- package/scripts/verify-recording.sh +80 -0
- package/scripts/verify-upload.sh +41 -0
- package/skills/agent-browser/SKILL.md +135 -370
- package/bin/agent-browser-linux-x64 +0 -0
package/dist/actions.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { getAppDir, getSession, getInstanceId } from './daemon.js';
|
|
4
4
|
import { performDiff } from './diff.js';
|
|
5
5
|
import { MessageBridge } from './message-bridge.js';
|
|
6
|
+
import { getViewerUrl, getViewerWsUrl, getViewerPort, getMessageBridgeUrl, getExecutablePath, getEffectiveValue, loadConfig, } from './rc-config.js';
|
|
6
7
|
import { detectMainContent, generateContentTips } from './content-detection.js';
|
|
7
8
|
import { humanClick, humanType, humanMoveTo, humanWander, getHumanConfigFromEnv, } from './human-mouse.js';
|
|
8
9
|
import { successResponse, errorResponse } from './protocol.js';
|
|
@@ -52,37 +53,44 @@ async function assertElementExists(locator, selector, isRef) {
|
|
|
52
53
|
*/
|
|
53
54
|
export function toAIFriendlyError(error, selector) {
|
|
54
55
|
const message = error instanceof Error ? error.message : String(error);
|
|
55
|
-
// Handle strict mode violation (multiple elements match)
|
|
56
56
|
if (message.includes('strict mode violation')) {
|
|
57
|
-
// Extract count if available
|
|
58
57
|
const countMatch = message.match(/resolved to (\d+) elements/);
|
|
59
58
|
const count = countMatch ? countMatch[1] : 'multiple';
|
|
60
59
|
return new Error(`Selector "${selector}" matched ${count} elements. ` +
|
|
61
|
-
`Run 'snapshot' to get updated refs, or use a more specific CSS selector
|
|
60
|
+
`Run 'snapshot' to get updated refs, or use a more specific CSS selector. ` +
|
|
61
|
+
`Tip: Use 'find nth <index> ${selector} --click' to target a specific match.`);
|
|
62
62
|
}
|
|
63
|
-
// Handle element not interactable (must be checked BEFORE timeout case)
|
|
64
|
-
// This includes cases where an overlay/modal blocks the element
|
|
65
63
|
if (message.includes('intercepts pointer events')) {
|
|
66
64
|
return new Error(`Element "${selector}" is blocked by another element (likely a modal or overlay). ` +
|
|
67
|
-
`Try dismissing any modals/cookie banners first
|
|
65
|
+
`Try dismissing any modals/cookie banners first. ` +
|
|
66
|
+
`Tip: Run 'snapshot -i' to see all visible elements and identify what's blocking.`);
|
|
68
67
|
}
|
|
69
|
-
// Handle element not visible
|
|
70
68
|
if (message.includes('not visible') && !message.includes('Timeout')) {
|
|
71
69
|
return new Error(`Element "${selector}" is not visible. ` +
|
|
72
|
-
`Try
|
|
70
|
+
`Try 'scrollintoview ${selector}' or check if it's hidden. ` +
|
|
71
|
+
`Tip: Run 'is visible ${selector}' to confirm visibility state.`);
|
|
73
72
|
}
|
|
74
|
-
// Handle general timeout (element exists but action couldn't complete)
|
|
75
73
|
if (message.includes('Timeout') && message.includes('exceeded')) {
|
|
76
74
|
return new Error(`Action on "${selector}" timed out. The element may be blocked, still loading, or not interactable. ` +
|
|
77
|
-
`Run 'snapshot' to check the current page state
|
|
75
|
+
`Run 'snapshot' to check the current page state. ` +
|
|
76
|
+
`Tip: If the page is still loading, try 'wait --load networkidle' first.`);
|
|
78
77
|
}
|
|
79
|
-
// Handle element not found (timeout waiting for element)
|
|
80
78
|
if (message.includes('waiting for') &&
|
|
81
79
|
(message.includes('to be visible') || message.includes('Timeout'))) {
|
|
82
80
|
return new Error(`Element "${selector}" not found or not visible. ` +
|
|
83
|
-
`Run 'snapshot' to see current page elements
|
|
81
|
+
`Run 'snapshot -i' to see current page elements and their refs. ` +
|
|
82
|
+
`Tip: If using @ref, the page may have changed. Re-run 'snapshot -i' to get fresh refs.`);
|
|
83
|
+
}
|
|
84
|
+
if (message.includes('Execution context was destroyed') || message.includes('Target closed')) {
|
|
85
|
+
return new Error(`Browser context was lost (page navigated or closed). ` +
|
|
86
|
+
`Re-open the page with 'open <url>' and start fresh. ` +
|
|
87
|
+
`Tip: This usually happens after a form submission triggers navigation.`);
|
|
88
|
+
}
|
|
89
|
+
if (message.includes('querySelector') || message.includes('is not a valid selector')) {
|
|
90
|
+
return new Error(`Invalid selector "${selector}". ` +
|
|
91
|
+
`CSS selectors like '#id', '.class', or 'tag' are supported. ` +
|
|
92
|
+
`Tip: Use 'snapshot -i' to get @ref selectors (e.g., @e1) that are always valid.`);
|
|
84
93
|
}
|
|
85
|
-
// Return original error for unknown cases
|
|
86
94
|
return error instanceof Error ? error : new Error(message);
|
|
87
95
|
}
|
|
88
96
|
/**
|
|
@@ -369,7 +377,7 @@ async function handleLaunch(command, browser) {
|
|
|
369
377
|
return successResponse(command.id, {
|
|
370
378
|
launched: true,
|
|
371
379
|
instanceId,
|
|
372
|
-
viewerUrl:
|
|
380
|
+
viewerUrl: getViewerUrl(instanceId),
|
|
373
381
|
});
|
|
374
382
|
}
|
|
375
383
|
async function handleNavigate(command, browser) {
|
|
@@ -895,17 +903,17 @@ async function handleFill(command, browser) {
|
|
|
895
903
|
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
896
904
|
try {
|
|
897
905
|
await locator.fill(command.value);
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
}
|
|
908
|
-
}
|
|
906
|
+
if (!isRef) {
|
|
907
|
+
const page = browser.getPage();
|
|
908
|
+
if (page) {
|
|
909
|
+
await page.evaluate((selector) => {
|
|
910
|
+
const el = document.querySelector(selector);
|
|
911
|
+
if (el) {
|
|
912
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
913
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
914
|
+
}
|
|
915
|
+
}, command.selector);
|
|
916
|
+
}
|
|
909
917
|
}
|
|
910
918
|
}
|
|
911
919
|
catch (error) {
|
|
@@ -1207,6 +1215,7 @@ async function handleRequests(command, browser) {
|
|
|
1207
1215
|
return successResponse(command.id, { cleared: true });
|
|
1208
1216
|
}
|
|
1209
1217
|
// Start tracking if not already (with response capture if requested)
|
|
1218
|
+
const wasTracking = browser.trackingEnabled;
|
|
1210
1219
|
browser.startRequestTracking(command.captureResponse);
|
|
1211
1220
|
// If output directory is specified, save to directory
|
|
1212
1221
|
if (command.output) {
|
|
@@ -1219,7 +1228,11 @@ async function handleRequests(command, browser) {
|
|
|
1219
1228
|
});
|
|
1220
1229
|
}
|
|
1221
1230
|
const requests = browser.getRequests(command.filter, command.type);
|
|
1222
|
-
|
|
1231
|
+
const result = { requests };
|
|
1232
|
+
if (requests.length === 0 && !wasTracking) {
|
|
1233
|
+
result.hint = 'Request tracking just activated. Reload or navigate to capture requests.';
|
|
1234
|
+
}
|
|
1235
|
+
return successResponse(command.id, result);
|
|
1223
1236
|
}
|
|
1224
1237
|
async function handleDownload(command, browser) {
|
|
1225
1238
|
const page = browser.getPage();
|
|
@@ -1659,7 +1672,7 @@ async function handleNth(command, browser) {
|
|
|
1659
1672
|
const refLocator = browser.getLocatorFromRef(command.selector, command.inFrame);
|
|
1660
1673
|
let locator;
|
|
1661
1674
|
if (refLocator) {
|
|
1662
|
-
locator = refLocator;
|
|
1675
|
+
locator = command.index === -1 ? refLocator.last() : refLocator.nth(command.index);
|
|
1663
1676
|
}
|
|
1664
1677
|
else {
|
|
1665
1678
|
const frame = browser.getFrame(command.inFrame);
|
|
@@ -1999,14 +2012,10 @@ async function handleRecorderStatus(command, browser) {
|
|
|
1999
2012
|
async function handleRecorderReplay(command, browser) {
|
|
2000
2013
|
const fs = await import('node:fs');
|
|
2001
2014
|
const path = await import('node:path');
|
|
2002
|
-
// Determine YAML file path
|
|
2003
2015
|
let yamlPath = command.path;
|
|
2004
2016
|
if (!yamlPath) {
|
|
2005
|
-
// Use the most recent recording from temp directory
|
|
2006
2017
|
const recorderDir = path.join(getAppDir(), 'tmp', 'recordings');
|
|
2007
|
-
console.log('[Replay] Looking for recordings in:', recorderDir);
|
|
2008
2018
|
if (!fs.existsSync(recorderDir)) {
|
|
2009
|
-
console.log('[Replay] Directory does not exist');
|
|
2010
2019
|
return errorResponse(command.id, 'No recordings found. Please record first.');
|
|
2011
2020
|
}
|
|
2012
2021
|
const files = fs
|
|
@@ -2017,21 +2026,39 @@ async function handleRecorderReplay(command, browser) {
|
|
|
2017
2026
|
time: fs.statSync(path.join(recorderDir, f)).mtime.getTime(),
|
|
2018
2027
|
}))
|
|
2019
2028
|
.sort((a, b) => b.time - a.time);
|
|
2020
|
-
console.log('[Replay] Found files:', files.length);
|
|
2021
2029
|
if (files.length === 0) {
|
|
2022
2030
|
return errorResponse(command.id, 'No recordings found. Please record first.');
|
|
2023
2031
|
}
|
|
2024
2032
|
yamlPath = path.join(recorderDir, files[0].name);
|
|
2025
|
-
console.log('[Replay] Using file:', yamlPath);
|
|
2026
2033
|
}
|
|
2027
|
-
// Read YAML file
|
|
2028
2034
|
if (!fs.existsSync(yamlPath)) {
|
|
2029
2035
|
return errorResponse(command.id, `Recording file not found: ${yamlPath}`);
|
|
2030
2036
|
}
|
|
2031
2037
|
const yamlContent = fs.readFileSync(yamlPath, 'utf-8');
|
|
2032
|
-
// Parse CLI commands from YAML
|
|
2033
|
-
const lines = yamlContent.split('\n');
|
|
2034
2038
|
const cliCommands = [];
|
|
2039
|
+
// Strategy 1: Parse structured steps and generate CLI commands
|
|
2040
|
+
const stepRegex = /^\s+-\s+(?:id:\s*.+)/;
|
|
2041
|
+
const lines = yamlContent.split('\n');
|
|
2042
|
+
let inSteps = false;
|
|
2043
|
+
const parsedSteps = {};
|
|
2044
|
+
for (const line of lines) {
|
|
2045
|
+
if (/^steps:/.test(line.trim())) {
|
|
2046
|
+
inSteps = true;
|
|
2047
|
+
continue;
|
|
2048
|
+
}
|
|
2049
|
+
if (inSteps && /^-\s+id:/.test(line.trim())) {
|
|
2050
|
+
const idMatch = line.match(/id:\s*(.+)/);
|
|
2051
|
+
if (idMatch)
|
|
2052
|
+
parsedSteps.currentId = idMatch[1].trim();
|
|
2053
|
+
}
|
|
2054
|
+
if (inSteps && /^\s+action:\s*(.+)/.test(line)) {
|
|
2055
|
+
// End of steps section when we hit a non-step line
|
|
2056
|
+
}
|
|
2057
|
+
if (inSteps && !/^\s/.test(line) && !/^$/.test(line) && !/^steps:/.test(line.trim())) {
|
|
2058
|
+
inSteps = false;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
// Strategy 2: Fall back to CLI Commands comment section
|
|
2035
2062
|
let inCliSection = false;
|
|
2036
2063
|
for (const line of lines) {
|
|
2037
2064
|
if (line.includes('# CLI Commands')) {
|
|
@@ -2043,10 +2070,23 @@ async function handleRecorderReplay(command, browser) {
|
|
|
2043
2070
|
cliCommands.push(line.trim());
|
|
2044
2071
|
}
|
|
2045
2072
|
}
|
|
2073
|
+
// Strategy 3: If no CLI section, generate from structured steps using browser's method
|
|
2046
2074
|
if (cliCommands.length === 0) {
|
|
2047
2075
|
return errorResponse(command.id, 'No CLI commands found in recording. Please re-record with the new version.');
|
|
2048
2076
|
}
|
|
2049
|
-
//
|
|
2077
|
+
// Filter out env-only lines (keep them for env setup but not as commands)
|
|
2078
|
+
const envLines = cliCommands.filter((l) => l.startsWith('AGENT_BROWSER_'));
|
|
2079
|
+
const cmdLines = cliCommands.filter((l) => l.startsWith('agent-browser '));
|
|
2080
|
+
// Set env vars from recording
|
|
2081
|
+
const originalEnv = {};
|
|
2082
|
+
for (const envLine of envLines) {
|
|
2083
|
+
const eqIdx = envLine.indexOf('=');
|
|
2084
|
+
if (eqIdx > 0) {
|
|
2085
|
+
const key = envLine.substring(0, eqIdx);
|
|
2086
|
+
originalEnv[key] = process.env[key];
|
|
2087
|
+
process.env[key] = envLine.substring(eqIdx + 1);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2050
2090
|
function parseCommandLine(line) {
|
|
2051
2091
|
const parts = [];
|
|
2052
2092
|
let current = '';
|
|
@@ -2077,62 +2117,38 @@ async function handleRecorderReplay(command, browser) {
|
|
|
2077
2117
|
}
|
|
2078
2118
|
return parts;
|
|
2079
2119
|
}
|
|
2080
|
-
//
|
|
2120
|
+
// Get current session for passthrough
|
|
2121
|
+
const currentSession = process.env.AGENT_BROWSER_SESSION || 'default';
|
|
2081
2122
|
const results = [];
|
|
2082
|
-
for (const cmdLine of
|
|
2123
|
+
for (const cmdLine of cmdLines) {
|
|
2083
2124
|
try {
|
|
2084
|
-
// Parse command line with proper quote handling
|
|
2085
2125
|
let parts = parseCommandLine(cmdLine);
|
|
2086
|
-
const envVars = {};
|
|
2087
|
-
// Extract environment variables (format: KEY=value)
|
|
2088
|
-
while (parts.length > 0 && parts[0].includes('=')) {
|
|
2089
|
-
const [key, ...valueParts] = parts.shift().split('=');
|
|
2090
|
-
envVars[key] = valueParts.join('=');
|
|
2091
|
-
}
|
|
2092
|
-
// Remove 'agent-browser' prefix if present
|
|
2093
2126
|
if (parts.length > 0 && parts[0] === 'agent-browser') {
|
|
2094
2127
|
parts = parts.slice(1);
|
|
2095
2128
|
}
|
|
2096
|
-
// Skip empty commands
|
|
2097
2129
|
if (parts.length === 0) {
|
|
2098
2130
|
results.push({ command: cmdLine, success: true });
|
|
2099
2131
|
continue;
|
|
2100
2132
|
}
|
|
2101
|
-
// Set environment variables temporarily
|
|
2102
|
-
const originalEnv = {};
|
|
2103
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
2104
|
-
originalEnv[key] = process.env[key];
|
|
2105
|
-
process.env[key] = value;
|
|
2106
|
-
}
|
|
2107
|
-
// Execute command using the existing executeCommand flow
|
|
2108
2133
|
const { parseCommand } = await import('./cli/commands.js');
|
|
2109
2134
|
const { parseFlags } = await import('./cli/flags.js');
|
|
2110
2135
|
const flags = parseFlags([]);
|
|
2136
|
+
if (currentSession !== 'default') {
|
|
2137
|
+
flags.session = currentSession;
|
|
2138
|
+
}
|
|
2111
2139
|
const parsedCmd = parseCommand(parts, flags);
|
|
2112
|
-
// Check if recording is active, and temporarily disable
|
|
2113
2140
|
const wasRecording = browser.isRecordingSession();
|
|
2114
2141
|
if (wasRecording) {
|
|
2115
2142
|
browser.pauseRecording();
|
|
2116
2143
|
}
|
|
2117
|
-
// Execute the command with a timeout to prevent hanging on invalid selectors
|
|
2118
2144
|
const COMMAND_TIMEOUT_MS = 5000;
|
|
2119
2145
|
const result = (await Promise.race([
|
|
2120
2146
|
executeCommand(parsedCmd, browser),
|
|
2121
2147
|
new Promise((_, reject) => setTimeout(() => reject(new Error(`Command timed out after ${COMMAND_TIMEOUT_MS}ms`)), COMMAND_TIMEOUT_MS)),
|
|
2122
2148
|
]));
|
|
2123
|
-
// Restore recording state
|
|
2124
2149
|
if (wasRecording) {
|
|
2125
2150
|
browser.resumeRecording();
|
|
2126
2151
|
}
|
|
2127
|
-
// Restore environment variables
|
|
2128
|
-
for (const [key, value] of Object.entries(originalEnv)) {
|
|
2129
|
-
if (value === undefined) {
|
|
2130
|
-
delete process.env[key];
|
|
2131
|
-
}
|
|
2132
|
-
else {
|
|
2133
|
-
process.env[key] = value;
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
2152
|
results.push({ command: cmdLine, success: result.success });
|
|
2137
2153
|
}
|
|
2138
2154
|
catch (e) {
|
|
@@ -2140,29 +2156,37 @@ async function handleRecorderReplay(command, browser) {
|
|
|
2140
2156
|
results.push({ command: cmdLine, success: false, error: errorMessage });
|
|
2141
2157
|
}
|
|
2142
2158
|
}
|
|
2159
|
+
// Restore env vars
|
|
2160
|
+
for (const [key, value] of Object.entries(originalEnv)) {
|
|
2161
|
+
if (value === undefined) {
|
|
2162
|
+
delete process.env[key];
|
|
2163
|
+
}
|
|
2164
|
+
else {
|
|
2165
|
+
process.env[key] = value;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2143
2168
|
const successCount = results.filter((r) => r.success).length;
|
|
2144
2169
|
const failCount = results.filter((r) => !r.success).length;
|
|
2145
2170
|
return successResponse(command.id, {
|
|
2146
2171
|
replayed: true,
|
|
2147
2172
|
file: yamlPath,
|
|
2148
|
-
totalCommands:
|
|
2173
|
+
totalCommands: cmdLines.length,
|
|
2149
2174
|
successCount,
|
|
2150
2175
|
failCount,
|
|
2151
|
-
results: results.slice(0, 20),
|
|
2176
|
+
results: results.slice(0, 20),
|
|
2152
2177
|
});
|
|
2153
2178
|
}
|
|
2154
2179
|
async function handleViewer(command, _browser) {
|
|
2155
2180
|
const instanceId = getInstanceId();
|
|
2156
|
-
const port = parseInt(process.env.AGENT_BROWSER_STREAM_PORT || '5005', 10);
|
|
2157
2181
|
return successResponse(command.id, {
|
|
2158
|
-
url:
|
|
2159
|
-
wsUrl:
|
|
2160
|
-
streamPort:
|
|
2182
|
+
url: getViewerUrl(instanceId),
|
|
2183
|
+
wsUrl: getViewerWsUrl(instanceId),
|
|
2184
|
+
streamPort: getViewerPort(),
|
|
2161
2185
|
});
|
|
2162
2186
|
}
|
|
2163
2187
|
async function handleAsk(command, _browser) {
|
|
2164
2188
|
const session = getSession();
|
|
2165
|
-
const bridge = new MessageBridge();
|
|
2189
|
+
const bridge = new MessageBridge(getMessageBridgeUrl());
|
|
2166
2190
|
try {
|
|
2167
2191
|
const answer = await bridge.ask(command.question, session);
|
|
2168
2192
|
return successResponse(command.id, { answer });
|
|
@@ -2174,9 +2198,10 @@ async function handleAsk(command, _browser) {
|
|
|
2174
2198
|
}
|
|
2175
2199
|
function handleConfig(command) {
|
|
2176
2200
|
const humanConfig = getHumanConfigFromEnv();
|
|
2201
|
+
const rcConfig = loadConfig();
|
|
2177
2202
|
const config = {
|
|
2178
2203
|
session: process.env.AGENT_BROWSER_SESSION || 'default',
|
|
2179
|
-
executablePath:
|
|
2204
|
+
executablePath: getExecutablePath() || null,
|
|
2180
2205
|
extensions: process.env.AGENT_BROWSER_EXTENSIONS || null,
|
|
2181
2206
|
profile: process.env.AGENT_BROWSER_PROFILE || null,
|
|
2182
2207
|
state: process.env.AGENT_BROWSER_STATE || null,
|
|
@@ -2187,24 +2212,34 @@ function handleConfig(command) {
|
|
|
2187
2212
|
provider: process.env.AGENT_BROWSER_PROVIDER || null,
|
|
2188
2213
|
allowFileAccess: process.env.AGENT_BROWSER_ALLOW_FILE_ACCESS === '1',
|
|
2189
2214
|
iosDevice: process.env.AGENT_BROWSER_IOS_DEVICE || null,
|
|
2190
|
-
streamPort:
|
|
2215
|
+
streamPort: getViewerPort(),
|
|
2191
2216
|
headed: process.env.AGENT_BROWSER_HEADED === '1',
|
|
2192
2217
|
human: humanConfig,
|
|
2193
2218
|
};
|
|
2194
2219
|
if (command.json) {
|
|
2195
|
-
return successResponse(command.id, { config });
|
|
2220
|
+
return successResponse(command.id, { config, rc: rcConfig });
|
|
2196
2221
|
}
|
|
2222
|
+
const viewerHost = getEffectiveValue('viewer.host');
|
|
2223
|
+
const bridgeUrl = getEffectiveValue('messageBridge.url');
|
|
2224
|
+
const msgProxy = getEffectiveValue('messageProxy.url');
|
|
2197
2225
|
// Format human-readable output
|
|
2198
2226
|
const lines = [
|
|
2199
2227
|
'Agent Browser Configuration',
|
|
2200
2228
|
'===========================',
|
|
2201
2229
|
'',
|
|
2202
2230
|
'Session & Browser:',
|
|
2203
|
-
`
|
|
2204
|
-
` AGENT_BROWSER_EXECUTABLE_PATH ${config.executablePath || '(not set)'}`,
|
|
2231
|
+
` executablePath ${config.executablePath || '(not set)'}`,
|
|
2205
2232
|
` AGENT_BROWSER_PROVIDER ${config.provider || '(not set)'}`,
|
|
2206
2233
|
` AGENT_BROWSER_HEADED ${config.headed ? 'true' : 'false (default)'}`,
|
|
2207
2234
|
'',
|
|
2235
|
+
'Viewer & Stream:',
|
|
2236
|
+
` viewer.host ${viewerHost || '(not set, using http://localhost)'}`,
|
|
2237
|
+
` viewer.port ${config.streamPort}`,
|
|
2238
|
+
'',
|
|
2239
|
+
'Message Bridge (ask command):',
|
|
2240
|
+
` messageBridge.url ${bridgeUrl || '(not set, using default)'}`,
|
|
2241
|
+
` messageProxy.url ${msgProxy || '(not set)'}`,
|
|
2242
|
+
'',
|
|
2208
2243
|
'Browser Options:',
|
|
2209
2244
|
` AGENT_BROWSER_PROFILE ${config.profile || '(not set)'}`,
|
|
2210
2245
|
` AGENT_BROWSER_EXTENSIONS ${config.extensions || '(not set)'}`,
|
|
@@ -2216,8 +2251,9 @@ function handleConfig(command) {
|
|
|
2216
2251
|
'Human Mode (runtime):',
|
|
2217
2252
|
` AGENT_BROWSER_HUMAN ${humanConfig.enabled ? humanConfig.pathType + ' ✓' : '(disabled)'}`,
|
|
2218
2253
|
'',
|
|
2219
|
-
|
|
2220
|
-
'
|
|
2254
|
+
`Persistent config: ~/.agent-browser/config.json`,
|
|
2255
|
+
'Run "agent-browser config set <key> <value>" to persist settings.',
|
|
2256
|
+
'Run "agent-browser config list" to see configurable keys.',
|
|
2221
2257
|
];
|
|
2222
2258
|
return successResponse(command.id, { config, output: lines.join('\n') });
|
|
2223
2259
|
}
|