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 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> &nbsp; <a href="https://www.npmjs.com/package/glidercli"><img src="./assets/badges/npm.badge.svg" alt="npm install" 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
- ## Install
30
-
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
-
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
- | 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 |
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
- ## Browsers
49
-
50
- | | |
51
- |---|---|
52
- | **How it works** | Chrome extension → WebSocket relay → CDP. Browser must support that extension (Chromium-based). |
30
+ ## Issue
53
31
 
54
- ### Browser support
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
- **Extension:** Install [Glider](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj) from the Chrome Web Store in each browser/profile you plan to automate
39
+ ---
57
40
 
58
- | | Browser | Config |
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
- ```json
114
- {
115
- "use": "arc"
116
- }
43
+ ```bash
44
+ npm i -g glidercli
45
+ glider install
46
+ glider connect
117
47
  ```
118
48
 
119
- Registry is loaded from: `$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
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
- **Option B- Explicit name/path:**
56
+ Node 18+. Chromium-based browser with the extension enabled (see Browsers).
122
57
 
123
- | Field | Required | Description |
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
- \* Omit `name` when using `use` (registry key).
60
+ ## Browsers
130
61
 
131
- **Example:**
62
+ Extension + relay model uses Chromium + Glider extension from Chrome Web Store in the same profile as `glider connect`.
132
63
 
133
- ```json
134
- {
135
- "name": "Arc",
136
- "path": "/Applications/Arc.app",
137
- "processName": "Arc"
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
- **By browser:**
72
+ Not supported today: Firefox/Safari/WebKit/Gecko, DuckDuckGo, browsers without Chrome Web Store extension path.
142
73
 
143
- | Browser | `name` | `path` (optional) | `processName` (optional) |
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
- Check app name in Finder/Spotlight, process name: `ps aux | grep -i <name>`
76
+ Priority: `~/.glider/config/browser.json` default Google Chrome.
150
77
 
151
- ### Browser registry (keymap)
78
+ Registry key (recommended):
152
79
 
153
- A single registry file can define all Chromium browsers, Glider picks one by **key**
80
+ ```json
81
+ { "use": "arc" }
82
+ ```
154
83
 
155
- **Registry location:**
84
+ Registry file: `~/.glider/config/browsers-registry.json`
156
85
 
157
- - `$HOME/.glider/config/browsers-registry.json`
86
+ ```bash
87
+ glider use arc
88
+ glider browser
89
+ ```
158
90
 
159
- **Registry format:**
91
+ Explicit name/path:
160
92
 
161
93
  ```json
162
94
  {
163
- "version": "1.0",
164
- "registry": {
165
- "arc": { "name": "Arc", "path": "/Applications/Arc.app", "processName": "Arc" },
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` | Set `$HOME/.glider/config/browser.json` to `{ "use": "arc" }` (resolved from registry). |
178
- | `glider use brave` | Switch to Brave. |
179
- | `glider use` | Show current key and list of registry keys. |
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
- ### Platform
107
+ macOS: `open -a` / AppleScript. Linux/Windows: partial, on roadmap.
185
108
 
186
- | Platform | Behavior |
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
- ### Browser summary
111
+ ## Task files
192
112
 
193
- | Topic | Detail |
194
- |-------|--------|
195
- | Supported | Chromium-based + Chrome Web Store extension (see table above). |
196
- | Not supported | See **Future** in this README. |
197
- | Configure | `$HOME/.glider/config/browser.json` (use key or name/path). Registry: `$HOME/.glider/config/browsers-registry.json` |
198
- | Switch | `glider use <key>` (e.g. `glider use arc`, `glider use brave`). |
199
- | Path | Optional, use when app is not in default location |
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://reddit.com"
129
+ glider goto "https://news.ycombinator.com"
209
130
  glider eval "document.title"
210
- glider run task.yaml
211
- glider loop task.yaml -n 50
131
+ glider run `hn-scrape.yaml`
132
+ glider loop `hn-scrape.yaml` -n 50 -m hn_scrape_done
212
133
  ```
213
134
 
214
- | Daemon | Logs |
135
+ ```bash
136
+ # per-host capture hints (optional)
137
+ glider resolve https://news.ycombinator.com --json
138
+ ```
139
+
140
+ | Output | Path |
215
141
  |--------|------|
216
- | `glider install` / `glider uninstall` | `~/.glider/daemon.log` |
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
- ## Task files
156
+ ## Gotchas
221
157
 
222
- ```yaml
223
- name: "Reddit"
224
- steps:
225
- - goto: "https://reddit.com"
226
- - wait: 2
227
- - eval: "document.title"
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` | Install daemon (relay at login) |
238
- | `glider uninstall` | Remove daemon |
239
- | `glider connect` | Connect to browser |
240
- | `glider status` | Server / extension / tabs |
241
- | `glider browser` | Show browser config (name, path) |
242
- | `glider goto <url>` | Navigate |
243
- | `glider eval <js>` | Run JS in page |
244
- | `glider click <sel>` | Click element |
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
- ## Docs
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
- - [x] CDP relay + extension, YAML tasks, loop, daemon, multi-tab
266
- - [ ] Linux / Windows
267
- - [ ] headless (cloud)
268
- - [ ] task chaining
269
- - [ ] crawling templates
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
- <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>
197
+ [![`vd7.io`](https://res.cloudinary.com/ddyc1es5v/image/upload/v1773910810/readme-badges/readme-badge-vd7.png)](https://vd7.io)
198
+
199
+ [![`@vdutts7`](https://res.cloudinary.com/ddyc1es5v/image/upload/v1773910817/readme-badges/readme-badge-x.png)](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> Resolve host to local warch intel ${DIM}(--json)${NC}
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-01-31"
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": "$CURREGISTRY/glider/domains.template.json",
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
 
@@ -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
- const DOMAIN_CONFIG_PATHS = [
9
- path.join(os.homedir(), '.glider', 'config', 'domains.json'),
10
- path.join(os.homedir(), '.glider', 'domains.json'),
11
- ];
12
-
13
- function warchRoot() {
14
- const base = process.env.CURREGISTRY || path.join(os.homedir(), '.cursor', 'registry');
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 DOMAIN_CONFIG_PATHS) {
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
- let indexHit = null;
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: indexHit,
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 = { resolveDomain, hostFromUrl, warchRoot, loadDomainsIndex };
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.10",
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",