glidercli 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,187 +1,275 @@
1
1
  <div align="center">
2
2
 
3
- <img src="assets/icons/glider-blue-squircle.webp" alt="glider" width="80" height="80" />
4
- <img src="assets/icons/chrome.webp" alt="chrome" width="80" height="80" />
5
- <img src="assets/icons/claude.webp" alt="claude" width="80" height="80" />
6
- <img src="assets/icons/ralph-wiggum.webp" alt="ralph" width="80" height="80" />
3
+ <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/glider.webp" alt="glider" width="80" height="80" />
4
+ <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chrome.webp" alt="chrome" width="80" height="80" />
5
+ <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/claude.webp" alt="claude" width="80" height="80" />
6
+ <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/ralph-wiggum.webp" alt="ralph" width="80" height="80" />
7
7
 
8
- <h1 align="center">glidercli</h1>
9
- <p align="center"><i><b>Browser automation CLI with autonomous loop execution.</b></i></p>
8
+ <h1 align="center">glider CLI</h1>
9
+ <p align="center"><i><b>Browser automation CLI with autonomous loop execution</b></i></p>
10
10
 
11
11
  [![Github][github]][github-url]
12
12
  [![npm][npm]][npm-url]
13
-
14
13
  </div>
15
14
 
16
15
  <br/>
17
16
 
18
- ## ToC
17
+ ## About
19
18
 
20
- <ol>
21
- <a href="#about">About</a><br/>
22
- <a href="#install">Install</a><br/>
23
- <a href="#usage">Usage</a><br/>
24
- <a href="#the-loop">The loop</a><br/>
25
- <a href="#task-files">Task files</a><br/>
26
- <a href="#commands">Commands</a><br/>
27
- <a href="#roadmap">Roadmap</a><br/>
28
- <a href="#tools-used">Tools</a><br/>
29
- <a href="#contact">Contact</a>
30
- </ol>
19
+ | | |
20
+ |---|---|
21
+ | **What** | Control a **Chromium-based** browser from the terminal via CDP, run YAML tasks, and loop until done (Ralph Wiggum pattern) |
22
+ | **CDP** | Chrome DevTools Protocol via relay + browser extension |
23
+ | **Tasks** | Declarative steps: `goto`, `click`, `explore`, `eval`, `screenshot` |
24
+ | **Loops** | Run until completion marker or max iterations / timeout |
25
+ | **Safety** | Max iterations, timeout, backoff |
31
26
 
32
- <br/>
27
+ ---
33
28
 
34
- ## About
29
+ ## Install
35
30
 
36
- Control Chrome from terminal. Run YAML tasks. Loop until complete (Ralph Wiggum pattern).
31
+ | Step | Action |
32
+ |------|--------|
33
+ | **1. CLI** | `npm i -g glidercli` |
34
+ | **2. Extension** | [Install Glider from Chrome Web Store](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj) in the same browser/profile you will automate (required, bridges relay ↔ tab) |
35
+ | **3. Daemon** | `glider install` then `glider connect` |
36
+ | **4. Browser (required setup)** | Configure supported browser/profile + extension in the **Browsers** section below. |
37
37
 
38
- - **CDP-based** - Direct Chrome DevTools Protocol (CDP) control
39
- - **YAML tasks** - Define automation steps declaratively
40
- - **Autonomous loops** - Run until completion marker found
41
- - **Safety guards** - Max iterations, timeout, exponential backoff
42
38
 
43
- ## Install
39
+ ## Requirements
44
40
 
45
- **One-liner:**
46
- ```bash
47
- npm i -g glidercli && open "https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj"
48
- ```
41
+ | Requirement | Minimum |
42
+ |-------------|---------|
43
+ | Node | 18+ |
44
+ | Browser | Chromium-based (Chrome, Arc, Edge, Brave, Opera, Vivaldi) with the Glider extension installed/enabled in that browser profile. No Firefox/Safari/DuckDuckGo |
49
45
 
50
- **Then:**
51
- ```bash
52
- glider install # start daemon (runs forever, auto-restarts)
53
- glider connect # connect to Chrome
54
- ```
46
+ ---
55
47
 
