glidercli 0.3.10 → 0.3.14
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 +113 -189
- package/bin/glider.js +68 -1
- package/config/domains.template.json +15 -0
- package/docs/setup.json +5 -2
- package/lib/bserve.js +8 -0
- package/lib/domain-resolve.js +27 -24
- package/lib/paths.js +76 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,195 +8,116 @@
|
|
|
8
8
|
<h1 align="center">glider CLI</h1>
|
|
9
9
|
<p align="center"><i><b>Browser automation CLI with autonomous loop execution</b></i></p>
|
|
10
10
|
|
|
11
|
-
<a href="https://github.com/vdutts7/glidercli"><img src="./assets/badges/github.badge.svg" alt="GitHub" height="34" /></a>
|
|
11
|
+
<a href="https://github.com/vdutts7/glidercli"><img src="./assets/badges/github.badge.svg" alt="GitHub" height="34" /></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/glidercli"><img src="./assets/badges/npm.badge.svg" alt="glidercli on npm" height="34" /></a>
|
|
12
13
|
|
|
13
14
|
</div>
|
|
14
15
|
|
|
15
16
|
<br/>
|
|
16
17
|
|
|
17
|
-
## About
|
|
18
|
-
|
|
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 |
|
|
26
|
-
|
|
27
18
|
---
|
|
28
19
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
|
32
|
-
|
|
33
|
-
|
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
## Requirements
|
|
20
|
+
| | headless CDP | extension relay (glider) |
|
|
21
|
+
|---|--------------|---------------------------|
|
|
22
|
+
| logged-in tab / SSO | ❌ cold profile | ✅ attach to open tab |
|
|
23
|
+
| corp / MFA sessions | ❌ re-auth wall | ✅ reuse browser cookies |
|
|
24
|
+
| loop until done | manual glue | ✅ `glider loop` + markers |
|
|
40
25
|
|
|
41
|
-
|
|
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 |
|
|
26
|
+
`glidercli` → relay at `ws://127.0.0.1:19988` → [`Glider extension`](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj) → CDP on your tab.
|
|
45
27
|
|
|
46
28
|
---
|
|
47
29
|
|
|
48
|
-
##
|
|
49
|
-
|
|
50
|
-
| | |
|
|
51
|
-
|---|---|
|
|
52
|
-
| **How it works** | Chrome extension → WebSocket relay → CDP. Browser must support that extension (Chromium-based). |
|
|
30
|
+
## Issue
|
|
53
31
|
|
|
54
|
-
|
|
32
|
+
| failure mode | symptom |
|
|
33
|
+
|--------------|---------|
|
|
34
|
+
| ❌ cold profile launch | SSO/MFA breaks on internal sites; no logged-in tab to drive |
|
|
35
|
+
| ❌ raw CDP without bridge | extension must relay debugger traffic from real Chromium profile |
|
|
36
|
+
| ❌ cookie-only terminal fetch | cross-origin API hosts often 401 without in-tab bearer |
|
|
37
|
+
| ❌ one-shot scripts only | no first-class loop with iteration cap, timeout, completion marker |
|
|
55
38
|
|
|
56
|
-
|
|
39
|
+
---
|
|
57
40
|
|
|
58
|
-
|
|
59
|
-
|:---:|--------|--------|
|
|
60
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chrome.webp" width="16" alt=""> | Google Chrome | Default for `glider connect`|
|
|
61
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chrome-canary.webp" width="16" alt=""> | Chrome Canary | n/a |
|
|
62
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/arc.webp" width="16" alt=""> | Arc | [browser.json](config/browser.json.example) (`{ "use": "arc" }`) |
|
|
63
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/microsoft/microsoft-edge.webp" width="16" alt=""> | Microsoft Edge | n/a |
|
|
64
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/brave.webp" width="16" alt=""> | Brave | n/a |
|
|
65
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/operagx.webp" width="16" alt=""> | Opera | n/a |
|
|
66
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/vivaldi.webp" width="16" alt=""> | Vivaldi | n/a |
|
|
67
|
-
| <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. |
|
|
68
|
-
|
|
69
|
-
### Future
|
|
70
|
-
|
|
71
|
-
- not supported today
|
|
72
|
-
- Glider needs a **Chromium-based** browser that can install the extension from the **Chrome Web Store**
|
|
73
|
-
- no timeline implied- listed for clarity
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
| | Browser | Notes |
|
|
77
|
-
|:---:|--------|--------|
|
|
78
|
-
| <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 |
|
|
79
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/firefox-focus.webp" width="16" alt=""> | Firefox Focus | Gecko- same constraints as Firefox |
|
|
80
|
-
| <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 |
|
|
81
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/librewolf.webp" width="16" alt=""> | LibreWolf | Gecko- same constraints as Firefox |
|
|
82
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/waterfox.webp" width="16" alt=""> | Waterfox | Gecko- same constraints as Firefox |
|
|
83
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/zen.webp" width="16" alt=""> | Zen | Gecko- same constraints as Firefox |
|
|
84
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/floorp.webp" width="16" alt=""> | Floorp | Gecko- same constraints as Firefox |
|
|
85
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/tor-browser.webp" width="16" alt=""> | Tor Browser | Gecko- same constraints as Firefox |
|
|
86
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/mullvad-browser.webp" width="16" alt=""> | Mullvad Browser | Gecko- same constraints as Firefox |
|
|
87
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/icecat.webp" width="16" alt=""> | IceCat | Gecko- same constraints as Firefox |
|
|
88
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/safari.webp" width="16" alt=""> | Safari | WebKit (Apple desktop). Not Chromium |
|
|
89
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/safari-technology-preview.webp" width="16" alt=""> | Safari Technology Preview | WebKit preview channel (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/dia-browser.webp" width="16" alt=""> | Dia | AI-first browser, not in Glider’s supported Chromium + CWS model today |
|
|
92
|
-
| <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 |
|
|
93
|
-
| <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 |
|
|
94
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/whale-browser.webp" width="16" alt=""> | Whale Browser | Chromium-based, support not implemented in Glider today |
|
|
95
|
-
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/yandex-browser.webp" width="16" alt=""> | Yandex Browser | Chromium-based, support not implemented in Glider today |
|
|
96
|
-
| <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 |
|
|
97
|
-
| <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 |
|
|
98
|
-
| <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 |
|
|
99
|
-
| <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 |
|
|
100
|
-
|
|
101
|
-
### Configuring the browser
|
|
102
|
-
|
|
103
|
-
**Priority (highest first):** config file -> default `Google Chrome`
|
|
104
|
-
|
|
105
|
-
#### Config file: `$HOME/.glider/config/browser.json`
|
|
106
|
-
|
|
107
|
-
Use a **registry key** or explicit name/path in the file
|
|
108
|
-
|
|
109
|
-
**Option A- Registry key (recommended):**
|
|
110
|
-
|
|
111
|
-
Set browser by key from the browsers registry. Run `glider use <key>` to write this.
|
|
41
|
+
## Setup
|
|
112
42
|
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
43
|
+
```bash
|
|
44
|
+
npm i -g glidercli
|
|
45
|
+
glider install
|
|
46
|
+
glider connect
|
|
117
47
|
```
|
|
118
48
|
|
|
119
|
-
|
|
49
|
+
| Step | Action |
|
|
50
|
+
|------|--------|
|
|
51
|
+
| CLI | `npm i -g glidercli` |
|
|
52
|
+
| Extension | [`Glider` on Chrome Web Store](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj) in the profile you automate |
|
|
53
|
+
| Daemon | `glider install` |
|
|
54
|
+
| Session | `glider connect` (once per browser launch) |
|
|
120
55
|
|
|
121
|
-
|
|
56
|
+
Node 18+. Chromium-based browser with the extension enabled (see Browsers).
|
|
122
57
|
|
|
123
|
-
|
|
124
|
-
|-------|:--------:|-------------|
|
|
125
|
-
| `name` | Yes* | App name for `open -a` / AppleScript. Must match system (e.g. `Arc`, `Google Chrome`). |
|
|
126
|
-
| `path` | No | If set, use `open "<path>"` instead of `open -a "<name>"`. For non-default install location. |
|
|
127
|
-
| `processName` | No | For `pgrep -x`. Defaults to `name`. |
|
|
58
|
+
---
|
|
128
59
|
|
|
129
|
-
|
|
60
|
+
## Browsers
|
|
130
61
|
|
|
131
|
-
|
|
62
|
+
Extension + relay model uses Chromium + Glider extension from Chrome Web Store in the same profile as `glider connect`.
|
|
132
63
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
64
|
+
| | Browser | Config |
|
|
65
|
+
|---|--------|--------|
|
|
66
|
+
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chrome.webp" width="16" alt=""> | Google Chrome | default for `glider connect` |
|
|
67
|
+
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/arc.webp" width="16" alt=""> | Arc | [`config/browser.json.example`](config/browser.json.example) |
|
|
68
|
+
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/microsoft/microsoft-edge.webp" width="16" alt=""> | Microsoft Edge | registry key `edge` |
|
|
69
|
+
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/brave.webp" width="16" alt=""> | Brave | registry key `brave` |
|
|
70
|
+
| <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/vivaldi.webp" width="16" alt=""> | Vivaldi | registry key `vivaldi` |
|
|
140
71
|
|
|
141
|
-
|
|
72
|
+
Not supported today: Firefox/Safari/WebKit/Gecko, DuckDuckGo, browsers without Chrome Web Store extension path.
|
|
142
73
|
|
|
143
|
-
|
|
144
|
-
|---------|--------|-------------------|---------------------------|
|
|
145
|
-
| Arc | `Arc` | `/Applications/Arc.app` | `Arc` |
|
|
146
|
-
| Edge | `Microsoft Edge` | n/a | `Microsoft Edge` |
|
|
147
|
-
| Chrome (custom) | `Google Chrome` | `/Users/me/Applications/Google Chrome.app` | `Google Chrome` |
|
|
74
|
+
### Browser config
|
|
148
75
|
|
|
149
|
-
|
|
76
|
+
Priority: `~/.glider/config/browser.json` → default Google Chrome.
|
|
150
77
|
|
|
151
|
-
|
|
78
|
+
Registry key (recommended):
|
|
152
79
|
|
|
153
|
-
|
|
80
|
+
```json
|
|
81
|
+
{ "use": "arc" }
|
|
82
|
+
```
|
|
154
83
|
|
|
155
|
-
|
|
84
|
+
Registry file: `~/.glider/config/browsers-registry.json`
|
|
156
85
|
|
|
157
|
-
|
|
86
|
+
```bash
|
|
87
|
+
glider use arc
|
|
88
|
+
glider browser
|
|
89
|
+
```
|
|
158
90
|
|
|
159
|
-
|
|
91
|
+
Explicit name/path:
|
|
160
92
|
|
|
161
93
|
```json
|
|
162
94
|
{
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
|
|
166
|
-
"brave": { "name": "Brave Browser", "path": "/Applications/Brave Browser.app", "processName": "Brave Browser" },
|
|
167
|
-
"chrome": { "name": "Google Chrome", "path": "/Applications/Google Chrome.app", "processName": "Google Chrome" },
|
|
168
|
-
"edge": { "name": "Microsoft Edge", "path": "/Applications/Microsoft Edge.app", "processName": "Microsoft Edge" }
|
|
169
|
-
}
|
|
95
|
+
"name": "Arc",
|
|
96
|
+
"path": "/Applications/Arc.app",
|
|
97
|
+
"processName": "Arc"
|
|
170
98
|
}
|
|
171
99
|
```
|
|
172
100
|
|
|
173
|
-
**Commands:**
|
|
174
|
-
|
|
175
101
|
| Command | Effect |
|
|
176
102
|
|---------|--------|
|
|
177
|
-
| `glider use arc` |
|
|
178
|
-
| `glider use
|
|
179
|
-
| `glider
|
|
180
|
-
| `glider browser` | Show resolved name, path, processName (and `use` key if set). |
|
|
181
|
-
|
|
182
|
-
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.
|
|
103
|
+
| `glider use arc` | write `{ "use": "arc" }` to `browser.json` |
|
|
104
|
+
| `glider use` | list registry keys |
|
|
105
|
+
| `glider browser` | show resolved name, path, process |
|
|
183
106
|
|
|
184
|
-
|
|
107
|
+
macOS: `open -a` / AppleScript. Linux/Windows: partial, on roadmap.
|
|
185
108
|
|
|
186
|
-
|
|
187
|
-
|----------|----------|
|
|
188
|
-
| macOS | `open -a "<name>"` or `open "<path>"`, AppleScript for tab/window. `name` = exact app name |
|
|
189
|
-
| Linux / Windows | Not fully implemented. Future: `path` may be executable. |
|
|
109
|
+
---
|
|
190
110
|
|
|
191
|
-
|
|
111
|
+
## Task files
|
|
192
112
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
113
|
+
```yaml
|
|
114
|
+
name: hn-front
|
|
115
|
+
steps:
|
|
116
|
+
goto: "https://news.ycombinator.com"
|
|
117
|
+
wait: 2
|
|
118
|
+
eval: "document.title"
|
|
119
|
+
screenshot: "/tmp/hn.png"
|
|
120
|
+
```
|
|
200
121
|
|
|
201
122
|
---
|
|
202
123
|
|
|
@@ -205,28 +126,41 @@ Add or edit entries in the registry to match your machine (e.g. custom install p
|
|
|
205
126
|
```bash
|
|
206
127
|
glider connect
|
|
207
128
|
glider status
|
|
208
|
-
glider goto "https://
|
|
129
|
+
glider goto "https://news.ycombinator.com"
|
|
209
130
|
glider eval "document.title"
|
|
210
|
-
glider run
|
|
211
|
-
glider loop
|
|
131
|
+
glider run `hn-scrape.yaml`
|
|
132
|
+
glider loop `hn-scrape.yaml` -n 50 -m hn_scrape_done
|
|
212
133
|
```
|
|
213
134
|
|
|
214
|
-
|
|
135
|
+
```bash
|
|
136
|
+
# per-host capture hints (optional)
|
|
137
|
+
glider resolve https://news.ycombinator.com --json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
| Output | Path |
|
|
215
141
|
|--------|------|
|
|
216
|
-
|
|
|
142
|
+
| daemon log | `~/.glider/daemon.log` |
|
|
143
|
+
| domain index | `~/.glider/config/domains.json` |
|
|
144
|
+
| per-host intel | `~/.glider/warch/HOST/glider.json` |
|
|
145
|
+
| explore cache | `~/.glider/bexplore/HOST/` |
|
|
146
|
+
|
|
147
|
+
| Env | Default | Role |
|
|
148
|
+
|-----|---------|------|
|
|
149
|
+
| `GLIDER_HOME` | `~/.glider` | config, cache, warch tree |
|
|
150
|
+
| `AGREGISTRY` | unset | optional registry root → warch at `$AGREGISTRY/warch/HOST/` |
|
|
151
|
+
|
|
152
|
+
Copy `config/domains.template.json` into `~/.glider/config/domains.json` to seed the host index.
|
|
217
153
|
|
|
218
154
|
---
|
|
219
155
|
|
|
220
|
-
##
|
|
156
|
+
## Gotchas
|
|
221
157
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
-
|
|
226
|
-
-
|
|
227
|
-
-
|
|
228
|
-
- screenshot: "/tmp/out.png"
|
|
229
|
-
```
|
|
158
|
+
| problem | fix | stability | why |
|
|
159
|
+
|---------|-----|-----------|-----|
|
|
160
|
+
| extension not connected | click Glider icon in toolbar → `glider connect` | per Chrome launch | relay waits on extension WS |
|
|
161
|
+
| wrong tab targeted | `glider targets` → `glider use-session session-6` | session-stable | multi-tab needs explicit session |
|
|
162
|
+
| explore HAR empty bodies | replay in-tab with auth hook on XHR/fetch | site-specific | some SPAs never expose bearer in storage |
|
|
163
|
+
| `resolve` misses host | add `~/.glider/warch/HOST/glider.json` or set `AGREGISTRY` | file-stable | optional per-host capture hints |
|
|
230
164
|
|
|
231
165
|
---
|
|
232
166
|
|
|
@@ -234,42 +168,32 @@ steps:
|
|
|
234
168
|
|
|
235
169
|
| Command | Description |
|
|
236
170
|
|---------|-------------|
|
|
237
|
-
| `glider install` |
|
|
238
|
-
| `glider
|
|
239
|
-
| `glider
|
|
240
|
-
| `glider
|
|
241
|
-
| `glider
|
|
242
|
-
| `glider
|
|
243
|
-
| `glider
|
|
244
|
-
| `glider
|
|
245
|
-
| `glider type <sel> <text>` | Type into input |
|
|
246
|
-
| `glider screenshot [path]` | Capture page |
|
|
247
|
-
| `glider run <file>` | Run YAML task |
|
|
248
|
-
| `glider loop <file> [-n N]` | Loop until done or limit |
|
|
249
|
-
|
|
250
|
-
Full list: `glider --help`
|
|
251
|
-
|
|
252
|
-
---
|
|
171
|
+
| `glider install` / `uninstall` | daemon at login |
|
|
172
|
+
| `glider connect` | attach relay to browser |
|
|
173
|
+
| `glider status` | server, extension, tabs |
|
|
174
|
+
| `glider goto` / `eval` / `click` / `type` | page ops |
|
|
175
|
+
| `glider screenshot` | PNG capture |
|
|
176
|
+
| `glider explore` | crawl + HAR |
|
|
177
|
+
| `glider resolve` | host → local warch intel (`--json`) |
|
|
178
|
+
| `glider run` / `loop` | YAML task / Ralph loop |
|
|
253
179
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
| Doc | Contents |
|
|
257
|
-
|-----|----------|
|
|
258
|
-
| This README | Install, usage, commands, full browser support/config |
|
|
259
|
-
| [config/browser.json.example](config/browser.json.example) | Example browser config |
|
|
180
|
+
Full surface: `glider --help`
|
|
260
181
|
|
|
261
182
|
---
|
|
262
183
|
|
|
263
184
|
## Roadmap
|
|
264
185
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
186
|
+
| status | item |
|
|
187
|
+
|--------|------|
|
|
188
|
+
| done | CDP relay, YAML tasks, loop, daemon, multi-tab, `resolve` |
|
|
189
|
+
| planned | Linux and Windows browser launch |
|
|
190
|
+
| | headless cloud mode |
|
|
191
|
+
| | task chaining |
|
|
270
192
|
|
|
271
193
|
---
|
|
272
194
|
|
|
273
195
|
## Contact
|
|
274
196
|
|
|
275
|
-
|
|
197
|
+
[](https://vd7.io)
|
|
198
|
+
|
|
199
|
+
[](https://x.com/vdutts7)
|
package/bin/glider.js
CHANGED
|
@@ -700,6 +700,66 @@ async function cmdRestart() {
|
|
|
700
700
|
await cmdStart();
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
+
// POTEMKIN-PATCH v1: automate the extension reload + tab re-attachment loop
|
|
704
|
+
// so operators don't have to click chrome://extensions after every code change.
|
|
705
|
+
// Bootstrap cost: one manual reload after installing this handler for the first time.
|
|
706
|
+
async function cmdReloadExt() {
|
|
707
|
+
try {
|
|
708
|
+
const r = await postExtension({ method: 'reloadSelf', params: {} });
|
|
709
|
+
log.ok(`Extension reload triggered (persisted ${r.result?.persisted ?? '?'} tab URLs).`);
|
|
710
|
+
log.info('Waiting 4s for extension to boot back up + reconnect...');
|
|
711
|
+
await new Promise(x => setTimeout(x, 4000));
|
|
712
|
+
// Extension reboots → autoAttachActiveTab restores from chrome.storage
|
|
713
|
+
// Confirm state
|
|
714
|
+
const st = await httpGetJson('/status');
|
|
715
|
+
log.ok(`relay reconnected: extension=${st.extension} targets=${st.targets}`);
|
|
716
|
+
} catch (e) {
|
|
717
|
+
log.fail(`reload-ext failed: ${e.message}`);
|
|
718
|
+
log.info('First-time bootstrap: open your browser extensions page and reload Glider (one time only).');
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
async function cmdAttachAll(filter) {
|
|
723
|
+
try {
|
|
724
|
+
const r = await postExtension({ method: 'attachAllTabs', params: filter ? { urlSubstring: filter } : {} });
|
|
725
|
+
log.ok(`attach-all: attached=${r.result?.attached ?? '?'} skipped=${r.result?.skipped ?? '?'} failed=${r.result?.failed ?? '?'} total_connected=${r.result?.total_connected ?? '?'}`);
|
|
726
|
+
} catch (e) {
|
|
727
|
+
log.fail(`attach-all failed: ${e.message}`);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Helper: POST to relay's /extension endpoint (already exists in bserve.js)
|
|
732
|
+
async function postExtension(body) {
|
|
733
|
+
return new Promise((resolve, reject) => {
|
|
734
|
+
const data = JSON.stringify(body);
|
|
735
|
+
const req = http.request({
|
|
736
|
+
hostname: '127.0.0.1', port: 19988, path: '/extension', method: 'POST',
|
|
737
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }
|
|
738
|
+
}, (res) => {
|
|
739
|
+
let s = '';
|
|
740
|
+
res.on('data', c => s += c);
|
|
741
|
+
res.on('end', () => {
|
|
742
|
+
try {
|
|
743
|
+
const j = JSON.parse(s);
|
|
744
|
+
if (j.error) reject(new Error(j.error.message || j.error));
|
|
745
|
+
else resolve(j);
|
|
746
|
+
} catch(e) { reject(new Error('bad JSON from /extension: ' + s.slice(0,200))); }
|
|
747
|
+
});
|
|
748
|
+
});
|
|
749
|
+
req.on('error', reject);
|
|
750
|
+
req.write(data); req.end();
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
async function httpGetJson(pathStr) {
|
|
755
|
+
return new Promise((resolve, reject) => {
|
|
756
|
+
http.get({ hostname: '127.0.0.1', port: 19988, path: pathStr }, (res) => {
|
|
757
|
+
let s = ''; res.on('data', c => s += c);
|
|
758
|
+
res.on('end', () => { try { resolve(JSON.parse(s)); } catch(e) { reject(e); } });
|
|
759
|
+
}).on('error', reject);
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
|
|
703
763
|
// Daemon management - runs forever, respawns on crash
|
|
704
764
|
async function cmdInstallDaemon() {
|
|
705
765
|
const home = os.homedir();
|
|
@@ -1973,7 +2033,7 @@ ${B5}STATUS${NC}
|
|
|
1973
2033
|
${BW}use${NC} <key> Set browser by registry key ${DIM}(e.g. arc, brave, chrome)${NC}
|
|
1974
2034
|
${BW}test${NC} Run diagnostics
|
|
1975
2035
|
${BW}domains${NC} List ~/.glider domain shortcuts + warch paths
|
|
1976
|
-
${BW}resolve${NC} <url>
|
|
2036
|
+
${BW}resolve${NC} <url> Domain intel under ~/.glider/warch ${DIM}(--json)${NC}
|
|
1977
2037
|
|
|
1978
2038
|
${B5}NAVIGATION${NC}
|
|
1979
2039
|
${BW}goto${NC} <url> Navigate to URL
|
|
@@ -2188,6 +2248,13 @@ async function main() {
|
|
|
2188
2248
|
case 'restart':
|
|
2189
2249
|
await cmdRestart();
|
|
2190
2250
|
break;
|
|
2251
|
+
case 'reload-ext':
|
|
2252
|
+
case 'reload-extension':
|
|
2253
|
+
await cmdReloadExt();
|
|
2254
|
+
break;
|
|
2255
|
+
case 'attach-all':
|
|
2256
|
+
await cmdAttachAll(args[1]); // optional URL substring filter, e.g. 'microsoft.com'
|
|
2257
|
+
break;
|
|
2191
2258
|
case 'install':
|
|
2192
2259
|
await cmdInstallDaemon();
|
|
2193
2260
|
break;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"schema_version": "2.0",
|
|
4
|
+
"description": "Domain index: host → warch dir under registry base",
|
|
5
|
+
"registry_base": "AGREGISTRY env if set, else GLIDER_HOME (~/.glider)",
|
|
6
|
+
"warch_layout": "<registry_base>/warch/<host>/"
|
|
7
|
+
},
|
|
8
|
+
"example_com": {
|
|
9
|
+
"host": "example.com",
|
|
10
|
+
"warch": "warch/example.com",
|
|
11
|
+
"shortcut": { "type": "none", "target": null },
|
|
12
|
+
"description": "Replace with your domain",
|
|
13
|
+
"notes": "glider.json + gotchas.json under warch/<host>/"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/docs/setup.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"project": "glidercli",
|
|
4
|
-
"updated": "2026-
|
|
4
|
+
"updated": "2026-07-06"
|
|
5
5
|
},
|
|
6
6
|
"architecture": {
|
|
7
7
|
"flow": "glidercli -> bserve (ws:19988) -> chrome-extension -> chrome.debugger -> tab",
|
|
@@ -32,8 +32,11 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"config_paths": {
|
|
35
|
+
"glider_home": "~/.glider (override: GLIDER_HOME)",
|
|
35
36
|
"domains": "~/.glider/config/domains.json",
|
|
36
|
-
"domains_template": "
|
|
37
|
+
"domains_template": "config/domains.template.json (shipped in package)",
|
|
38
|
+
"warch_root": "<registry_base>/warch/<host>/ (glider.json, gotchas.json, bexplore/)",
|
|
39
|
+
"registry_base": "AGREGISTRY if set, else GLIDER_HOME (~/.glider)",
|
|
37
40
|
"resolve": "glider resolve <url> --json",
|
|
38
41
|
"browser": "~/.glider/config/browser.json",
|
|
39
42
|
"daemon_log": "~/.glider/daemon.log"
|
package/lib/bserve.js
CHANGED
|
@@ -294,6 +294,14 @@ async function routeCDPCommand({ method, params, sessionId }) {
|
|
|
294
294
|
};
|
|
295
295
|
|
|
296
296
|
case 'Target.setAutoAttach':
|
|
297
|
+
// OOPIF-PATCH v1: forward to extension when session-scoped (per-tab autoAttach)
|
|
298
|
+
// so chrome.debugger emits Target.attachedToTarget for OOPIF children.
|
|
299
|
+
// When no sessionId (browser-level call), fall through to the existing
|
|
300
|
+
// "replay attachedToTarget for connectedTargets" branch in the ws handler above.
|
|
301
|
+
if (sessionId) {
|
|
302
|
+
break; // forward to extension
|
|
303
|
+
}
|
|
304
|
+
return {};
|
|
297
305
|
case 'Target.setDiscoverTargets':
|
|
298
306
|
return {};
|
|
299
307
|
|
package/lib/domain-resolve.js
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const os = require('os');
|
|
5
4
|
const path = require('path');
|
|
6
5
|
const { URL } = require('url');
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return path.join(base, 'warch');
|
|
16
|
-
}
|
|
6
|
+
const {
|
|
7
|
+
configPath,
|
|
8
|
+
gliderHome,
|
|
9
|
+
registryBase,
|
|
10
|
+
registryMode,
|
|
11
|
+
warchDirForHost,
|
|
12
|
+
warchRoot,
|
|
13
|
+
} = require('./paths.js');
|
|
17
14
|
|
|
18
15
|
function loadDomainsIndex() {
|
|
19
|
-
for (const cfgPath of
|
|
16
|
+
for (const cfgPath of configPath('domains.json')) {
|
|
20
17
|
if (!fs.existsSync(cfgPath)) continue;
|
|
21
18
|
try {
|
|
22
19
|
return JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
@@ -37,17 +34,8 @@ function hostFromUrl(input) {
|
|
|
37
34
|
|
|
38
35
|
function resolveDomain(input) {
|
|
39
36
|
const host = hostFromUrl(input);
|
|
40
|
-
const root = warchRoot();
|
|
41
|
-
const warchPath = host ? path.join(root, host) : null;
|
|
42
37
|
const domains = loadDomainsIndex();
|
|
43
|
-
|
|
44
|
-
for (const [key, val] of Object.entries(domains)) {
|
|
45
|
-
if (key === 'meta' || !val || typeof val !== 'object') continue;
|
|
46
|
-
if (val.host === host || key === host) {
|
|
47
|
-
indexHit = key;
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
38
|
+
const warchPath = host ? warchDirForHost(host, domains) : null;
|
|
51
39
|
const gliderJsonPath = warchPath && path.join(warchPath, 'glider.json');
|
|
52
40
|
const gotchasPath = warchPath && path.join(warchPath, 'gotchas.json');
|
|
53
41
|
const gliderJsonExists = !!(gliderJsonPath && fs.existsSync(gliderJsonPath));
|
|
@@ -60,13 +48,28 @@ function resolveDomain(input) {
|
|
|
60
48
|
}
|
|
61
49
|
return {
|
|
62
50
|
host,
|
|
51
|
+
registry_mode: registryMode(),
|
|
52
|
+
glider_home: gliderHome(),
|
|
53
|
+
registry_base: registryBase(),
|
|
54
|
+
warch_root: warchRoot(),
|
|
63
55
|
warch_path: warchPath,
|
|
64
56
|
glider_json_exists: gliderJsonExists,
|
|
65
57
|
gotchas_exists: gotchasExists,
|
|
66
|
-
domains_index_hit:
|
|
58
|
+
domains_index_hit: host ? Object.keys(domains).find((k) => {
|
|
59
|
+
if (k === 'meta') return false;
|
|
60
|
+
const v = domains[k];
|
|
61
|
+
return v && typeof v === 'object' && (v.host === host || k === host);
|
|
62
|
+
}) ?? null : null,
|
|
67
63
|
capture_mode: gliderJson?.capture_mode ?? null,
|
|
68
64
|
wait_ms: gliderJson?.wait_ms ?? null,
|
|
65
|
+
auth_mode: gliderJson?.auth_mode ?? null,
|
|
69
66
|
};
|
|
70
67
|
}
|
|
71
68
|
|
|
72
|
-
module.exports = {
|
|
69
|
+
module.exports = {
|
|
70
|
+
resolveDomain,
|
|
71
|
+
hostFromUrl,
|
|
72
|
+
warchRoot,
|
|
73
|
+
loadDomainsIndex,
|
|
74
|
+
gliderHome,
|
|
75
|
+
};
|
package/lib/paths.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/** Browser runtime data — always ~/.glider unless GLIDER_HOME set. */
|
|
7
|
+
function gliderHome() {
|
|
8
|
+
return process.env.GLIDER_HOME || path.join(os.homedir(), '.glider');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Installed package root (glidercli npm tree). */
|
|
12
|
+
function packageRoot() {
|
|
13
|
+
return path.join(__dirname, '..');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Registry base for warch: AGREGISTRY or GLIDER_HOME. */
|
|
17
|
+
function registryBase() {
|
|
18
|
+
const ag = process.env.AGREGISTRY;
|
|
19
|
+
if (ag) return expandUser(ag);
|
|
20
|
+
return gliderHome();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function registryMode() {
|
|
24
|
+
return process.env.AGREGISTRY ? 'agents' : 'standalone';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function configPath(name) {
|
|
28
|
+
const home = gliderHome();
|
|
29
|
+
return [
|
|
30
|
+
path.join(home, 'config', name),
|
|
31
|
+
path.join(home, name),
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Domain intel: $AGREGISTRY/warch or ~/.glider/warch when AGREGISTRY unset. */
|
|
36
|
+
function warchRoot() {
|
|
37
|
+
return path.join(registryBase(), 'warch');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function domainsTemplatePath() {
|
|
41
|
+
return path.join(packageRoot(), 'config', 'domains.template.json');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function expandUser(p) {
|
|
45
|
+
if (!p || typeof p !== 'string') return p;
|
|
46
|
+
return p.replace(/^~(?=$|[/\\])/, os.homedir());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** warch dir: domains.json entry (relative to registryBase) or warch/<host>. */
|
|
50
|
+
function warchDirForHost(host, domainsIndex) {
|
|
51
|
+
if (!host) return null;
|
|
52
|
+
const domains = domainsIndex || {};
|
|
53
|
+
const base = registryBase();
|
|
54
|
+
for (const [key, val] of Object.entries(domains)) {
|
|
55
|
+
if (key === 'meta' || !val || typeof val !== 'object') continue;
|
|
56
|
+
if (val.host !== host && key !== host) continue;
|
|
57
|
+
if (val.warch) {
|
|
58
|
+
const raw = expandUser(String(val.warch));
|
|
59
|
+
return path.isAbsolute(raw) ? raw : path.join(base, raw);
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
return path.join(warchRoot(), host);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
gliderHome,
|
|
68
|
+
packageRoot,
|
|
69
|
+
registryBase,
|
|
70
|
+
registryMode,
|
|
71
|
+
configPath,
|
|
72
|
+
warchRoot,
|
|
73
|
+
domainsTemplatePath,
|
|
74
|
+
expandUser,
|
|
75
|
+
warchDirForHost,
|
|
76
|
+
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glidercli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
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": {
|
|
7
7
|
"glider": "bin/glider.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"test": "node bin/glider.js --help"
|
|
10
|
+
"test": "node bin/glider.js --help && bash scripts/ship-gate.sh"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
13
13
|
"browser",
|