hyper-agent-browser 0.1.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/LICENSE +21 -0
- package/README.md +196 -0
- package/package.json +63 -0
- package/src/browser/context.ts +66 -0
- package/src/browser/manager.ts +414 -0
- package/src/browser/sync-chrome-data.ts +53 -0
- package/src/cli.ts +628 -0
- package/src/cli.ts.backup +529 -0
- package/src/commands/actions.ts +232 -0
- package/src/commands/advanced.ts +252 -0
- package/src/commands/config.ts +44 -0
- package/src/commands/getters.ts +110 -0
- package/src/commands/info.ts +195 -0
- package/src/commands/navigation.ts +50 -0
- package/src/commands/session.ts +83 -0
- package/src/daemon/browser-pool.ts +65 -0
- package/src/daemon/client.ts +128 -0
- package/src/daemon/main.ts +200 -0
- package/src/daemon/server.ts +562 -0
- package/src/session/manager.ts +110 -0
- package/src/session/store.ts +172 -0
- package/src/snapshot/accessibility.ts +182 -0
- package/src/snapshot/dom-extractor.ts +220 -0
- package/src/snapshot/formatter.ts +115 -0
- package/src/snapshot/reference-store.ts +97 -0
- package/src/utils/config.ts +183 -0
- package/src/utils/errors.ts +121 -0
- package/src/utils/logger.ts +12 -0
- package/src/utils/selector.ts +23 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { BrowserContextManager } from "./browser/context";
|
|
4
|
+
import * as actionCommands from "./commands/actions";
|
|
5
|
+
import * as infoCommands from "./commands/info";
|
|
6
|
+
import * as navigationCommands from "./commands/navigation";
|
|
7
|
+
import * as sessionCommands from "./commands/session";
|
|
8
|
+
import * as configCommands from "./commands/config";
|
|
9
|
+
import { SessionManager } from "./session/manager";
|
|
10
|
+
import { ReferenceStore } from "./snapshot/reference-store";
|
|
11
|
+
import { formatError, getExitCode } from "./utils/errors";
|
|
12
|
+
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
// Global state
|
|
16
|
+
let sessionManager: SessionManager;
|
|
17
|
+
let currentSessionName: string;
|
|
18
|
+
let browserContext: BrowserContextManager | null = null;
|
|
19
|
+
let referenceStore: ReferenceStore | null = null;
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name("hba")
|
|
23
|
+
.description("hyperagentbrowser - Browser automation CLI for AI Agents")
|
|
24
|
+
.version("0.1.0");
|
|
25
|
+
|
|
26
|
+
// Global options
|
|
27
|
+
program
|
|
28
|
+
.option("-s, --session <name>", "Session name", "default")
|
|
29
|
+
.option("-H, --headed", "Show browser window", false)
|
|
30
|
+
.option("-c, --channel <browser>", "Browser channel (chrome/msedge/chromium)", "chrome")
|
|
31
|
+
.option("-t, --timeout <ms>", "Timeout in milliseconds", "30000")
|
|
32
|
+
.option("-v, --verbose", "Verbose output", false);
|
|
33
|
+
|
|
34
|
+
// Navigation commands
|
|
35
|
+
program
|
|
36
|
+
.command("open <url>")
|
|
37
|
+
.description("Open a URL")
|
|
38
|
+
.option("--wait-until <state>", "Wait until state (load/domcontentloaded/networkidle)", "load")
|
|
39
|
+
.action(async (url, options, command) => {
|
|
40
|
+
try {
|
|
41
|
+
await initSession(command.parent);
|
|
42
|
+
const page = await browserContext!.getPage(getBrowserOptions(command.parent));
|
|
43
|
+
|
|
44
|
+
await withOperationIndicator(`打开页面 ${url}`, async () => {
|
|
45
|
+
await navigationCommands.open(page, url, {
|
|
46
|
+
waitUntil: options.waitUntil as any,
|
|
47
|
+
timeout: getTimeout(command.parent),
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await updateSessionInfo();
|
|
52
|
+
console.log(`Opened: ${url}`);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
handleError(error);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
program
|
|
59
|
+
.command("reload")
|
|
60
|
+
.description("Reload current page")
|
|
61
|
+
.action(async (_options, command) => {
|
|
62
|
+
try {
|
|
63
|
+
await ensureConnected(command.parent);
|
|
64
|
+
const page = await browserContext!.getPage();
|
|
65
|
+
await withOperationIndicator("刷新页面", async () => {
|
|
66
|
+
await navigationCommands.reload(page);
|
|
67
|
+
});
|
|
68
|
+
console.log("Page reloaded");
|
|
69
|
+
} catch (error) {
|
|
70
|
+
handleError(error);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
program
|
|
75
|
+
.command("back")
|
|
76
|
+
.description("Go back in history")
|
|
77
|
+
.action(async (_options, command) => {
|
|
78
|
+
try {
|
|
79
|
+
await ensureConnected(command.parent);
|
|
80
|
+
const page = await browserContext!.getPage();
|
|
81
|
+
await withOperationIndicator("后退", async () => {
|
|
82
|
+
await navigationCommands.back(page);
|
|
83
|
+
});
|
|
84
|
+
console.log("Navigated back");
|
|
85
|
+
} catch (error) {
|
|
86
|
+
handleError(error);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
program
|
|
91
|
+
.command("forward")
|
|
92
|
+
.description("Go forward in history")
|
|
93
|
+
.action(async (_options, command) => {
|
|
94
|
+
try {
|
|
95
|
+
await ensureConnected(command.parent);
|
|
96
|
+
const page = await browserContext!.getPage();
|
|
97
|
+
await withOperationIndicator("前进", async () => {
|
|
98
|
+
await navigationCommands.forward(page);
|
|
99
|
+
});
|
|
100
|
+
console.log("Navigated forward");
|
|
101
|
+
} catch (error) {
|
|
102
|
+
handleError(error);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Action commands
|
|
107
|
+
program
|
|
108
|
+
.command("click <selector>")
|
|
109
|
+
.description("Click an element")
|
|
110
|
+
.action(async (selector, _options, command) => {
|
|
111
|
+
try {
|
|
112
|
+
await ensureConnected(command.parent);
|
|
113
|
+
const page = await browserContext!.getPage();
|
|
114
|
+
await withOperationIndicator(`点击 ${selector}`, async () => {
|
|
115
|
+
await actionCommands.click(page, selector);
|
|
116
|
+
});
|
|
117
|
+
console.log(`Clicked: ${selector}`);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
handleError(error);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
program
|
|
124
|
+
.command("fill <selector> <value>")
|
|
125
|
+
.description("Fill an input field")
|
|
126
|
+
.action(async (selector, value, _options, command) => {
|
|
127
|
+
try {
|
|
128
|
+
await ensureConnected(command.parent);
|
|
129
|
+
const page = await browserContext!.getPage();
|
|
130
|
+
await withOperationIndicator(`填写 ${selector}`, async () => {
|
|
131
|
+
await actionCommands.fill(page, selector, value);
|
|
132
|
+
});
|
|
133
|
+
console.log(`Filled: ${selector}`);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
handleError(error);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
program
|
|
140
|
+
.command("type <selector> <text>")
|
|
141
|
+
.description("Type text into an element")
|
|
142
|
+
.option("--delay <ms>", "Delay between keystrokes", "0")
|
|
143
|
+
.action(async (selector, text, options, command) => {
|
|
144
|
+
try {
|
|
145
|
+
await ensureConnected(command.parent);
|
|
146
|
+
const page = await browserContext!.getPage();
|
|
147
|
+
await withOperationIndicator(`输入文本到 ${selector}`, async () => {
|
|
148
|
+
await actionCommands.type(page, selector, text, Number.parseInt(options.delay));
|
|
149
|
+
});
|
|
150
|
+
console.log(`Typed into: ${selector}`);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
handleError(error);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
program
|
|
157
|
+
.command("press <key>")
|
|
158
|
+
.description("Press a key")
|
|
159
|
+
.action(async (key, _options, command) => {
|
|
160
|
+
try {
|
|
161
|
+
await ensureConnected(command.parent);
|
|
162
|
+
const page = await browserContext!.getPage();
|
|
163
|
+
await withOperationIndicator(`按键 ${key}`, async () => {
|
|
164
|
+
await actionCommands.press(page, key);
|
|
165
|
+
});
|
|
166
|
+
console.log(`Pressed: ${key}`);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
handleError(error);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
program
|
|
173
|
+
.command("scroll <direction>")
|
|
174
|
+
.description("Scroll page (up/down/left/right)")
|
|
175
|
+
.option("--amount <pixels>", "Scroll amount in pixels", "500")
|
|
176
|
+
.option("--selector <selector>", "Scroll within element")
|
|
177
|
+
.action(async (direction, options, command) => {
|
|
178
|
+
try {
|
|
179
|
+
await ensureConnected(command.parent);
|
|
180
|
+
const page = await browserContext!.getPage();
|
|
181
|
+
await withOperationIndicator(`滚动 ${direction}`, async () => {
|
|
182
|
+
await actionCommands.scroll(
|
|
183
|
+
page,
|
|
184
|
+
direction as any,
|
|
185
|
+
Number.parseInt(options.amount),
|
|
186
|
+
options.selector,
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
console.log(`Scrolled ${direction}`);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
handleError(error);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
program
|
|
196
|
+
.command("hover <selector>")
|
|
197
|
+
.description("Hover over an element")
|
|
198
|
+
.action(async (selector, _options, command) => {
|
|
199
|
+
try {
|
|
200
|
+
await ensureConnected(command.parent);
|
|
201
|
+
const page = await browserContext!.getPage();
|
|
202
|
+
await withOperationIndicator(`悬停 ${selector}`, async () => {
|
|
203
|
+
await actionCommands.hover(page, selector);
|
|
204
|
+
});
|
|
205
|
+
console.log(`Hovered: ${selector}`);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
handleError(error);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
program
|
|
212
|
+
.command("select <selector> <value>")
|
|
213
|
+
.description("Select option from dropdown")
|
|
214
|
+
.action(async (selector, value, _options, command) => {
|
|
215
|
+
try {
|
|
216
|
+
await ensureConnected(command.parent);
|
|
217
|
+
const page = await browserContext!.getPage();
|
|
218
|
+
await withOperationIndicator(`选择 ${value}`, async () => {
|
|
219
|
+
await actionCommands.select(page, selector, value);
|
|
220
|
+
});
|
|
221
|
+
console.log(`Selected: ${value} in ${selector}`);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
handleError(error);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
program
|
|
228
|
+
.command("wait <condition>")
|
|
229
|
+
.description("Wait for condition (ms/selector=/hidden=/navigation)")
|
|
230
|
+
.option("--timeout <ms>", "Timeout in milliseconds")
|
|
231
|
+
.action(async (condition, options, command) => {
|
|
232
|
+
try {
|
|
233
|
+
await ensureConnected(command.parent);
|
|
234
|
+
const page = await browserContext!.getPage();
|
|
235
|
+
|
|
236
|
+
const conditionValue = /^\d+$/.test(condition) ? Number.parseInt(condition) : condition;
|
|
237
|
+
await actionCommands.wait(page, conditionValue, {
|
|
238
|
+
timeout: options.timeout ? Number.parseInt(options.timeout) : undefined,
|
|
239
|
+
});
|
|
240
|
+
console.log("Wait completed");
|
|
241
|
+
} catch (error) {
|
|
242
|
+
handleError(error);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Info commands
|
|
247
|
+
program
|
|
248
|
+
.command("snapshot")
|
|
249
|
+
.description("Get page snapshot")
|
|
250
|
+
.option("-i, --interactive", "Show only interactive elements")
|
|
251
|
+
.option("-f, --full", "Show all elements")
|
|
252
|
+
.option("-r, --raw", "Output raw JSON")
|
|
253
|
+
.option("-o, --output <file>", "Output to file")
|
|
254
|
+
.action(async (options, command) => {
|
|
255
|
+
try {
|
|
256
|
+
await ensureConnected(command.parent);
|
|
257
|
+
const page = await browserContext!.getPage();
|
|
258
|
+
|
|
259
|
+
const result = await withOperationIndicator("获取页面快照", async () => {
|
|
260
|
+
return await infoCommands.snapshot(page, {
|
|
261
|
+
interactive: options.interactive,
|
|
262
|
+
full: options.full,
|
|
263
|
+
raw: options.raw,
|
|
264
|
+
referenceStore: referenceStore,
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
if (options.output) {
|
|
269
|
+
await Bun.write(options.output, result);
|
|
270
|
+
console.log(`Snapshot saved to: ${options.output}`);
|
|
271
|
+
} else {
|
|
272
|
+
console.log(result);
|
|
273
|
+
}
|
|
274
|
+
} catch (error) {
|
|
275
|
+
handleError(error);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
program
|
|
280
|
+
.command("screenshot")
|
|
281
|
+
.description("Take a screenshot")
|
|
282
|
+
.option("-o, --output <file>", "Output file", "screenshot.png")
|
|
283
|
+
.option("--full-page", "Capture full page")
|
|
284
|
+
.option("--selector <selector>", "Capture specific element")
|
|
285
|
+
.action(async (options, command) => {
|
|
286
|
+
try {
|
|
287
|
+
await ensureConnected(command.parent);
|
|
288
|
+
const page = await browserContext!.getPage();
|
|
289
|
+
|
|
290
|
+
const output = await withOperationIndicator("截图", async () => {
|
|
291
|
+
return await infoCommands.screenshot(page, {
|
|
292
|
+
output: options.output,
|
|
293
|
+
fullPage: options.fullPage,
|
|
294
|
+
selector: options.selector,
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
console.log(`Screenshot saved to: ${output}`);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
handleError(error);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
program
|
|
304
|
+
.command("evaluate <script>")
|
|
305
|
+
.description("Execute JavaScript in page context")
|
|
306
|
+
.action(async (script, _options, command) => {
|
|
307
|
+
try {
|
|
308
|
+
await ensureConnected(command.parent);
|
|
309
|
+
const page = await browserContext!.getPage();
|
|
310
|
+
const result = await infoCommands.evaluate(page, script);
|
|
311
|
+
console.log(result);
|
|
312
|
+
} catch (error) {
|
|
313
|
+
handleError(error);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
program
|
|
318
|
+
.command("url")
|
|
319
|
+
.description("Get current URL")
|
|
320
|
+
.action(async (_options, command) => {
|
|
321
|
+
try {
|
|
322
|
+
await ensureConnected(command.parent);
|
|
323
|
+
const page = await browserContext!.getPage();
|
|
324
|
+
const url = await infoCommands.url(page);
|
|
325
|
+
console.log(url);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
handleError(error);
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
program
|
|
332
|
+
.command("title")
|
|
333
|
+
.description("Get page title")
|
|
334
|
+
.action(async (_options, command) => {
|
|
335
|
+
try {
|
|
336
|
+
await ensureConnected(command.parent);
|
|
337
|
+
const page = await browserContext!.getPage();
|
|
338
|
+
const title = await infoCommands.title(page);
|
|
339
|
+
console.log(title);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
handleError(error);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
program
|
|
346
|
+
.command("content")
|
|
347
|
+
.description("Get page text content")
|
|
348
|
+
.option("--selector <selector>", "Get content from specific element")
|
|
349
|
+
.option("--max-length <n>", "Maximum length", "10000")
|
|
350
|
+
.action(async (options, command) => {
|
|
351
|
+
try {
|
|
352
|
+
await ensureConnected(command.parent);
|
|
353
|
+
const page = await browserContext!.getPage();
|
|
354
|
+
const text = await infoCommands.content(page, {
|
|
355
|
+
selector: options.selector,
|
|
356
|
+
maxLength: Number.parseInt(options.maxLength),
|
|
357
|
+
});
|
|
358
|
+
console.log(text);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
handleError(error);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Session commands
|
|
365
|
+
program
|
|
366
|
+
.command("sessions")
|
|
367
|
+
.description("List all sessions")
|
|
368
|
+
.option("--json", "Output as JSON")
|
|
369
|
+
.action(async (options) => {
|
|
370
|
+
try {
|
|
371
|
+
sessionManager = new SessionManager();
|
|
372
|
+
const output = await sessionCommands.listSessions(sessionManager, {
|
|
373
|
+
json: options.json,
|
|
374
|
+
});
|
|
375
|
+
console.log(output);
|
|
376
|
+
} catch (error) {
|
|
377
|
+
handleError(error);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
program
|
|
382
|
+
.command("close")
|
|
383
|
+
.description("Close current session")
|
|
384
|
+
.option("--all", "Close all sessions")
|
|
385
|
+
.action(async (options, command) => {
|
|
386
|
+
try {
|
|
387
|
+
sessionManager = sessionManager || new SessionManager();
|
|
388
|
+
const sessionName = options.all ? undefined : getSessionName(command.parent);
|
|
389
|
+
|
|
390
|
+
if (browserContext) {
|
|
391
|
+
await browserContext.close();
|
|
392
|
+
browserContext = null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const output = await sessionCommands.closeSession(sessionManager, sessionName, options.all);
|
|
396
|
+
console.log(output);
|
|
397
|
+
} catch (error) {
|
|
398
|
+
handleError(error);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Config commands
|
|
403
|
+
program
|
|
404
|
+
.command("config")
|
|
405
|
+
.description("Manage configuration")
|
|
406
|
+
.argument("[action]", "Action: list, get, set")
|
|
407
|
+
.argument("[key]", "Config key (for get/set)")
|
|
408
|
+
.argument("[value]", "Config value (for set)")
|
|
409
|
+
.action(async (action, key, value) => {
|
|
410
|
+
try {
|
|
411
|
+
if (!action || action === "list") {
|
|
412
|
+
const output = await configCommands.listConfig();
|
|
413
|
+
console.log(output);
|
|
414
|
+
} else if (action === "get") {
|
|
415
|
+
if (!key) {
|
|
416
|
+
throw new Error("Config key required for 'get' action");
|
|
417
|
+
}
|
|
418
|
+
const output = await configCommands.getConfig(key);
|
|
419
|
+
console.log(output);
|
|
420
|
+
} else if (action === "set") {
|
|
421
|
+
if (!key || !value) {
|
|
422
|
+
throw new Error("Config key and value required for 'set' action");
|
|
423
|
+
}
|
|
424
|
+
const output = await configCommands.setConfig(key, value);
|
|
425
|
+
console.log(output);
|
|
426
|
+
} else {
|
|
427
|
+
throw new Error(`Unknown config action: ${action}`);
|
|
428
|
+
}
|
|
429
|
+
} catch (error) {
|
|
430
|
+
handleError(error);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Version command
|
|
435
|
+
program
|
|
436
|
+
.command("version")
|
|
437
|
+
.description("Show version information")
|
|
438
|
+
.action(() => {
|
|
439
|
+
console.log("hyperagentbrowser v0.1.0");
|
|
440
|
+
console.log(`Bun v${Bun.version}`);
|
|
441
|
+
console.log("Patchright v1.55.1");
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Helper functions
|
|
445
|
+
async function withOperationIndicator<T>(
|
|
446
|
+
operation: string,
|
|
447
|
+
fn: () => Promise<T>
|
|
448
|
+
): Promise<T> {
|
|
449
|
+
try {
|
|
450
|
+
await browserContext?.showOperationIndicator(operation);
|
|
451
|
+
const result = await fn();
|
|
452
|
+
return result;
|
|
453
|
+
} finally {
|
|
454
|
+
await browserContext?.hideOperationIndicator();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
async function initSession(parentCommand: any) {
|
|
459
|
+
currentSessionName = getSessionName(parentCommand);
|
|
460
|
+
sessionManager = new SessionManager();
|
|
461
|
+
|
|
462
|
+
const channel = getChannel(parentCommand);
|
|
463
|
+
const session = await sessionManager.getOrCreate(currentSessionName, channel);
|
|
464
|
+
|
|
465
|
+
// Initialize reference store for this session
|
|
466
|
+
referenceStore = new ReferenceStore(session);
|
|
467
|
+
await referenceStore.load();
|
|
468
|
+
|
|
469
|
+
// Set the global reference store for actions
|
|
470
|
+
actionCommands.setReferenceStore(referenceStore);
|
|
471
|
+
|
|
472
|
+
browserContext = new BrowserContextManager(session);
|
|
473
|
+
await browserContext.getPage(getBrowserOptions(parentCommand));
|
|
474
|
+
|
|
475
|
+
// Update session with wsEndpoint and PID
|
|
476
|
+
const wsEndpoint = browserContext.getWsEndpoint();
|
|
477
|
+
const pid = browserContext.getPid();
|
|
478
|
+
if (wsEndpoint) {
|
|
479
|
+
await sessionManager.markRunning(currentSessionName, wsEndpoint, pid);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async function ensureConnected(parentCommand: any) {
|
|
484
|
+
if (!browserContext) {
|
|
485
|
+
await initSession(parentCommand);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
async function updateSessionInfo() {
|
|
490
|
+
if (!browserContext || !sessionManager) return;
|
|
491
|
+
|
|
492
|
+
const page = await browserContext.getPage();
|
|
493
|
+
const url = await page.url();
|
|
494
|
+
const title = await page.title();
|
|
495
|
+
|
|
496
|
+
await sessionManager.updatePageInfo(currentSessionName, url, title);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function getBrowserOptions(parentCommand: any) {
|
|
500
|
+
return {
|
|
501
|
+
headed: parentCommand.opts().headed,
|
|
502
|
+
timeout: getTimeout(parentCommand),
|
|
503
|
+
channel: getChannel(parentCommand),
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function getSessionName(parentCommand: any): string {
|
|
508
|
+
return parentCommand.opts().session || "default";
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function getChannel(parentCommand: any): "chrome" | "msedge" | "chromium" {
|
|
512
|
+
return parentCommand.opts().channel || "chrome";
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function getTimeout(parentCommand: any): number {
|
|
516
|
+
return Number.parseInt(parentCommand.opts().timeout || "30000");
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function handleError(error: any) {
|
|
520
|
+
if (error instanceof Error) {
|
|
521
|
+
console.error(formatError(error));
|
|
522
|
+
process.exit(getExitCode(error));
|
|
523
|
+
} else {
|
|
524
|
+
console.error("Error:", error);
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
program.parse();
|