56
- **Update anytime:**
57
- ```bash
58
- glider update # pulls latest from npm
48
+ ## Browsers
49
+
50
+ | | |
51
+ |---|---|
52
+ | **How it works** | Chrome extension → WebSocket relay → CDP. Browser must support that extension (Chromium-based). |
53
+
54
+ ### Browser support
55
+
56
+ Icons: `https://raw.githubusercontent.com/vdutts7/squircle/main/webp/{slug}.webp` ([squircle](https://github.com/vdutts7/squircle)).
57
+
58
+ **Extension:** Install [Glider](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj) from the Chrome Web Store in each browser/profile you plan to automate
59
+
60
+ | | Browser | Config |
61
+ |:---:|--------|--------|
62
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chrome.webp" width="16" alt=""> | Google Chrome | Default for `glider connect`. |
63
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/arc.webp" width="16" alt=""> | Arc | [browser.json](config/browser.json.example) (`{ "use": "arc" }`) |
64
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/microsoft/microsoft-edge.webp" width="16" alt=""> | Microsoft Edge | n/a |
65
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/brave.webp" width="16" alt=""> | Brave | n/a |
66
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/opera-gx.webp" width="16" alt=""> | Opera | n/a |
67
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/vivaldi.webp" width="16" alt=""> | Vivaldi | n/a |
68
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chromium.webp" width="16" alt=""> | Other Chromium | Must support installing extensions from the Chrome Web Store. |
69
+
70
+ ### Future
71
+
72
+ - not supported today
73
+ - Glider needs a **Chromium-based** browser that can install the extension from the **Chrome Web Store**
74
+ - no timeline implied- listed for clarity
75
+
76
+
77
+ | | Browser | Notes |
78
+ |:---:|--------|--------|
79
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/firefox.webp" width="16" alt=""> | Firefox | **Gecko** (Firefox engine). Not Chromium, Glider uses a Chrome Web Store extension + CDP |
80
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/firefox-focus.webp" width="16" alt=""> | Firefox Focus | Gecko- same constraints as Firefox |
81
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/firefox.webp" width="16" alt=""> | Firefox Klar | Gecko (Focus branding in some regions)- same constraints as Firefox |
82
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/librewolf.webp" width="16" alt=""> | LibreWolf | Gecko- same constraints as Firefox |
83
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/waterfox.webp" width="16" alt=""> | Waterfox | Gecko- same constraints as Firefox |
84
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/zen.webp" width="16" alt=""> | Zen | Gecko- same constraints as Firefox |
85
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/floorp.webp" width="16" alt=""> | Floorp | Gecko- same constraints as Firefox |
86
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/tor-browser.webp" width="16" alt=""> | Tor Browser | Gecko- same constraints as Firefox |
87
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/mullvad-browser.webp" width="16" alt=""> | Mullvad Browser | Gecko- same constraints as Firefox |
88
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/icecat.webp" width="16" alt=""> | IceCat | Gecko- same constraints as Firefox |
89
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/safari.webp" width="16" alt=""> | Safari | WebKit (Apple desktop). Not Chromium |
90
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/orion.webp" width="16" alt=""> | Orion | WebKit-based desktop browser. Not Chromium |
91
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chatgpt-atlas.webp" width="16" alt=""> | ChatGPT Atlas | AI-first browser, not in Glider’s supported Chromium + CWS model today |
92
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/perplexity-comet.webp" width="16" alt=""> | Perplexity Comet | AI-first browser, not in Glider’s supported Chromium + CWS model today |
93
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/bromite.webp" width="16" alt=""> | Bromite | Chromium-derived, no practical Chrome Web Store path for Glider |
94
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chromium.webp" width="16" alt=""> | Chromite | Chromium-derived, no practical Chrome Web Store path for Glider |
95
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/grapheneos.webp" width="16" alt=""> | Vanadium | Chromium-derived (GrapheneOS), no practical Chrome Web Store path for Glider |
96
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/duckduckgo.webp" width="16" alt=""> | DuckDuckGo | No practical Chrome Web Store extension install path for Glider |
97
+
98
+ ### Configuring the browser
99
+
100
+ **Priority (highest first):** config file -> default `Google Chrome`
101
+
102
+ #### Config file: `$HOME/.glider/config/browser.json`
103
+
104
+ Use a **registry key** or explicit name/path in the file
105
+
106
+ **Option A- Registry key (recommended):**
107
+
108
+ Set browser by key from the browsers registry. Run `glider use <key>` to write this.
109
+
110
+ ```json
111
+ {
112
+ "use": "arc"
113
+ }
59
114
  ```
60
115
 
61
- ### Requirements
116
+ Registry is loaded from (first found): `$HOME/.cursor/registry/browsers.json`, `$HOME/.glider/config/browsers-registry.json`. Keys are predefined (e.g. `arc`, `brave`, `chrome`, `edge`, `opera`, `vivaldi`, `chromium`). Edit the registry to add or change paths
62
117
 
63
- 1. **Node 18+**
118
+ **Option B- Explicit name/path:**
64
119
 
65
- 2. **Glider Chrome extension** - [Install from Chrome Web Store](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj)
120
+ | Field | Required | Description |
121
+ |-------|:--------:|-------------|
122
+ | `name` | Yes* | App name for `open -a` / AppleScript. Must match system (e.g. `Arc`, `Google Chrome`). |
123
+ | `path` | No | If set, use `open "<path>"` instead of `open -a "<name>"`. For non-default install location. |
124
+ | `processName` | No | For `pgrep -x`. Defaults to `name`. |
66
125
 
67
- ## Usage
126
+ \* Omit `name` when using `use` (registry key).
68
127
 
