gologin-agent-browser-cli 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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +220 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +352 -0
  5. package/dist/commands/check.d.ts +2 -0
  6. package/dist/commands/check.js +17 -0
  7. package/dist/commands/click.d.ts +2 -0
  8. package/dist/commands/click.js +17 -0
  9. package/dist/commands/close.d.ts +2 -0
  10. package/dist/commands/close.js +12 -0
  11. package/dist/commands/current.d.ts +2 -0
  12. package/dist/commands/current.js +9 -0
  13. package/dist/commands/dblclick.d.ts +2 -0
  14. package/dist/commands/dblclick.js +17 -0
  15. package/dist/commands/fill.d.ts +2 -0
  16. package/dist/commands/fill.js +18 -0
  17. package/dist/commands/find.d.ts +2 -0
  18. package/dist/commands/find.js +86 -0
  19. package/dist/commands/focus.d.ts +2 -0
  20. package/dist/commands/focus.js +17 -0
  21. package/dist/commands/get.d.ts +2 -0
  22. package/dist/commands/get.js +19 -0
  23. package/dist/commands/hover.d.ts +2 -0
  24. package/dist/commands/hover.js +17 -0
  25. package/dist/commands/open.d.ts +2 -0
  26. package/dist/commands/open.js +67 -0
  27. package/dist/commands/pdf.d.ts +2 -0
  28. package/dist/commands/pdf.js +18 -0
  29. package/dist/commands/press.d.ts +2 -0
  30. package/dist/commands/press.js +19 -0
  31. package/dist/commands/screenshot.d.ts +2 -0
  32. package/dist/commands/screenshot.js +20 -0
  33. package/dist/commands/scroll.d.ts +2 -0
  34. package/dist/commands/scroll.js +25 -0
  35. package/dist/commands/scrollIntoView.d.ts +2 -0
  36. package/dist/commands/scrollIntoView.js +17 -0
  37. package/dist/commands/select.d.ts +2 -0
  38. package/dist/commands/select.js +18 -0
  39. package/dist/commands/sessions.d.ts +2 -0
  40. package/dist/commands/sessions.js +15 -0
  41. package/dist/commands/shared.d.ts +3 -0
  42. package/dist/commands/shared.js +13 -0
  43. package/dist/commands/snapshot.d.ts +2 -0
  44. package/dist/commands/snapshot.js +16 -0
  45. package/dist/commands/type.d.ts +2 -0
  46. package/dist/commands/type.js +18 -0
  47. package/dist/commands/uncheck.d.ts +2 -0
  48. package/dist/commands/uncheck.js +17 -0
  49. package/dist/commands/upload.d.ts +2 -0
  50. package/dist/commands/upload.js +18 -0
  51. package/dist/commands/wait.d.ts +2 -0
  52. package/dist/commands/wait.js +41 -0
  53. package/dist/daemon/browser.d.ts +37 -0
  54. package/dist/daemon/browser.js +557 -0
  55. package/dist/daemon/refStore.d.ts +9 -0
  56. package/dist/daemon/refStore.js +26 -0
  57. package/dist/daemon/server.d.ts +1 -0
  58. package/dist/daemon/server.js +235 -0
  59. package/dist/daemon/sessionManager.d.ts +50 -0
  60. package/dist/daemon/sessionManager.js +512 -0
  61. package/dist/daemon/snapshot.d.ts +8 -0
  62. package/dist/daemon/snapshot.js +285 -0
  63. package/dist/lib/config.d.ts +3 -0
  64. package/dist/lib/config.js +58 -0
  65. package/dist/lib/errors.d.ts +12 -0
  66. package/dist/lib/errors.js +63 -0
  67. package/dist/lib/types.d.ts +301 -0
  68. package/dist/lib/types.js +2 -0
  69. package/dist/lib/utils.d.ts +27 -0
  70. package/dist/lib/utils.js +165 -0
  71. package/examples/agent-flow.sh +19 -0
  72. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GoLogin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # GoLogin Agent CLI
