@kritchoff/agent-browser 0.9.2 → 0.9.4
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/dist/actions.js +27 -2
- package/dist/actions.js.map +1 -1
- package/dist/browser.d.ts +4 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +13 -2
- package/dist/browser.js.map +1 -1
- package/dist/daemon.d.ts +0 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/daemon.js.map +1 -1
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -0
- package/dist/snapshot.d.ts +9 -16
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/snapshot.js +0 -161
- package/dist/snapshot.js.map +1 -1
- package/dist/taxtree.d.ts +6 -0
- package/dist/taxtree.d.ts.map +1 -0
- package/dist/taxtree.js +287 -0
- package/dist/taxtree.js.map +1 -0
- package/package.json +3 -1
- package/start.sh +117 -0
package/dist/taxtree.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
export async function getDualModeSnapshot(page, options = {}) {
|
|
2
|
+
const session = await page.context().newCDPSession(page);
|
|
3
|
+
let nodes = [];
|
|
4
|
+
let isDualMode = false;
|
|
5
|
+
try {
|
|
6
|
+
const result = (await session.send('Accessibility.getDualModeAXTree'));
|
|
7
|
+
nodes = result.nodes;
|
|
8
|
+
isDualMode = true;
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
try {
|
|
12
|
+
const result = (await session.send('Accessibility.getFullAXTree'));
|
|
13
|
+
nodes = result.nodes;
|
|
14
|
+
}
|
|
15
|
+
catch (e2) {
|
|
16
|
+
console.warn('Failed to fetch AXTree via CDP:', e2);
|
|
17
|
+
return { tree: '(accessibility tree unavailable)', refs: {} };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await session.detach();
|
|
22
|
+
}
|
|
23
|
+
const refs = {};
|
|
24
|
+
let tree = '';
|
|
25
|
+
resetRefs();
|
|
26
|
+
if (isDualMode) {
|
|
27
|
+
const rootNodes = buildTreeFromFlatNodes(nodes);
|
|
28
|
+
tree = processDualModeTree(rootNodes, refs, options.interactive ?? false);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const rootNodes = buildStandardTree(nodes);
|
|
32
|
+
tree = processStandardTree(rootNodes, refs, options.interactive ?? false);
|
|
33
|
+
}
|
|
34
|
+
return { tree, refs };
|
|
35
|
+
}
|
|
36
|
+
function buildTreeFromFlatNodes(nodes) {
|
|
37
|
+
const nodeMap = new Map();
|
|
38
|
+
nodes.forEach((n) => nodeMap.set(n.core.nodeId, n));
|
|
39
|
+
const roots = [];
|
|
40
|
+
nodes.forEach((node) => {
|
|
41
|
+
if (node.core.childrenIds) {
|
|
42
|
+
node.children = node.core.childrenIds
|
|
43
|
+
.map((id) => nodeMap.get(id))
|
|
44
|
+
.filter((n) => !!n);
|
|
45
|
+
}
|
|
46
|
+
const parentId = node.core.parentId;
|
|
47
|
+
if (parentId === undefined || !nodeMap.has(parentId)) {
|
|
48
|
+
roots.push(node);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return roots;
|
|
52
|
+
}
|
|
53
|
+
function buildStandardTree(nodes) {
|
|
54
|
+
const nodeMap = new Map();
|
|
55
|
+
// Initialize with empty children array
|
|
56
|
+
nodes.forEach((n) => nodeMap.set(n.nodeId, { ...n, children: [] }));
|
|
57
|
+
const roots = [];
|
|
58
|
+
const childrenIdsSet = new Set();
|
|
59
|
+
nodes.forEach((node) => {
|
|
60
|
+
if (node.childIds) {
|
|
61
|
+
const parent = nodeMap.get(node.nodeId);
|
|
62
|
+
if (parent) {
|
|
63
|
+
node.childIds.forEach((childId) => {
|
|
64
|
+
const child = nodeMap.get(childId);
|
|
65
|
+
if (child) {
|
|
66
|
+
parent.children.push(child);
|
|
67
|
+
childrenIdsSet.add(childId);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
nodes.forEach((node) => {
|
|
74
|
+
if (!childrenIdsSet.has(node.nodeId)) {
|
|
75
|
+
const root = nodeMap.get(node.nodeId);
|
|
76
|
+
if (root)
|
|
77
|
+
roots.push(root);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return roots;
|
|
81
|
+
}
|
|
82
|
+
let refCounter = 0;
|
|
83
|
+
function resetRefs() {
|
|
84
|
+
refCounter = 0;
|
|
85
|
+
}
|
|
86
|
+
function nextRef() {
|
|
87
|
+
return `e${++refCounter}`;
|
|
88
|
+
}
|
|
89
|
+
const INTERACTIVE_ROLES = new Set([
|
|
90
|
+
'button',
|
|
91
|
+
'link',
|
|
92
|
+
'textbox',
|
|
93
|
+
'checkbox',
|
|
94
|
+
'radio',
|
|
95
|
+
'combobox',
|
|
96
|
+
'listbox',
|
|
97
|
+
'menuitem',
|
|
98
|
+
'option',
|
|
99
|
+
'searchbox',
|
|
100
|
+
'slider',
|
|
101
|
+
'spinbutton',
|
|
102
|
+
'switch',
|
|
103
|
+
'tab',
|
|
104
|
+
'treeitem',
|
|
105
|
+
]);
|
|
106
|
+
function processDualModeTree(nodes, refs, interactiveOnly = false, depth = 0) {
|
|
107
|
+
const lines = [];
|
|
108
|
+
for (const node of nodes) {
|
|
109
|
+
const core = node.core;
|
|
110
|
+
if (!core.visible)
|
|
111
|
+
continue;
|
|
112
|
+
const semantics = node.xrayMode?.semantics || {};
|
|
113
|
+
const interaction = node.xrayMode?.interaction || {};
|
|
114
|
+
const design = node.designMode || {};
|
|
115
|
+
const role = (semantics.role || core.className || 'unknown').toLowerCase();
|
|
116
|
+
let name = semantics.name || core.text || core.contentDescription || '';
|
|
117
|
+
name = name.replace(/\s+/g, ' ').trim();
|
|
118
|
+
// Smart Merge: Use child text if name is empty
|
|
119
|
+
if (name === '' && node.children && node.children.length > 0) {
|
|
120
|
+
const textChild = node.children.find((c) => c.core.className === '#text.StaticText');
|
|
121
|
+
if (textChild) {
|
|
122
|
+
name = (textChild.core.text || '').trim();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const isInteractive = core.clickable ||
|
|
126
|
+
INTERACTIVE_ROLES.has(role) ||
|
|
127
|
+
semantics.intentTags?.includes('interactive');
|
|
128
|
+
if (interactiveOnly && !isInteractive && (!node.children || node.children.length === 0)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
let line = `${' '.repeat(depth)}- ${role}`;
|
|
132
|
+
if (name)
|
|
133
|
+
line += ` "${name.replace(/"/g, '\\"')}"`;
|
|
134
|
+
if (isInteractive || (name && !['unknown', 'generic', 'group'].includes(role))) {
|
|
135
|
+
const ref = nextRef();
|
|
136
|
+
line += ` [ref=${ref}]`;
|
|
137
|
+
const safeNameDouble = name.replace(/"/g, '\\"');
|
|
138
|
+
let selector = '';
|
|
139
|
+
if (['button', 'link', 'textbox', 'checkbox', 'radio'].includes(role)) {
|
|
140
|
+
if (name)
|
|
141
|
+
selector = `getByRole('${role}', { name: "${safeNameDouble}" })`;
|
|
142
|
+
else
|
|
143
|
+
selector = `getByRole('${role}')`;
|
|
144
|
+
}
|
|
145
|
+
else if (name) {
|
|
146
|
+
selector = `getByText("${safeNameDouble}")`;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
selector = `locator('.${core.className || role}')`;
|
|
150
|
+
}
|
|
151
|
+
refs[ref] = {
|
|
152
|
+
selector,
|
|
153
|
+
role,
|
|
154
|
+
name,
|
|
155
|
+
bounds: core.bounds,
|
|
156
|
+
nodeId: core.nodeId,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// --- FULL METADATA OUTPUT ---
|
|
160
|
+
// 1. Core Info (filtered to interesting flags)
|
|
161
|
+
const coreInfo = {};
|
|
162
|
+
if (core.clickable)
|
|
163
|
+
coreInfo.clickable = true;
|
|
164
|
+
if (core.longClickable)
|
|
165
|
+
coreInfo.longClickable = true;
|
|
166
|
+
if (core.scrollable)
|
|
167
|
+
coreInfo.scrollable = true;
|
|
168
|
+
if (core.focusable)
|
|
169
|
+
coreInfo.focusable = true;
|
|
170
|
+
if (core.editable)
|
|
171
|
+
coreInfo.editable = true;
|
|
172
|
+
if (core.checkable)
|
|
173
|
+
coreInfo.checkable = true;
|
|
174
|
+
if (core.checked)
|
|
175
|
+
coreInfo.checked = true;
|
|
176
|
+
if (core.selected)
|
|
177
|
+
coreInfo.selected = true;
|
|
178
|
+
if (core.focused)
|
|
179
|
+
coreInfo.focused = true;
|
|
180
|
+
if (!core.enabled)
|
|
181
|
+
coreInfo.disabled = true;
|
|
182
|
+
// 2. Xray Info (semantics + interaction)
|
|
183
|
+
const xrayInfo = {};
|
|
184
|
+
if (semantics.importanceScore)
|
|
185
|
+
xrayInfo.importance = semantics.importanceScore;
|
|
186
|
+
if (semantics.intentTags?.length)
|
|
187
|
+
xrayInfo.intent = semantics.intentTags;
|
|
188
|
+
if (interaction.availableActions?.length)
|
|
189
|
+
xrayInfo.actions = interaction.availableActions;
|
|
190
|
+
if (interaction.affordanceScore)
|
|
191
|
+
xrayInfo.affordance = interaction.affordanceScore;
|
|
192
|
+
// 3. Design Info (visual + layout + spatial)
|
|
193
|
+
// Only include if non-default/interesting
|
|
194
|
+
const designInfo = {};
|
|
195
|
+
if (design.visual) {
|
|
196
|
+
if (design.visual.backgroundColor)
|
|
197
|
+
designInfo.bg = design.visual.backgroundColor;
|
|
198
|
+
if (design.visual.foregroundColor)
|
|
199
|
+
designInfo.fg = design.visual.foregroundColor;
|
|
200
|
+
if (design.visual.fontSize)
|
|
201
|
+
designInfo.fontSize = design.visual.fontSize;
|
|
202
|
+
if (design.visual.fontWeight && design.visual.fontWeight !== 400)
|
|
203
|
+
designInfo.weight = design.visual.fontWeight;
|
|
204
|
+
if (design.visual.opacity !== 1)
|
|
205
|
+
designInfo.opacity = design.visual.opacity;
|
|
206
|
+
}
|
|
207
|
+
if (design.layout) {
|
|
208
|
+
if (design.layout.zIndex !== 0)
|
|
209
|
+
designInfo.zIndex = design.layout.zIndex;
|
|
210
|
+
if (design.layout.isFixedPosition)
|
|
211
|
+
designInfo.fixed = true;
|
|
212
|
+
if (design.layout.isSticky)
|
|
213
|
+
designInfo.sticky = true;
|
|
214
|
+
}
|
|
215
|
+
if (design.spatial) {
|
|
216
|
+
if (!design.spatial.isAboveFold)
|
|
217
|
+
designInfo.belowFold = true;
|
|
218
|
+
if (design.spatial.visualProminenceScore)
|
|
219
|
+
designInfo.prominence = design.spatial.visualProminenceScore;
|
|
220
|
+
}
|
|
221
|
+
// Append JSON objects to line, indented
|
|
222
|
+
const indent = ' '.repeat(depth + 1);
|
|
223
|
+
if (Object.keys(coreInfo).length > 0) {
|
|
224
|
+
line += `\n${indent}core: ${JSON.stringify(coreInfo)}`;
|
|
225
|
+
}
|
|
226
|
+
if (Object.keys(xrayInfo).length > 0) {
|
|
227
|
+
line += `\n${indent}xray: ${JSON.stringify(xrayInfo)}`;
|
|
228
|
+
}
|
|
229
|
+
if (Object.keys(designInfo).length > 0) {
|
|
230
|
+
line += `\n${indent}design: ${JSON.stringify(designInfo)}`;
|
|
231
|
+
}
|
|
232
|
+
lines.push(line);
|
|
233
|
+
if (node.children) {
|
|
234
|
+
const filteredChildren = node.children.filter((c) => c.core.className !== '#text.StaticText');
|
|
235
|
+
if (filteredChildren.length > 0) {
|
|
236
|
+
const childrenStr = processDualModeTree(filteredChildren, refs, interactiveOnly, depth + 1);
|
|
237
|
+
if (childrenStr)
|
|
238
|
+
lines.push(childrenStr);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return lines.join('\n');
|
|
243
|
+
}
|
|
244
|
+
function processStandardTree(nodes, refs, interactiveOnly, depth = 0) {
|
|
245
|
+
const lines = [];
|
|
246
|
+
for (const node of nodes) {
|
|
247
|
+
const role = (node.role?.value || 'unknown').toLowerCase();
|
|
248
|
+
let name = node.name?.value || '';
|
|
249
|
+
name = name.replace(/\s+/g, ' ').trim();
|
|
250
|
+
const isInteractive = INTERACTIVE_ROLES.has(role);
|
|
251
|
+
let line = `${' '.repeat(depth)}- ${role}`;
|
|
252
|
+
if (name) {
|
|
253
|
+
line += ` "${name.replace(/"/g, '\\"')}"`;
|
|
254
|
+
}
|
|
255
|
+
if (isInteractive || (name && role !== 'unknown')) {
|
|
256
|
+
const ref = nextRef();
|
|
257
|
+
line += ` [ref=${ref}]`;
|
|
258
|
+
const safeNameDouble = name.replace(/"/g, '\\"');
|
|
259
|
+
let selector = '';
|
|
260
|
+
if (isInteractive) {
|
|
261
|
+
if (name)
|
|
262
|
+
selector = `getByRole('${role}', { name: "${safeNameDouble}" })`;
|
|
263
|
+
else
|
|
264
|
+
selector = `getByRole('${role}')`;
|
|
265
|
+
}
|
|
266
|
+
else if (name) {
|
|
267
|
+
selector = `getByText("${safeNameDouble}")`;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
selector = `locator('${role}')`;
|
|
271
|
+
}
|
|
272
|
+
refs[ref] = {
|
|
273
|
+
selector: selector,
|
|
274
|
+
role: role,
|
|
275
|
+
name: name,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
lines.push(line);
|
|
279
|
+
if (node.children && node.children.length > 0) {
|
|
280
|
+
const childrenTree = processStandardTree(node.children, refs, interactiveOnly, depth + 1);
|
|
281
|
+
if (childrenTree)
|
|
282
|
+
lines.push(childrenTree);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return lines.join('\n');
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=taxtree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taxtree.js","sourceRoot":"","sources":["../src/taxtree.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kritchoff/agent-browser",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "Headless browser automation CLI for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"scripts",
|
|
12
12
|
"skills",
|
|
13
13
|
"sdk.sh",
|
|
14
|
+
"start.sh",
|
|
14
15
|
"docker-compose.sdk.yml"
|
|
15
16
|
],
|
|
16
17
|
"bin": {
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
"fast-reset": "./scripts/fast_reset.sh",
|
|
32
33
|
"sdk": "./sdk.sh",
|
|
33
34
|
"release": "npm run version:sync && npm run build && npm run build:all-platforms && npm publish",
|
|
35
|
+
"prepublishOnly": "npm run build",
|
|
34
36
|
"start": "node dist/daemon.js",
|
|
35
37
|
"dev": "tsx src/daemon.ts",
|
|
36
38
|
"typecheck": "tsc --noEmit",
|
package/start.sh
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Colors
|
|
5
|
+
GREEN='\033[0;32m'
|
|
6
|
+
BLUE='\033[0;34m'
|
|
7
|
+
YELLOW='\033[1;33m'
|
|
8
|
+
RED='\033[0;31m'
|
|
9
|
+
NC='\033[0m' # No Color
|
|
10
|
+
|
|
11
|
+
echo -e "${BLUE}=================================================${NC}"
|
|
12
|
+
echo -e "${BLUE} Agent Browser - Android Environment Setup ${NC}"
|
|
13
|
+
echo -e "${BLUE}=================================================${NC}"
|
|
14
|
+
|
|
15
|
+
SNAPSHOT_PATH=""
|
|
16
|
+
while [[ $# -gt 0 ]]; do
|
|
17
|
+
case $1 in
|
|
18
|
+
--snapshot)
|
|
19
|
+
SNAPSHOT_PATH="$2"
|
|
20
|
+
shift 2
|
|
21
|
+
;;
|
|
22
|
+
*)
|
|
23
|
+
echo "Unknown option: $1"
|
|
24
|
+
exit 1
|
|
25
|
+
;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
# 1. Pre-flight Checks
|
|
30
|
+
echo -e "\n${YELLOW}[1/4] Checking System Requirements...${NC}"
|
|
31
|
+
|
|
32
|
+
if ! command -v docker &> /dev/null; then
|
|
33
|
+
echo -e "${RED}Error: Docker is not installed.${NC}"
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|
38
|
+
if [ -e /dev/kvm ]; then
|
|
39
|
+
echo -e "${GREEN}✓ KVM Acceleration detected (/dev/kvm)${NC}"
|
|
40
|
+
else
|
|
41
|
+
echo -e "${YELLOW}⚠ Warning: No KVM detected. Emulator will be slow.${NC}"
|
|
42
|
+
fi
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# 2. Start Services
|
|
46
|
+
echo -e "\n${YELLOW}[2/4] Starting Docker Stack...${NC}"
|
|
47
|
+
echo " (First run may take a few minutes to download images)"
|
|
48
|
+
|
|
49
|
+
docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" up -d --build --remove-orphans > /dev/null 2>&1
|
|
50
|
+
|
|
51
|
+
# Find actual container names
|
|
52
|
+
ANDROID_CONTAINER=$(docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" ps -q android-service)
|
|
53
|
+
AGENT_CONTAINER=$(docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" ps -q agent-service)
|
|
54
|
+
|
|
55
|
+
# 2b. Import Snapshot (if requested)
|
|
56
|
+
if [ -n "$SNAPSHOT_PATH" ]; then
|
|
57
|
+
echo -e "\n${YELLOW}[2.5/4] Importing Snapshot: $SNAPSHOT_PATH...${NC}"
|
|
58
|
+
|
|
59
|
+
# Wait for container to be responsive
|
|
60
|
+
echo -n " Waiting for container to be ready for import... "
|
|
61
|
+
until docker exec "$ANDROID_CONTAINER" echo "ready" &>/dev/null; do
|
|
62
|
+
sleep 1
|
|
63
|
+
done
|
|
64
|
+
echo -e "${GREEN}OK${NC}"
|
|
65
|
+
|
|
66
|
+
# Import
|
|
67
|
+
if ./scripts/snapshot_manager.sh import "$SNAPSHOT_PATH" "w8rl_imported"; then
|
|
68
|
+
echo -e "${GREEN} Snapshot imported successfully.${NC}"
|
|
69
|
+
|
|
70
|
+
# Configure emulator to load this snapshot
|
|
71
|
+
# We set the env var in the container for the next boot
|
|
72
|
+
# (This assumes the entrypoint script respects EMULATOR_SNAPSHOT_NAME)
|
|
73
|
+
# For now, we'll rely on the default behavior or standard AVD loading
|
|
74
|
+
|
|
75
|
+
echo " Restarting Android service to load snapshot..."
|
|
76
|
+
docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" restart android-service
|
|
77
|
+
|
|
78
|
+
# Update container ID after restart
|
|
79
|
+
ANDROID_CONTAINER=$(docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" ps -q android-service)
|
|
80
|
+
else
|
|
81
|
+
echo -e "${RED}Error: Failed to import snapshot.${NC}"
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# 3. Wait for Readiness
|
|
87
|
+
echo -e "\n${YELLOW}[3/4] Waiting for Initialization...${NC}"
|
|
88
|
+
|
|
89
|
+
wait_for_log() {
|
|
90
|
+
local container=$1
|
|
91
|
+
local pattern=$2
|
|
92
|
+
local label=$3
|
|
93
|
+
|
|
94
|
+
echo -n " Waiting for $label... "
|
|
95
|
+
until docker logs "$container" 2>&1 | grep -q "$pattern"; do
|
|
96
|
+
sleep 2
|
|
97
|
+
done
|
|
98
|
+
echo -e "${GREEN}Done!${NC}"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
wait_for_log "$ANDROID_CONTAINER" "Emulator boot complete" "Android Emulator Boot"
|
|
102
|
+
wait_for_log "$ANDROID_CONTAINER" "APK installation complete" "WootzApp Installation"
|
|
103
|
+
wait_for_log "$ANDROID_CONTAINER" "CDP Bridge ready" "CDP Bridge"
|
|
104
|
+
wait_for_log "$AGENT_CONTAINER" "Ready on port 3000" "Agent Daemon Connection"
|
|
105
|
+
|
|
106
|
+
# 4. Success
|
|
107
|
+
echo -e "\n${GREEN}[4/4] Environment Ready!${NC}"
|
|
108
|
+
echo -e "${BLUE}=================================================${NC}"
|
|
109
|
+
echo -e "You can now control the Android browser."
|
|
110
|
+
echo -e ""
|
|
111
|
+
echo -e "Try these commands:"
|
|
112
|
+
echo -e " ${GREEN}./agent open https://google.com${NC}"
|
|
113
|
+
echo -e " ${GREEN}./agent snapshot${NC}"
|
|
114
|
+
echo -e " ${GREEN}./agent click @e1${NC}"
|
|
115
|
+
echo -e ""
|
|
116
|
+
echo -e "See COMMANDS.md for full reference."
|
|
117
|
+
echo -e "${BLUE}=================================================${NC}"
|