69
- ```bash
70
- glider connect # connect to browser
71
- glider status # check connection
72
- glider goto "https://x.com" # navigate
73
- glider eval "document.title" # run JS
74
- glider run task.yaml # execute task file
75
- glider loop task.yaml -n 50 # autonomous loop
128
+ **Example:**
129
+
130
+ ```json
131
+ {
132
+ "name": "Arc",
133
+ "path": "/Applications/Arc.app",
134
+ "processName": "Arc"
135
+ }
76
136
  ```
77
137
 
78
- ### Daemon
138
+ **By browser:**
79
139
 
80
- The daemon keeps the relay server running 24/7. Auto-restarts on crash.
140
+ | Browser | `name` | `path` (optional) | `processName` (optional) |
141
+ |---------|--------|-------------------|---------------------------|
142
+ | Arc | `Arc` | `/Applications/Arc.app` | `Arc` |
143
+ | Edge | `Microsoft Edge` | n/a | `Microsoft Edge` |
144
+ | Chrome (custom) | `Google Chrome` | `/Users/me/Applications/Google Chrome.app` | `Google Chrome` |
81
145
 
82
- ```bash
83
- glider install # install daemon (runs at login)
84
- glider uninstall # remove daemon
146
+ Check app name in Finder/Spotlight, process name: `ps aux | grep -i <name>`
147
+
148
+ ### Browser registry (keymap)
149
+
150
+ A single registry file can define all Chromium browsers, Glider picks one by key
151
+
152
+ **Registry location (first found):**
153
+
154
+ - `$HOME/.cursor/registry/browsers.json`
155
+ - `$HOME/.glider/config/browsers-registry.json`
156
+
157
+ **Registry format:**
158
+
159
+ ```json
160
+ {
161
+ "version": "1.0",
162
+ "registry": {
163
+ "arc": { "name": "Arc", "path": "/Applications/Arc.app", "processName": "Arc" },
164
+ "brave": { "name": "Brave Browser", "path": "/Applications/Brave Browser.app", "processName": "Brave Browser" },
165
+ "chrome": { "name": "Google Chrome", "path": "/Applications/Google Chrome.app", "processName": "Google Chrome" },
166
+ "edge": { "name": "Microsoft Edge", "path": "/Applications/Microsoft Edge.app", "processName": "Microsoft Edge" }
167
+ }
168
+ }
85
169
  ```
86
170
 
87
- Logs: `~/.glider/daemon.log`
171
+ **Commands:**
172
+
173
+ | Command | Effect |
174
+ |---------|--------|
175
+ | `glider use arc` | Set `$HOME/.glider/config/browser.json` to `{ "use": "arc" }` (resolved from registry). |
176
+ | `glider use brave` | Switch to Brave. |
177
+ | `glider use` | Show current key and list of registry keys. |
178
+ | `glider browser` | Show resolved name, path, processName (and `use` key if set). |
179
+
180
+ Add or edit entries in the registry to match your machine (e.g. custom install paths). Keys are stable, point Glider at one by name.
181
+
182
+ ### Platform
183
+
184
+ | Platform | Behavior |
185
+ |----------|----------|
186
+ | macOS | `open -a "<name>"` or `open "<path>"`, AppleScript for tab/window. `name` = exact app name |
187
+ | Linux / Windows | Not fully implemented. Future: `path` may be executable. |
88
188
 
89
- ## The loop
189
+ ### Browser summary
90
190
 
91
- The `loop` (or `ralph`) command runs your task repeatedly until:
92
- - Completion marker found (`LOOP_COMPLETE` or `DONE`)
93
- - Max iterations reached
94
- - Timeout hit
191
+ | Topic | Detail |
192
+ |-------|--------|
193
+ | Supported | Chromium-based + Chrome Web Store extension (see table above). |
194
+ | Not supported | See **Future** in this README. |
195
+ | Configure | `$HOME/.glider/config/browser.json` (use key or name/path). Registry: `$HOME/.cursor/registry/browsers.json` or `$HOME/.glider/config/browsers-registry.json` |
196
+ | Switch | `glider use <key>` (e.g. `glider use arc`, `glider use brave`). |
197
+ | Path | Optional, use when app is not in default location |
198
+
199
+ ---
200
+
201
+ ## Usage
95
202
 
96
203
  ```bash
97
- glider loop scrape-feed.yaml -n 100 -t 3600
98
- glider ralph task.yaml # same thing
204
+ glider connect
205
+ glider status
206
+ glider goto "https://reddit.com"
207
+ glider eval "document.title"
208
+ glider run task.yaml
209
+ glider loop task.yaml -n 50
99
210
  ```
100
211
 
101
- Safety: max iterations, timeout, exponential backoff on errors, state persistence.
212
+ | Daemon | Logs |
213
+ |--------|------|
214
+ | `glider install` / `glider uninstall` | `~/.glider/daemon.log` |
215
+
216
+ ---
102
217
 
103
218
  ## Task files
104
219
 
105
220
  ```yaml
106
- name: "Get timeline"
221
+ name: "Reddit"
107
222
  steps:
108
- - goto: "https://x.com/home"
109
- - wait: 3
110
- - eval: "document.querySelectorAll('article').length"
111
- - screenshot: "/tmp/timeline.png"
223
+ - goto: "https://reddit.com"
224
+ - wait: 2
225
+ - eval: "document.title"
226
+ - screenshot: "/tmp/out.png"
112
227
  ```
113
228
 
229
+ ---
230
+
114
231
  ## Commands
115
232
 
116
- ### Setup
117
- | Command | What |
118
- |---------|------|
119
- | `glider install` | Install daemon (runs at login) |
233
+ | Command | Description |
234
+ |---------|-------------|
235
+ | `glider install` | Install daemon (relay at login) |
120
236
  | `glider uninstall` | Remove daemon |