2
+
3
+ GoLogin Agent CLI is a cloud browser automation CLI built for AI agents. It turns GoLogin Cloud Browser into a persistent, scriptable runtime with compact page snapshots, ref-based interaction, session memory, and shell-friendly commands.
4
+
5
+ It is designed for agent loops that need to stay simple:
6
+
7
+ - open a live browser session
8
+ - read the page as a compact text snapshot
9
+ - act on stable refs like `@e3`
10
+ - keep working across multiple CLI calls through a local daemon
11
+ - save artifacts such as screenshots and PDFs when needed
12
+
13
+ Unlike local-browser automation tools, it runs on top of a cloud browser stack built around GoLogin profiles, proxies, fingerprinting, and anti-detect capabilities.
14
+
15
+ ## Why Cloud Browser
16
+
17
+ Local-browser automation is convenient, but it comes with hard limits for agent workflows that need to survive real-world websites:
18
+
19
+ - local browsers are easier to detect
20
+ - local runs usually do not carry profile-based fingerprinting
21
+ - local runs do not come with persistent cloud browser profiles
22
+ - local networking is limited unless you bolt on your own proxy layer
23
+ - local sessions are harder to standardize across agents and environments
24
+
25
+ GoLogin Agent CLI takes the opposite approach:
26
+
27
+ - cloud browser runtime instead of a local browser process
28
+ - GoLogin profiles as the session identity layer
29
+ - proxy-aware browser sessions
30
+ - fingerprint and anti-detect capabilities inherited from GoLogin
31
+ - a persistent daemon that keeps agent sessions alive across CLI calls
32
+
33
+ ## Architecture
34
+
35
+ The system has two parts:
36
+
37
+ - `gologin-agent-browser` CLI
38
+ - a persistent local daemon
39
+
40
+ The CLI parses commands, auto-starts the daemon when needed, and prints compact output for agents. The daemon owns live browser sessions, connects to GoLogin Cloud Browser through Playwright `connectOverCDP`, keeps the active page in memory, builds snapshots, resolves refs like `@e1`, and tracks session metadata such as proxy mode, idle timeout, and generated artifacts.
41
+
42
+ If you do not provide a profile id, the daemon creates a temporary GoLogin cloud profile through the GoLogin API, uses it to open the session, and attempts to delete it when the session is closed.
43
+
44
+ Transport is local only:
45
+
46
+ - Unix socket at `${TMPDIR:-/tmp}/gologin-agent-browser.sock` on Unix-like systems
47
+ - localhost HTTP on `127.0.0.1:${GOLOGIN_DAEMON_PORT:-44777}`
48
+
49
+ ## Installation
50
+
51
+ Node.js 18+ is required.
52
+
53
+ Install from npm:
54
+
55
+ ```bash
56
+ npm install -g gologin-agent-browser-cli
57
+ ```
58
+
59
+ Run it directly:
60
+
61
+ ```bash
62
+ gologin-agent-browser --help
63
+ ```
64
+
65
+ Or use it without a global install:
66
+
67
+ ```bash
68
+ npx gologin-agent-browser-cli --help
69
+ ```
70
+
71
+ Developer setup from source:
72
+
73
+ ```bash
74
+ git clone https://gitlab.com/easync/agent-browser.git
75
+ cd agent-browser
76
+ npm install
77
+ npm run build
78
+ ```
79
+
80
+ ## Required Environment
81
+
82
+ - `GOLOGIN_TOKEN` required for `open`
83
+ - `GOLOGIN_PROFILE_ID` optional default profile for `open`
84
+ - `GOLOGIN_DAEMON_PORT` optional, defaults to `44777`
85
+ - `GOLOGIN_CONNECT_BASE` optional, defaults to `https://cloudbrowser.gologin.com/connect`
86
+
87
+ Optional config file:
88
+
89
+ ```json
90
+ {
91
+ "token": "from-your-own-secret-store",
92
+ "defaultProfileId": "profile-id",
93
+ "daemonPort": 44777,
94
+ "connectBase": "https://cloudbrowser.gologin.com/connect"
95
+ }
96
+ ```
97
+
98
+ Save it as `~/.gologin-agent-browser/config.json`.
99
+
100
+ ## Quickstart
101
+
102
+ ```bash
103
+ export GOLOGIN_TOKEN=your_token
104
+
105
+ gologin-agent-browser open https://example.com
106
+ gologin-agent-browser snapshot -i
107
+ gologin-agent-browser current
108
+ gologin-agent-browser click @e3
109
+ gologin-agent-browser fill "input[name='email']" "test@example.com"
110
+ gologin-agent-browser scroll down 600
111
+ gologin-agent-browser get title
112
+ gologin-agent-browser pdf page.pdf
113
+ gologin-agent-browser screenshot page.png --annotate
114
+ gologin-agent-browser sessions
115
+ gologin-agent-browser close
116
+ ```
117
+
118
+ More examples:
119
+
120
+ ```bash
121
+ gologin-agent-browser open https://example.com --proxy-host 1.2.3.4 --proxy-port 8080 --proxy-mode http --idle-timeout-ms 300000
122
+ gologin-agent-browser open https://example.com --profile your-preconfigured-gologin-profile
123
+ gologin-agent-browser click "a[href*='iana']"
124
+ gologin-agent-browser type @e4 "hello world"
125
+ gologin-agent-browser focus "input[name='email']"
126
+ gologin-agent-browser press Enter
127
+ gologin-agent-browser select "select[name='plan']" pro
128
+ gologin-agent-browser check "input[name='terms']"
129
+ gologin-agent-browser uncheck "input[name='newsletter']"
130
+ gologin-agent-browser scrollintoview "#submit"
131
+ gologin-agent-browser find label "Email" fill "test@example.com"
132
+ gologin-agent-browser upload "input[type='file']" /absolute/path/to/avatar.png
133
+ gologin-agent-browser wait --text "Welcome"
134
+ ```
135
+
136
+ ## Commands
137
+
138
+ - `open <url> [--profile <profileId>] [--session <sessionId>] [--idle-timeout-ms <ms>]`
139
+ - `open <url> [--proxy-host <host> --proxy-port <port> --proxy-mode <http|socks4|socks5> --proxy-user <user> --proxy-pass <pass>]`
140
+ - `snapshot [--session <sessionId>] [--interactive]`
141
+ - `click <target> [--session <sessionId>]`
142
+ - `dblclick <target> [--session <sessionId>]`
143
+ - `focus <target> [--session <sessionId>]`
144
+ - `type <target> <text> [--session <sessionId>]`
145
+ - `fill <target> <text> [--session <sessionId>]`
146
+ - `hover <target> [--session <sessionId>]`
147
+ - `select <target> <value> [--session <sessionId>]`
148
+ - `check <target> [--session <sessionId>]`
149
+ - `uncheck <target> [--session <sessionId>]`
150
+ - `press <key> [target] [--session <sessionId>]`
151
+ - `scroll <up|down|left|right> [pixels] [--target <target>] [--session <sessionId>]`
152
+ - `scrollintoview <target> [--session <sessionId>]`
153
+ - `wait <target|ms> [--text <text>] [--url <pattern>] [--load <state>] [--session <sessionId>]`
154
+ - `get <text|value|html|title|url> [target] [--session <sessionId>]`
155
+ - `find <role|text|label|placeholder|first|last|nth> ...`
156
+ - `upload <target> <file...> [--session <sessionId>]`
157
+ - `pdf <path> [--session <sessionId>]`
158
+ - `screenshot <path> [--annotate] [--session <sessionId>]`
159
+ - `close [--session <sessionId>]`
160
+ - `sessions`
161
+ - `current`
162
+
163
+ ## Example Session Flow
164
+
165
+ `snapshot` produces compact output designed for agent consumption:
166
+
167
+ ```text
168
+ session=s1 url=https://example.com/
169
+ - heading "Example Domain" [ref=@e1]
170
+ - paragraph "This domain is for use in illustrative examples in documents." [ref=@e2]
171
+ - link "More information..." [ref=@e3]
172
+ - checkbox "Accept terms" [checked] [ref=@e4]
173
+ - select "Plan" [selected=Pro] [ref=@e5]
174
+ ```
175
+
176
+ Agents can then use those refs:
177
+
178
+ ```bash
179
+ gologin-agent-browser click @e3
180
+ gologin-agent-browser type @e4 "hello world"
181
+ gologin-agent-browser fill "input[name='email']" "test@example.com"
182
+ gologin-agent-browser find role button click --name "Submit"
183
+ gologin-agent-browser screenshot page.png --annotate
184
+ ```
185
+
186
+ Targets can be either snapshot refs like `@e4` or raw Playwright/CSS selectors. `find` adds semantic locator flows similar to agent-browser.
187
+
188
+ `open`, `current`, and `sessions` also expose session metadata in a shell-friendly form:
189
+
190
+ ```text
191
+ session=s1 url=https://example.com snapshot=fresh proxy=http:1.2.3.4:8080 idleTimeoutMs=300000 shot=/tmp/page.png pdf=/tmp/page.pdf
192
+ ```
193
+
194
+ When screenshots or PDFs are generated, `current` and `sessions` include the latest artifact paths as `shot=...` and `pdf=...`.
195
+
196
+ Supported aliases:
197
+
198
+ - `goto`, `navigate` -> `open`
199
+ - `key` -> `press`
200
+ - `scrollinto` -> `scrollintoview`
201
+ - `quit`, `exit` -> `close`
202
+
203
+ ## Current Scope
204
+
205
+ - Session persistence lasts as long as the local daemon is running. Restarting the daemon clears in-memory sessions and refs.
206
+ - Idle timeout is a local daemon policy. It does not change GoLogin account-level cloud limits.
207
+ - Snapshot and ref resolution are best-effort. Dynamic pages can invalidate refs after heavy DOM changes or navigation.
208
+ - Snapshot output is compact and accessibility-informed, but it is not a full accessibility tree dump.
209
+ - Annotated screenshots are based on the current snapshot/ref model, so labels are also best-effort on highly dynamic pages.
210
+ - The daemon keeps only the latest snapshot ref map for each session.
211
+ - Real browser sessions require a valid GoLogin Cloud Browser account and token. A profile id is optional.
212
+ - Token-only mode works by provisioning a temporary cloud profile through the GoLogin API before connecting to Cloud Browser.
213
+ - Proxy support is cloud-profile based. Temporary profiles can be created with a custom proxy definition, and existing GoLogin profiles can be reused with `--profile` if they already have a managed proxy attached.
214
+ - Local Orbita is intentionally out of scope. This project targets GoLogin Cloud Browser only.
215
+ - GoLogin cloud live-view URLs are not auto-fetched by default because the current endpoint can interfere with an active CDP session.
216
+ - Playwright is the automation layer on top of GoLogin Cloud Browser. The browser runtime itself does not expose built-in agent actions such as `click()` or `type()`.
217
+
218
+ ## Live Smoke Check
219
+
220
+ The project includes a smoke test path that only runs when `GOLOGIN_TOKEN` is present in the environment. If `GOLOGIN_PROFILE_ID` is also set, the smoke flow can reuse that profile; otherwise GoLogin can create a temporary session profile automatically. Secrets are never written into source files, tests, or examples.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const node_http_1 = __importDefault(require("node:http"));
8
+ const node_child_process_1 = require("node:child_process");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const check_1 = require("./commands/check");
12
+ const click_1 = require("./commands/click");
13
+ const close_1 = require("./commands/close");
14
+ const current_1 = require("./commands/current");
15
+ const dblclick_1 = require("./commands/dblclick");
16
+ const fill_1 = require("./commands/fill");
17
+ const find_1 = require("./commands/find");
18
+ const focus_1 = require("./commands/focus");
19
+ const get_1 = require("./commands/get");
20
+ const hover_1 = require("./commands/hover");
21
+ const open_1 = require("./commands/open");
22
+ const pdf_1 = require("./commands/pdf");
23
+ const press_1 = require("./commands/press");
24
+ const screenshot_1 = require("./commands/screenshot");
25
+ const scroll_1 = require("./commands/scroll");
26
+ const scrollIntoView_1 = require("./commands/scrollIntoView");
27
+ const sessions_1 = require("./commands/sessions");
28
+ const snapshot_1 = require("./commands/snapshot");
29
+ const select_1 = require("./commands/select");
30
+ const type_1 = require("./commands/type");
31
+ const uncheck_1 = require("./commands/uncheck");
32
+ const upload_1 = require("./commands/upload");
33
+ const wait_1 = require("./commands/wait");
34
+ const config_1 = require("./lib/config");
35
+ const errors_1 = require("./lib/errors");
36
+ const utils_1 = require("./lib/utils");
37
+ function printUsage() {
38
+ process.stderr.write([
39
+ "GoLogin Agent CLI",
40
+ "",
41
+ "Usage:",
42
+ " gologin-agent-browser <command> [args] [options]",
43
+ "",
44
+ "Commands:",
45
+ " open <url> [--profile <profileId>] [--session <sessionId>] [--idle-timeout-ms <ms>] [--proxy-host <host> --proxy-port <port> --proxy-mode <http|socks4|socks5>] (aliases: goto, navigate)",
46
+ " snapshot [--session <sessionId>] [--interactive|-i]",
47
+ " click <target> [--session <sessionId>]",
48
+ " dblclick <target> [--session <sessionId>]",
49
+ " focus <target> [--session <sessionId>]",
50
+ " type <target> <text> [--session <sessionId>]",
51
+ " fill <target> <text> [--session <sessionId>]",
52
+ " hover <target> [--session <sessionId>]",
53
+ " select <target> <value> [--session <sessionId>]",
54
+ " check <target> [--session <sessionId>]",
55
+ " uncheck <target> [--session <sessionId>]",
56
+ " press <key> [target] [--session <sessionId>] (alias: key)",
57
+ " scroll <up|down|left|right> [pixels] [--target <target>] [--session <sessionId>]",
58
+ " scrollintoview <target> [--session <sessionId>] (alias: scrollinto)",
59
+ " wait <target|ms> [--text <text>] [--url <pattern>] [--load <state>] [--session <sessionId>]",
60
+ " get <text|value|html|title|url> [target] [--session <sessionId>]",
61
+ " find <role|text|label|placeholder|first|last|nth> ... [--exact]",
62
+ " upload <target> <file...> [--session <sessionId>]",
63
+ " pdf <path> [--session <sessionId>]",
64
+ " screenshot <path> [--annotate] [--session <sessionId>]",
65
+ " close [--session <sessionId>] (aliases: quit, exit)",
66
+ " sessions",
67
+ " current",
68
+ "",
69
+ "Environment:",
70
+ " GOLOGIN_TOKEN",
71
+ " GOLOGIN_PROFILE_ID",
72
+ " GOLOGIN_DAEMON_PORT",
73
+ " GOLOGIN_CONNECT_BASE"
74
+ ].join("\n") + "\n");
75
+ }
76
+ function projectRootFromCli() {
77
+ return node_path_1.default.resolve(__dirname, "..");
78
+ }
79
+ function buildDaemonSpawnCommand(projectRoot) {
80
+ const distServerPath = node_path_1.default.join(projectRoot, "dist", "daemon", "server.js");
81
+ if (node_fs_1.default.existsSync(distServerPath)) {
82
+ return {
83
+ command: process.execPath,
84
+ args: [distServerPath]
85
+ };
86
+ }
87
+ const tsxCli = node_path_1.default.join(projectRoot, "node_modules", "tsx", "dist", "cli.mjs");
88
+ const srcServerPath = node_path_1.default.join(projectRoot, "src", "daemon", "server.ts");
89
+ if (node_fs_1.default.existsSync(tsxCli) && node_fs_1.default.existsSync(srcServerPath)) {
90
+ return {
91
+ command: process.execPath,
92
+ args: [tsxCli, srcServerPath]
93
+ };
94
+ }
95
+ throw new errors_1.AppError("DAEMON_UNREACHABLE", "Daemon entrypoint is missing. Run npm install and npm run build first.", 500);
96
+ }
97
+ function requestOverHttp(transport, method, requestPath, body) {
98
+ return new Promise((resolve, reject) => {
99
+ const payload = body === undefined ? undefined : Buffer.from(JSON.stringify(body));
100
+ const options = transport.kind === "socket"
101
+ ? {
102
+ socketPath: transport.socketPath,
103
+ path: requestPath,
104
+ method,
105
+ headers: payload
106
+ ? {
107
+ "content-type": "application/json",
108
+ "content-length": String(payload.length)
109
+ }
110
+ : undefined
111
+ }
112
+ : {
113
+ host: transport.host,
114
+ port: transport.port,
115
+ path: requestPath,
116
+ method,
117
+ headers: payload
118
+ ? {
119
+ "content-type": "application/json",
120
+ "content-length": String(payload.length)
121
+ }
122
+ : undefined
123
+ };
124
+ const request = node_http_1.default.request(options, (response) => {
125
+ const chunks = [];
126
+ response.on("data", (chunk) => chunks.push(chunk));
127
+ response.on("end", () => {
128
+ const raw = chunks.length > 0 ? Buffer.concat(chunks).toString("utf8") : "{}";
129
+ const parsed = raw.length > 0 ? JSON.parse(raw) : undefined;
130
+ if ((response.statusCode ?? 500) >= 400) {
131
+ if ((0, utils_1.isDaemonErrorResponse)(parsed)) {
132
+ reject((0, errors_1.fromDaemonError)(parsed));
133
+ return;
134
+ }
135
+ reject(new errors_1.AppError("INTERNAL_ERROR", `Daemon request failed with status ${response.statusCode}`, 500));
136
+ return;
137
+ }
138
+ resolve(parsed);
139
+ });
140
+ });
141
+ request.on("error", (error) => reject(error));
142
+ if (payload) {
143
+ request.write(payload);
144
+ }
145
+ request.end();
146
+ });
147
+ }
148
+ async function probeTransport(transport) {
149
+ try {
150
+ await requestOverHttp(transport, "GET", "/health");
151
+ return true;
152
+ }
153
+ catch {
154
+ return false;
155
+ }
156
+ }
157
+ async function waitForDaemon(transports, timeoutMs) {
158
+ const start = Date.now();
159
+ while (Date.now() - start < timeoutMs) {
160
+ for (const transport of transports) {
161
+ if (await probeTransport(transport)) {
162
+ return transport;
163
+ }
164
+ }
165
+ await new Promise((resolve) => setTimeout(resolve, 250));
166
+ }
167
+ return undefined;
168
+ }
169
+ async function ensureDaemon(config) {
170
+ const transports = [];
171
+ if (process.platform !== "win32") {
172
+ transports.push({
173
+ kind: "socket",
174
+ socketPath: config.socketPath
175
+ });
176
+ }
177
+ transports.push({
178
+ kind: "http",
179
+ host: config.daemonHost,
180
+ port: config.daemonPort
181
+ });
182
+ for (const transport of transports) {
183
+ if (await probeTransport(transport)) {
184
+ return transport;
185
+ }
186
+ }
187
+ const projectRoot = projectRootFromCli();
188
+ const command = buildDaemonSpawnCommand(projectRoot);
189
+ const child = (0, node_child_process_1.spawn)(command.command, command.args, {
190
+ cwd: projectRoot,
191
+ detached: true,
192
+ stdio: "ignore",
193
+ env: process.env
194
+ });
195
+ child.unref();
196
+ const resolved = await waitForDaemon(transports, 5_000);
197
+ if (!resolved) {
198
+ throw new errors_1.AppError("DAEMON_UNREACHABLE", "Local daemon did not start in time", 503);
199
+ }
200
+ return resolved;
201
+ }
202
+ function createDaemonClient(transport) {
203
+ return {
204
+ transport,
205
+ async request(method, requestPath, body) {
206
+ return (await requestOverHttp(transport, method, requestPath, body));
207
+ }
208
+ };
209
+ }
210
+ async function runCommand(command, context, args) {
211
+ switch (command) {
212
+ case "open":
213
+ await (0, open_1.runOpenCommand)(context, args);
214
+ return;
215
+ case "snapshot":
216
+ await (0, snapshot_1.runSnapshotCommand)(context, args);
217
+ return;
218
+ case "click":
219
+ await (0, click_1.runClickCommand)(context, args);
220
+ return;
221
+ case "dblclick":
222
+ await (0, dblclick_1.runDoubleClickCommand)(context, args);
223
+ return;
224
+ case "focus":
225
+ await (0, focus_1.runFocusCommand)(context, args);
226
+ return;
227
+ case "type":
228
+ await (0, type_1.runTypeCommand)(context, args);
229
+ return;
230
+ case "fill":
231
+ await (0, fill_1.runFillCommand)(context, args);
232
+ return;
233
+ case "hover":
234
+ await (0, hover_1.runHoverCommand)(context, args);
235
+ return;
236
+ case "select":
237
+ await (0, select_1.runSelectCommand)(context, args);
238
+ return;
239
+ case "check":
240
+ await (0, check_1.runCheckCommand)(context, args);
241
+ return;
242
+ case "uncheck":
243
+ await (0, uncheck_1.runUncheckCommand)(context, args);
244
+ return;
245
+ case "press":
246
+ await (0, press_1.runPressCommand)(context, args);
247
+ return;
248
+ case "scroll":
249
+ await (0, scroll_1.runScrollCommand)(context, args);
250
+ return;
251
+ case "scrollintoview":
252
+ await (0, scrollIntoView_1.runScrollIntoViewCommand)(context, args);
253
+ return;
254
+ case "wait":
255
+ await (0, wait_1.runWaitCommand)(context, args);
256
+ return;
257
+ case "get":
258
+ await (0, get_1.runGetCommand)(context, args);
259
+ return;
260
+ case "find":
261
+ await (0, find_1.runFindCommand)(context, args);
262
+ return;
263
+ case "upload":
264
+ await (0, upload_1.runUploadCommand)(context, args);
265
+ return;
266
+ case "pdf":
267
+ await (0, pdf_1.runPdfCommand)(context, args);
268
+ return;
269
+ case "screenshot":
270
+ await (0, screenshot_1.runScreenshotCommand)(context, args);
271
+ return;
272
+ case "close":
273
+ await (0, close_1.runCloseCommand)(context, args);
274
+ return;
275
+ case "sessions":
276
+ await (0, sessions_1.runSessionsCommand)(context, args);
277
+ return;
278
+ case "current":
279
+ await (0, current_1.runCurrentCommand)(context, args);
280
+ return;
281
+ }
282
+ }
283
+ function normalizeCommand(commandArg) {
284
+ const aliases = {
285
+ goto: "open",
286
+ navigate: "open",
287
+ dblclick: "dblclick",
288
+ key: "press",
289
+ scrollinto: "scrollintoview",
290
+ quit: "close",
291
+ exit: "close"
292
+ };
293
+ if (aliases[commandArg]) {
294
+ return aliases[commandArg];
295
+ }
296
+ const directCommands = new Set([
297
+ "open",
298
+ "snapshot",
299
+ "click",
300
+ "dblclick",
301
+ "focus",
302
+ "type",
303
+ "fill",
304
+ "hover",
305
+ "select",
306
+ "check",
307
+ "uncheck",
308
+ "press",
309
+ "scroll",
310
+ "scrollintoview",
311
+ "wait",
312
+ "get",
313
+ "find",
314
+ "upload",
315
+ "pdf",
316
+ "screenshot",
317
+ "close",
318
+ "sessions",
319
+ "current"
320
+ ]);
321
+ return directCommands.has(commandArg) ? commandArg : undefined;
322
+ }
323
+ async function main() {
324
+ const argv = process.argv.slice(2);
325
+ const commandArg = argv[0];
326
+ if (!commandArg || commandArg === "--help" || commandArg === "-h") {
327
+ printUsage();
328
+ process.exit(commandArg ? 0 : 1);
329
+ }
330
+ const command = normalizeCommand(commandArg);
331
+ if (!command) {
332
+ throw new errors_1.AppError("BAD_REQUEST", `Unknown command: ${commandArg}`, 400);
333
+ }
334
+ const config = (0, config_1.loadConfig)();
335
+ const transport = await ensureDaemon(config);
336
+ const client = createDaemonClient(transport);
337
+ const health = await client.request("GET", "/health");
338
+ if (!health.ok) {
339
+ throw new errors_1.AppError("DAEMON_UNREACHABLE", "Daemon health probe failed", 503);
340
+ }
341
+ const context = {
342
+ client,
343
+ stdout: process.stdout,
344
+ stderr: process.stderr,
345
+ cwd: process.cwd()
346
+ };
347
+ await runCommand(command, context, argv.slice(1));
348
+ }
349
+ main().catch((error) => {
350
+ process.stderr.write(`${(0, errors_1.formatErrorLine)(error)}\n`);
351
+ process.exit(error instanceof errors_1.AppError ? 1 : 1);
352
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandContext } from "../lib/types";
2
+ export declare function runCheckCommand(context: CommandContext, argv: string[]): Promise<void>;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCheckCommand = runCheckCommand;
4
+ const errors_1 = require("../lib/errors");
5
+ const utils_1 = require("../lib/utils");
6
+ const shared_1 = require("./shared");
7
+ async function runCheckCommand(context, argv) {
8
+ const parsed = (0, utils_1.parseArgs)(argv);
9
+ const target = parsed.positional[0];
10
+ const sessionId = (0, utils_1.getFlagString)(parsed, "session");
11
+ if (!target) {
12
+ throw new errors_1.AppError("BAD_REQUEST", "Usage: gologin-agent-browser check <target> [--session <sessionId>]", 400);
13
+ }
14
+ const resolvedSessionId = await (0, shared_1.resolveSessionId)(context, sessionId);
15
+ const response = await context.client.request("POST", `/sessions/${resolvedSessionId}/check`, { target });
16
+ (0, shared_1.writeActionResult)(context, "checked", target, response);
17
+ }
@@ -0,0 +1,2 @@
1
+ import type { CommandContext } from "../lib/types";
2
+ export declare function runClickCommand(context: CommandContext, argv: string[]): Promise<void>;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runClickCommand = runClickCommand;
4
+ const errors_1 = require("../lib/errors");
5
+ const utils_1 = require("../lib/utils");
6
+ const shared_1 = require("./shared");
7
+ async function runClickCommand(context, argv) {
8
+ const parsed = (0, utils_1.parseArgs)(argv);
9
+ const target = parsed.positional[0];
10
+ const sessionId = (0, utils_1.getFlagString)(parsed, "session");
11
+ if (!target) {
12
+ throw new errors_1.AppError("BAD_REQUEST", "Usage: gologin-agent-browser click <target> [--session <sessionId>]", 400);
13
+ }
14
+ const resolvedSessionId = await (0, shared_1.resolveSessionId)(context, sessionId);
15
+ const response = await context.client.request("POST", `/sessions/${resolvedSessionId}/click`, { target });
16
+ (0, shared_1.writeActionResult)(context, "clicked", target, response);
17
+ }
@@ -0,0 +1,2 @@
1
+ import type { CommandContext } from "../lib/types";
2
+ export declare function runCloseCommand(context: CommandContext, argv: string[]): Promise<void>;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCloseCommand = runCloseCommand;
4
+ const utils_1 = require("../lib/utils");
5
+ async function runCloseCommand(context, argv) {
6
+ const parsed = (0, utils_1.parseArgs)(argv);
7
+ const sessionId = (0, utils_1.getFlagString)(parsed, "session");
8
+ const resolvedSessionId = sessionId ??
9
+ (await context.client.request("GET", "/sessions/current")).sessionId;
10
+ const response = await context.client.request("POST", `/sessions/${resolvedSessionId}/close`);
11
+ context.stdout.write(`closed session=${response.sessionId}\n`);
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { CommandContext } from "../lib/types";
2
+ export declare function runCurrentCommand(context: CommandContext, argv: string[]): Promise<void>;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCurrentCommand = runCurrentCommand;
4
+ const utils_1 = require("../lib/utils");
5
+ async function runCurrentCommand(context, argv) {
6
+ (0, utils_1.parseArgs)(argv);
7
+ const response = await context.client.request("GET", "/sessions/current");
8
+ context.stdout.write(`${(0, utils_1.formatCurrentLine)(response)}\n`);
9
+ }
@@ -0,0 +1,2 @@
1
+ import type { CommandContext } from "../lib/types";
2
+ export declare function runDoubleClickCommand(context: CommandContext, argv: string[]): Promise<void>;