121
- | `glider update` | Update to latest version |
122
237
  | `glider connect` | Connect to browser |
123
- | `glider status` | Server/extension/tab status |
124
- | `glider test` | Run diagnostics |
125
-
126
- ### Navigation
127
- | Command | What |
128
- |---------|------|
238
+ | `glider status` | Server / extension / tabs |
239
+ | `glider browser` | Show browser config (name, path) |
129
240
  | `glider goto <url>` | Navigate |
130
- | `glider eval <js>` | Execute JavaScript |
241
+ | `glider eval <js>` | Run JS in page |
131
242
  | `glider click <sel>` | Click element |
132
243
  | `glider type <sel> <text>` | Type into input |
133
- | `glider screenshot` | Capture page |
134
- | `glider html <sel>` | Get element HTML |
135
- | `glider title` | Get page title |
136
- | `glider text` | Get page text |
137
-
138
- ### Multi-tab
139
- | Command | What |
140
- |---------|------|
141
- | `glider fetch <url>` | Fetch URL with browser session (authenticated) |
142
- | `glider spawn <urls...>` | Open multiple tabs |
143
- | `glider extract [opts]` | Extract content from all connected tabs |
144
- | `glider explore <url>` | Crawl site, capture links/network |
145
-
146
- ### Automation
147
- | Command | What |
148
- |---------|------|
244
+ | `glider screenshot [path]` | Capture page |
149
245
  | `glider run <file>` | Run YAML task |
150
- | `glider loop <file>` | Autonomous loop |
151
- | `glider ralph <file>` | Alias for loop |
246
+ | `glider loop <file> [-n N]` | Loop until done or limit |
247
+
248
+ Full list: `glider --help`
249
+
250
+ ---
251
+
252
+ ## Docs
253
+
254
+ | Doc | Contents |
255
+ |-----|----------|
256
+ | This README | Install, usage, commands, full browser support/config |
257
+ | [config/browser.json.example](config/browser.json.example) | Example browser config |
258
+
259
+ ---
152
260
 
153
261
  ## Roadmap
154
262
 
155
- - [x] CDP-based browser control via relay
156
- - [x] YAML task file execution
157
- - [x] Ralph Wiggum autonomous loop pattern
158
- - [x] Daemon mode (auto-start, auto-restart)
159
- - [x] macOS notifications
160
- - [x] Multi-tab orchestration (spawn, extract)
161
- - [x] Authenticated fetch via browser session
162
- - [x] Site exploration/crawling
163
- - [x] Chrome Web Store extension publish
164
- - [ ] Linux support
165
- - [ ] Windows support
166
- - [ ] Headless mode
167
- - [ ] Task chaining (output of one -> input of next)
168
- - [ ] Built-in scraping templates
169
- - [ ] Session recording/playback
170
- - [ ] AI-assisted task generation
171
- - [ ] Web dashboard for monitoring loops
172
-
173
- ## Tools
174
-
175
- [![Claude Code][claudecode-badge]][claudecode-url]
176
- [![Claude][claude-badge]][claude-url]
177
- [![Node.js][nodejs-badge]][nodejs-url]
178
- [![Chrome DevTools Protocol][cdp-badge]][cdp-url]
263
+ | Status | Area |
264
+ |--------|------|
265
+ | Done | CDP relay + extension, YAML tasks, loop, daemon, multi-tab |
266
+ | Todo | Linux / Windows, headless, task chaining, scraping templates |
179
267
 
180
- ## Contact
268
+ ---
181
269
 
270
+ ## Contact
182
271
 
183
- <a href="https://vd7.io"><img src="https://img.shields.io/badge/website-000000?style=for-the-badge&logo=data:image/webp;base64,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&logoColor=white" alt="website" /></a>
184
- <a href="https://x.com/vdutts7"><img src="https://img.shields.io/badge/vdutts7-000000?style=for-the-badge&logo=X&logoColor=white" alt="Twitter" /></a>
272
+ <a href="https://vd7.io"><img src="https://res.cloudinary.com/ddyc1es5v/image/upload/v1773910810/readme-badges/readme-badge-vd7.png" alt="vd7.io" height="40" /></a> &nbsp; <a href="https://x.com/vdutts7"><img src="https://res.cloudinary.com/ddyc1es5v/image/upload/v1773910817/readme-badges/readme-badge-x.png" alt="/vdutts7" height="40" /></a>
185
273
 
186
274
 
187
275
  <!-- BADGES -->
@@ -189,15 +277,3 @@ steps:
189
277
  [github-url]: https://github.com/vdutts7/glidercli
190
278
  [npm]: https://img.shields.io/badge/npm%20i%20--g%20glidercli-CB3837?style=for-the-badge&logo=npm
191
279
  [npm-url]: https://www.npmjs.com/package/glidercli
192
- [claudecode-badge]: https://img.shields.io/badge/Claude_Code-D97757?style=for-the-badge&logo=anthropic&logoColor=white
193
- [claudecode-url]: https://claude.ai/code
194
- [claude-badge]: https://img.shields.io/badge/Claude-D97757?style=for-the-badge&logo=anthropic&logoColor=white
195
- [claude-url]: https://claude.ai
196
- [nodejs-badge]: https://img.shields.io/badge/Node.js-339933?style=for-the-badge&logo=nodedotjs&logoColor=white
197
- [nodejs-url]: https://nodejs.org
198
- [cdp-badge]: https://img.shields.io/badge/Chrome_DevTools_Protocol-4285F4?style=for-the-badge&logo=googlechrome&logoColor=white
199
- [cdp-url]: https://chromedevtools.github.io/devtools-protocol/
200
- [email]: https://img.shields.io/badge/Email-000000?style=for-the-badge&logo=Gmail&logoColor=white
201
- [email-url]: mailto:me@vd7.io
202
- [twitter]: https://img.shields.io/badge/Twitter-000000?style=for-the-badge&logo=Twitter&logoColor=white
203
- [twitter-url]: https://x.com/vdutts7
package/bin/glider.js CHANGED
@@ -50,11 +50,10 @@ if (fs.existsSync(REGISTRY_FILE)) {
50
50
  // Direct CDP module
51
51
  const { DirectCDP, checkChrome } = require(path.join(LIB_DIR, 'cdp-direct.js'));
52
52
 
53
- // Domain extensions - load from ~/.glider/config/domains.json (primary) or legacy paths
53
+ // Domain extensions - load from ~/.glider/config/domains.json
54
54
  const DOMAIN_CONFIG_PATHS = [
55
55
  path.join(os.homedir(), '.glider', 'config', 'domains.json'),
56
56
  path.join(os.homedir(), '.glider', 'domains.json'),
57
- path.join(os.homedir(), '.cursor', 'glider', 'domains.json'), // legacy
58
57
  ];
59
58
  let DOMAINS = {};
60
59
  for (const cfgPath of DOMAIN_CONFIG_PATHS) {
@@ -66,6 +65,55 @@ for (const cfgPath of DOMAIN_CONFIG_PATHS) {
66
65
  }
67
66
  }
68
67
 
68
+ // Browser config - which browser to launch/use (must be Chromium-based, see docs/BROWSERS.md)
69
+ const BROWSER_CONFIG_PATHS = [
70
+ path.join(os.homedir(), '.glider', 'config', 'browser.json'),
71
+ path.join(os.homedir(), '.glider', 'browser.json'),
72
+ ];
73
+ let BROWSER_CONFIG = {};
74
+ for (const cfgPath of BROWSER_CONFIG_PATHS) {
75
+ if (fs.existsSync(cfgPath)) {
76
+ try {
77
+ BROWSER_CONFIG = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
78
+ break;
79
+ } catch (e) { /* ignore parse errors */ }
80
+ }
81
+ }
82
+
83
+ // Browsers registry - key → { name, path, processName }. Used when browser.json has "use": "<key>"
84
+ const BROWSERS_REGISTRY_PATHS = [
85
+ path.join(os.homedir(), '.cursor', 'registry', 'browsers.json'),
86
+ path.join(os.homedir(), '.glider', 'config', 'browsers-registry.json'),
87
+ ].filter(Boolean);
88
+ let BROWSERS_REGISTRY = {};
89
+ for (const regPath of BROWSERS_REGISTRY_PATHS) {
90
+ if (regPath && fs.existsSync(regPath)) {
91
+ try {
92
+ const data = JSON.parse(fs.readFileSync(regPath, 'utf8'));
93
+ BROWSERS_REGISTRY = data.registry || data;
94
+ break;
95
+ } catch (e) { /* ignore */ }
96
+ }
97
+ }
98
+
99
+ function getBrowserConfig() {
100
+ let name = BROWSER_CONFIG.name || null;
101
+ let pathOrNull = BROWSER_CONFIG.path || null;
102
+ let processName = BROWSER_CONFIG.processName || null;
103
+
104
+ // Key-based lookup: browser.json has { "use": "arc" } → resolve from registry
105
+ if (!name && BROWSER_CONFIG.use && BROWSERS_REGISTRY[BROWSER_CONFIG.use]) {
106
+ const entry = BROWSERS_REGISTRY[BROWSER_CONFIG.use];
107
+ name = entry.name;
108
+ pathOrNull = entry.path != null ? entry.path : null;
109
+ processName = entry.processName || entry.name;
110
+ }
111
+
112
+ name = name || 'Google Chrome';
113
+ processName = processName || name;
114
+ return { name, path: pathOrNull, processName };
115
+ }
116
+
69
117
  // Colors - matching the deep blue gradient logo
70
118
  const RED = '\x1b[31m';
71
119
  const GREEN = '\x1b[32m';
@@ -242,7 +290,7 @@ async function ensureConnected() {
242
290
 
243
291
  if (!await checkExtension()) {
244
292
  log.fail('Extension not connected - make sure Glider extension is installed');
245
- log.info('Install from: chrome://extensions Load unpacked → ~/glider-crx/glider/');
293
+ log.info('Install extension from Chrome Web Store: https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj');
246
294
  return false;
247
295
  }
248
296
 
@@ -621,7 +669,7 @@ async function cmdUninstallDaemon() {
621
669
  }
622
670
 
623
671
  async function cmdConnect() {
624
- // Bulletproof connect: relay + Chrome + trigger attach via HTTP
672
+ // Bulletproof connect: relay + browser + trigger attach via HTTP
625
673
  log.info('Connecting...');
626
674
 
627
675
  // 1. Ensure relay is running
@@ -630,12 +678,17 @@ async function cmdConnect() {
630
678
  await new Promise(r => setTimeout(r, 1000));
631
679
  }
632
680
 
633
- // 2. Ensure Chrome is running
681
+ // 2. Ensure browser is running (see getBrowserConfig + docs/BROWSERS.md)
682
+ const browser = getBrowserConfig();
634
683
  try {
635
- execSync('pgrep -x "Google Chrome"', { stdio: 'ignore' });
684
+ execSync(`pgrep -x "${browser.processName}"`, { stdio: 'ignore' });
636
685
  } catch {
637
- log.info('Starting Chrome...');
638
- execSync('open -a "Google Chrome"');
686
+ log.info(`Starting ${browser.name}...`);
687
+ if (browser.path) {
688
+ execSync(`open "${browser.path}"`, { stdio: 'ignore' });
689
+ } else {
690
+ execSync(`open -a "${browser.name}"`);
691
+ }
639
692
  await new Promise(r => setTimeout(r, 3000));
640
693
  }
641
694
 
@@ -647,7 +700,7 @@ async function cmdConnect() {
647
700
 
648
701
  if (!await checkExtension()) {
649
702
  log.fail('Extension not connected to relay');
650
- log.info('Make sure Glider extension is installed in Chrome');
703
+ log.info(`Make sure Glider extension is installed in ${browser.name} (Chromium-based only; see glider docs/BROWSERS.md)`);
651
704
  process.exit(1);
652
705
  }
653
706
  log.ok('Extension connected');
@@ -665,18 +718,18 @@ async function cmdConnect() {
665
718
  return;
666
719
  }
667
720
 
668
- // 5. Ensure we have a real tab (not chrome://)
721
+ // 5. Ensure we have a real tab (not chrome:// or arc://)
669
722
  try {
670
- const tabUrl = execSync(`osascript -e 'tell application "Google Chrome" to return URL of active tab of front window'`).toString().trim();
671
- if (tabUrl.startsWith('chrome://') || tabUrl.startsWith('chrome-extension://')) {
723
+ const tabUrl = execSync(`osascript -e 'tell application "${browser.name}" to return URL of active tab of front window'`).toString().trim();
724
+ if (tabUrl.startsWith('chrome://') || tabUrl.startsWith('chrome-extension://') || tabUrl.startsWith('arc://')) {
672
725
  log.info('Creating new tab...');
673
- execSync(`osascript -e 'tell application "Google Chrome" to make new tab at front window with properties {URL:"https://google.com"}'`);
726
+ execSync(`osascript -e 'tell application "${browser.name}" to make new tab at front window with properties {URL:"https://google.com"}'`);
674
727
  await new Promise(r => setTimeout(r, 2000));
675
728
  }
676
729
  } catch {
677
730
  // No window, create one
678
731
  log.info('Creating new window...');
679
- execSync(`osascript -e 'tell application "Google Chrome" to make new window with properties {URL:"https://google.com"}'`);
732
+ execSync(`osascript -e 'tell application "${browser.name}" to make new window with properties {URL:"https://google.com"}'`);
680
733
  await new Promise(r => setTimeout(r, 2000));
681
734
  }
682
735
 
@@ -700,7 +753,7 @@ async function cmdConnect() {
700
753
 
701
754
  // 7. Fallback: create fresh tab and retry
702
755
  log.info('Creating fresh tab...');
703
- execSync(`osascript -e 'tell application "Google Chrome" to make new tab at front window with properties {URL:"https://google.com"}'`);
756
+ execSync(`osascript -e 'tell application "${browser.name}" to make new tab at front window with properties {URL:"https://google.com"}'`);
704
757
  await new Promise(r => setTimeout(r, 2000));
705
758
 
706
759
  try {
@@ -717,13 +770,13 @@ async function cmdConnect() {
717
770
  }
718
771
  } catch {}
719
772
 
720
- // 8. Need manual click - open Chrome and show instructions
721
- log.warn('Click the Glider extension icon in Chrome');
722
- console.log(` ${B5}(on any real webpage, not chrome:// pages)${NC}`);
723
- execSync(`osascript -e 'tell application "Google Chrome" to activate'`);
773
+ // 8. Need manual click - activate browser and show instructions
774
+ log.warn(`Click the Glider extension icon in ${browser.name}`);
775
+ console.log(` ${B5}(on any real webpage, not chrome:// or arc:// pages)${NC}`);
776
+ execSync(`osascript -e 'tell application "${browser.name}" to activate'`);
724
777
 
725
778
  // Send macOS notification so user sees it even if not looking at terminal
726
- notify('Glider', 'Click the extension icon in Chrome to connect', true);
779
+ notify('Glider', `Click the extension icon in ${browser.name} to connect`, true);
727
780
 
728
781
  // Wait for user to click
729
782
  log.info('Waiting for connection...');
@@ -745,6 +798,40 @@ async function cmdConnect() {
745
798
  log.info('Make sure you clicked the extension icon on a real webpage');
746
799
  }
747
800
 
801
+ function cmdBrowser() {
802
+ const b = getBrowserConfig();
803
+ console.log('Browser config (used by glider connect):');
804
+ console.log(` name: ${b.name}`);
805
+ console.log(` path: ${b.path || '(default launch via name)'}`);
806
+ console.log(` processName: ${b.processName}`);
807
+ if (BROWSER_CONFIG.use) {
808
+ console.log(` use: ${BROWSER_CONFIG.use} ${DIM}(from registry)${NC}`);
809
+ }
810
+ console.log('');
811
+ console.log('Source: ~/.glider/config/browser.json { "use": "<key>" } or { name, path } → default "Google Chrome"');
812
+ console.log('Registry: ~/.cursor/registry/browsers.json or ~/.glider/config/browsers-registry.json. Keys: ' + (Object.keys(BROWSERS_REGISTRY).join(', ') || '(none loaded)'));
813
+ console.log('See README.md#browsers for compatibility and examples.');
814
+ }
815
+
816
+ function cmdUse(key) {
817
+ if (!key) {
818
+ console.log('Usage: glider use <key>');
819
+ console.log('Keys in registry: ' + (Object.keys(BROWSERS_REGISTRY).length ? Object.keys(BROWSERS_REGISTRY).join(', ') : '(no registry loaded)'));
820
+ if (BROWSER_CONFIG.use) console.log('Current: ' + BROWSER_CONFIG.use);
821
+ return;
822
+ }
823
+ if (!BROWSERS_REGISTRY[key]) {
824
+ console.error('Unknown key: ' + key + '. Available: ' + Object.keys(BROWSERS_REGISTRY).join(', '));
825
+ process.exit(1);
826
+ }
827
+ const configDir = path.join(os.homedir(), '.glider', 'config');
828
+ const browserPath = path.join(configDir, 'browser.json');
829
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
830
+ fs.writeFileSync(browserPath, JSON.stringify({ use: key }, null, 2) + '\n');
831
+ console.log('Set browser to: ' + key + ' → ' + BROWSERS_REGISTRY[key].name);
832
+ console.log('Run: glider connect');
833
+ }
834
+
748
835
  async function cmdTest() {
749
836
  showBanner();
750
837
  log.box('DIAGNOSTICS');
@@ -1342,11 +1429,13 @@ async function cmdExplore(url, opts = []) {
1342
1429
  let depth = 2;
1343
1430
  let outputDir = '/tmp/glider-explore';
1344
1431
  let harFile = null;
1432
+ let sessionId = null;
1345
1433
 
1346
1434
  for (let i = 0; i < opts.length; i++) {
1347
1435
  if (opts[i] === '--depth' || opts[i] === '-d') depth = parseInt(opts[++i], 10);
1348
1436
  else if (opts[i] === '--output' || opts[i] === '-o') outputDir = opts[++i];
1349
1437
  else if (opts[i] === '--har') harFile = opts[++i];
1438
+ else if (opts[i] === '--session-id') sessionId = opts[++i];
1350
1439
  }
1351
1440
 
1352
1441
  log.info(`Exploring: ${url} (depth: ${depth})`);
@@ -1357,6 +1446,7 @@ async function cmdExplore(url, opts = []) {
1357
1446
  const { spawn } = require('child_process');
1358
1447
  const spawnArgs = [bexplorePath, url, '--depth', String(depth), '--output', outputDir];
1359
1448
  if (harFile) spawnArgs.push('--har', harFile);
1449
+ if (sessionId) spawnArgs.push('--session-id', sessionId);
1360
1450
 
1361
1451
  const child = spawn('node', spawnArgs, {
1362
1452
  stdio: 'inherit'
@@ -1659,6 +1749,8 @@ ${B5}SETUP${NC}
1659
1749
 
1660
1750
  ${B5}STATUS${NC}
1661
1751
  ${BW}status${NC} Check server, extension, tabs
1752
+ ${BW}browser${NC} Show browser config ${DIM}(name, path, processName, or use key)${NC}
1753
+ ${BW}use${NC} <key> Set browser by registry key ${DIM}(e.g. arc, brave, chrome)${NC}
1662
1754
  ${BW}test${NC} Run diagnostics
1663
1755
 
1664
1756
  ${B5}NAVIGATION${NC}
@@ -1755,7 +1847,7 @@ ${YELLOW}DOMAIN EXTENSIONS:${NC}
1755
1847
  Add custom domain commands via ~/.glider/config/domains.json:
1756
1848
  {
1757
1849
  "mysite": { "url": "https://mysite.com/dashboard" },
1758
- "mytool": { "script": "~/.cursor/tools/scripts/mytool.sh" }
1850
+ "mytool": { "script": "~/scripts/mytool.sh" }
1759
1851
  }
1760
1852
  Then: glider mysite -> navigates to that URL
1761
1853
  glider mytool -> runs that script
@@ -1887,6 +1979,12 @@ async function main() {
1887
1979
  case 'connect':
1888
1980
  await cmdConnect();
1889
1981
  break;
1982
+ case 'browser':
1983
+ cmdBrowser();
1984
+ break;
1985
+ case 'use':
1986
+ cmdUse(args[1]);
1987
+ break;
1890
1988
  case 'test':
1891
1989
  await cmdTest();
1892
1990
  break;
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "Arc",
3
+ "path": "/Applications/Arc.app",
4
+ "processName": "Arc"
5
+ }
@@ -0,0 +1,7 @@
1
+ # Browser docs moved
2
+
3
+ Browser support and configuration now live in the main README:
4
+
5
+ - [README `## Browsers`](../README.md#browsers)
6
+
7
+ Reason: npmjs displays README prominently; putting browser setup there makes it much easier for users to find.
@@ -0,0 +1,40 @@
1
+ {
2
+ "meta": {
3
+ "project": "glidercli",
4
+ "updated": "2026-01-31"
5
+ },
6
+ "architecture": {
7
+ "flow": "glidercli -> bserve (ws:19988) -> chrome-extension -> chrome.debugger -> tab",
8
+ "relay_port": 19988,
9
+ "relay_host": "127.0.0.1"
10
+ },
11
+ "requirements": {
12
+ "node": ">=18",
13
+ "browser": "Chromium-based (Chrome, Arc, Edge, Brave, etc.); see README Browsers section",
14
+ "os": "macOS (tested), Linux (untested), Windows (untested)"
15
+ },
16
+ "install": {
17
+ "cli": "npm install -g glidercli",
18
+ "extension": {
19
+ "cws": "https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj",
20
+ "source": "https://github.com/vdutts7/glider"
21
+ }
22
+ },
23
+ "endpoints": {
24
+ "http": {
25
+ "/status": "GET - extension/targets/clients status",
26
+ "/targets": "GET - connected tabs",
27
+ "/cdp": "POST - forward CDP command"
28
+ },
29
+ "websocket": {
30
+ "/extension": "chrome extension connects here",
31
+ "/cdp": "cli/clients connect here"
32
+ }
33
+ },
34
+ "config_paths": {
35
+ "domains": "~/.glider/config/domains.json",
36
+ "browser": "~/.glider/config/browser.json",
37
+ "daemon_log": "~/.glider/daemon.log"
38
+ },
39
+ "discovery": "glider --help"
40
+ }
package/lib/bexplore.js CHANGED
@@ -27,6 +27,8 @@ class SiteExplorer {
27
27
  this.depth = options.depth || 3;
28
28
  this.outputDir = options.outputDir || '/tmp/explore';
29
29
  this.harFile = options.harFile;
30
+ this.wantedSessionId = options.sessionId || null;
31
+ this.sessionResolved = null;
30
32
 
31
33
  // Captured data
32
34
  this.requests = [];
@@ -77,8 +79,15 @@ class SiteExplorer {
77
79
  }
78
80
 
79
81
  if (msg.method === 'Target.attachedToTarget') {
80
- if (!this.sessionId) {
81
- this.sessionId = msg.params.sessionId;
82
+ const sid = msg.params.sessionId;
83
+ if (this.wantedSessionId) {
84
+ if (sid === this.wantedSessionId) {
85
+ this.sessionId = sid;
86
+ if (this.sessionResolved) this.sessionResolved();
87
+ }
88
+ } else if (!this.sessionId) {
89
+ this.sessionId = sid;
90
+ if (this.sessionResolved) this.sessionResolved();
82
91
  }
83
92
  }
84
93
 
@@ -179,7 +188,13 @@ class SiteExplorer {
179
188
 
180
189
  async init() {
181
190
  await this.send('Target.setAutoAttach', { autoAttach: true, waitForDebuggerOnStart: false, flatten: true });
182
- await new Promise(r => setTimeout(r, 500));
191
+ await new Promise((resolve, reject) => {
192
+ this.sessionResolved = resolve;
193
+ setTimeout(() => {
194
+ if (!this.sessionId) reject(new Error('Timeout waiting for tab attachment'));
195
+ else resolve();
196
+ }, 10000);
197
+ });
183
198
  if (!this.sessionId) throw new Error('No browser tab connected');
184
199
 
185
200
  // Enable ALL the things
@@ -756,14 +771,16 @@ Examples:
756
771
  let depth = 3;
757
772
  let outputDir = '/tmp/explore';
758
773
  let harFile = null;
774
+ let sessionId = null;
759
775
 
760
776
  for (let i = 0; i < args.length; i++) {
761
777
  if (args[i] === '--depth') depth = parseInt(args[++i]);
762
778
  else if (args[i] === '--output') outputDir = args[++i];
763
779
  else if (args[i] === '--har') harFile = args[++i];
780
+ else if (args[i] === '--session-id') sessionId = args[++i];
764
781
  }
765
782
 
766
- const explorer = new SiteExplorer({ depth, outputDir, harFile });
783
+ const explorer = new SiteExplorer({ depth, outputDir, harFile, sessionId });
767
784
 
768
785
  try {
769
786
  await explorer.connect();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glidercli",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Browser automation CLI. Control Chrome from terminal via CDP, run YAML task files, autonomous loops until completion.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -37,6 +37,8 @@
37
37
  "files": [
38
38
  "bin/",
39
39
  "lib/",
40
+ "docs/",
41
+ "config/",
40
42
  "index.js",
41
43
  "README.md"
42
44
  ]