glidercli 0.3.4 → 0.3.6

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
@@ -15,173 +15,110 @@
15
15
 
16
16
  <br/>
17
17
 
18
- ## ToC
19
-
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>
31
-
32
- <br/>
33
-
34
18
  ## About
35
19
 
36
- Control Chrome from terminal. Run YAML tasks. Loop until complete (Ralph Wiggum pattern).
20
+ | | |
21
+ |---|---|
22
+ | **What** | Control a Chromium-based browser from the terminal via CDP; run YAML tasks; loop until done (Ralph Wiggum pattern). |
23
+ | **CDP** | Chrome DevTools Protocol via relay + browser extension |
24
+ | **Tasks** | Declarative steps: `goto`, `click`, `explore`, `eval`, `screenshot` |
25
+ | **Loops** | Run until completion marker or max iterations / timeout |
26
+ | **Safety** | Max iterations, timeout, backoff |
37
27
 
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
28
+ ---
42
29
 
43
30
  ## Install
44
31
 
45
- **One-liner:**
46
- ```bash
47
- npm i -g glidercli && open "https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj"
48
- ```
32
+ | Step | Action |
33
+ |------|--------|
34
+ | **1. CLI** | `npm i -g glidercli` |
35
+ | **2. Extension** | [Install Glider from Chrome Web Store](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj) (required; bridges relay ↔ tab). |
36
+ | **3. Daemon** | `glider install` then `glider connect` |
37
+ | **4. (Optional) Browser** | Default: Chrome. For Arc/Edge/Brave: [BROWSERS.md](docs/BROWSERS.md) or `export GLIDER_BROWSER=Arc` |
49
38
 
50
- **Then:**
51
- ```bash
52
- glider install # start daemon (runs forever, auto-restarts)
53
- glider connect # connect to Chrome
54
- ```
55
39
 
56
- **Update anytime:**
57
- ```bash
58
- glider update # pulls latest from npm
59
- ```
60
-
61
- ### Requirements
40
+ ## Requirements
62
41
 
63
- 1. **Node 18+**
42
+ | Requirement | Minimum |
43
+ |-------------|---------|
44
+ | Node | 18+ |
45
+ | Browser | Chromium-based (Chrome, Arc, Edge, Brave, Opera, Vivaldi, DuckDuckGo). No Firefox/Safari → [BROWSERS.md](docs/BROWSERS.md) |
64
46
 
65
- 2. **Glider Chrome extension** - [Install from Chrome Web Store](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj)
47
+ ---
66
48
 
67
49
  ## Usage
68
50
 
69
51
  ```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
76
- ```
77
-
78
- ### Daemon
79
-
80
- The daemon keeps the relay server running 24/7. Auto-restarts on crash.
81
-
82
- ```bash
83
- glider install # install daemon (runs at login)
84
- glider uninstall # remove daemon
52
+ glider connect
53
+ glider status
54
+ glider goto "https://reddit.com"
55
+ glider eval "document.title"
56
+ glider run task.yaml
57
+ glider loop task.yaml -n 50
85
58
  ```
86
59
 
87
- Logs: `~/.glider/daemon.log`
60
+ | Daemon | Logs |
61
+ |--------|------|
62
+ | `glider install` / `glider uninstall` | `~/.glider/daemon.log` |
88
63
 
89
- ## The loop
90
-
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
95
-
96
- ```bash
97
- glider loop scrape-feed.yaml -n 100 -t 3600
98
- glider ralph task.yaml # same thing
99
- ```
100
-
101
- Safety: max iterations, timeout, exponential backoff on errors, state persistence.
64
+ ---
102
65
 
103
66
  ## Task files
104
67
 
105
68
  ```yaml
106
- name: "Get timeline"
69
+ name: "Reddit"
107
70
  steps:
108
- - goto: "https://x.com/home"
109
- - wait: 3
110
- - eval: "document.querySelectorAll('article').length"
111
- - screenshot: "/tmp/timeline.png"
71
+ - goto: "https://reddit.com"
72
+ - wait: 2
73
+ - eval: "document.title"
74
+ - screenshot: "/tmp/out.png"
112
75
  ```
113
76
 
77
+ ---
78
+
114
79
  ## Commands
115
80
 
116
- ### Setup
117
- | Command | What |
118
- |---------|------|
119
- | `glider install` | Install daemon (runs at login) |
81
+ | Command | Description |
82
+ |---------|-------------|
83
+ | `glider install` | Install daemon (relay at login) |
120
84
  | `glider uninstall` | Remove daemon |
121
- | `glider update` | Update to latest version |
122
85
  | `glider connect` | Connect to browser |
123
- | `glider status` | Server/extension/tab status |
124
- | `glider test` | Run diagnostics |
125
-
126
- ### Navigation
127
- | Command | What |
128
- |---------|------|
86
+ | `glider status` | Server / extension / tabs |
87
+ | `glider browser` | Show browser config (name, path) |
129
88
  | `glider goto <url>` | Navigate |
130
- | `glider eval <js>` | Execute JavaScript |
89
+ | `glider eval <js>` | Run JS in page |
131
90
  | `glider click <sel>` | Click element |
132
91
  | `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
- |---------|------|
92
+ | `glider screenshot [path]` | Capture page |
149
93
  | `glider run <file>` | Run YAML task |
150
- | `glider loop <file>` | Autonomous loop |
151
- | `glider ralph <file>` | Alias for loop |
94
+ | `glider loop <file> [-n N]` | Loop until done or limit |
95
+
96
+ Full list: `glider --help`.
97
+
98
+ ---
99
+
100
+ ## Docs
101
+
102
+ | Doc | Contents |
103
+ |-----|----------|
104
+ | This README | Install, usage, commands |
105
+ | [docs/BROWSERS.md](docs/BROWSERS.md) | Which browsers work; browser name/path (env or `~/.glider/config/browser.json`) |
106
+ | [config/browser.json.example](config/browser.json.example) | Example browser config |
107
+
108
+ ---
152
109
 
153
110
  ## Roadmap
154
111
 
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]
112
+ | Status | Area |
113
+ |--------|------|
114
+ | Done | CDP relay + extension, YAML tasks, loop, daemon, multi-tab |
115
+ | Todo | Linux / Windows, headless, task chaining, scraping templates |
179
116
 
180
- ## Contact
117
+ ---
181
118
 
119
+ ## Contact
182
120
 
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>
121
+ <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
122
 
186
123
 
187
124
  <!-- BADGES -->
@@ -189,15 +126,3 @@ steps:
189
126
  [github-url]: https://github.com/vdutts7/glidercli
190
127
  [npm]: https://img.shields.io/badge/npm%20i%20--g%20glidercli-CB3837?style=for-the-badge&logo=npm
191
128
  [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,56 @@ 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
+ process.env.GLIDER_BROWSERS_REGISTRY,
86
+ path.join(os.homedir(), '.cursor', 'registry', 'browsers.json'),
87
+ path.join(os.homedir(), '.glider', 'config', 'browsers-registry.json'),
88
+ ].filter(Boolean);
89
+ let BROWSERS_REGISTRY = {};
90
+ for (const regPath of BROWSERS_REGISTRY_PATHS) {
91
+ if (regPath && fs.existsSync(regPath)) {
92
+ try {
93
+ const data = JSON.parse(fs.readFileSync(regPath, 'utf8'));
94
+ BROWSERS_REGISTRY = data.registry || data;
95
+ break;
96
+ } catch (e) { /* ignore */ }
97
+ }
98
+ }
99
+
100
+ function getBrowserConfig() {
101
+ let name = process.env.GLIDER_BROWSER || BROWSER_CONFIG.name;
102
+ let pathOrNull = process.env.GLIDER_BROWSER_PATH || BROWSER_CONFIG.path || null;
103
+ let processName = process.env.GLIDER_BROWSER_PROCESS || BROWSER_CONFIG.processName;
104
+
105
+ // Key-based lookup: browser.json has { "use": "arc" } → resolve from registry
106
+ if (!name && BROWSER_CONFIG.use && BROWSERS_REGISTRY[BROWSER_CONFIG.use]) {
107
+ const entry = BROWSERS_REGISTRY[BROWSER_CONFIG.use];
108
+ name = entry.name;
109
+ pathOrNull = entry.path != null ? entry.path : null;
110
+ processName = entry.processName || entry.name;
111
+ }
112
+
113
+ name = name || 'Google Chrome';
114
+ processName = processName || name;
115
+ return { name, path: pathOrNull, processName };
116
+ }
117
+
69
118
  // Colors - matching the deep blue gradient logo
70
119
  const RED = '\x1b[31m';
71
120
  const GREEN = '\x1b[32m';
@@ -242,7 +291,7 @@ async function ensureConnected() {
242
291
 
243
292
  if (!await checkExtension()) {
244
293
  log.fail('Extension not connected - make sure Glider extension is installed');
245
- log.info('Install from: chrome://extensions Load unpacked → ~/glider-crx/glider/');
294
+ log.info('Install extension from Chrome Web Store: https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj');
246
295
  return false;
247
296
  }
248
297
 
@@ -621,7 +670,7 @@ async function cmdUninstallDaemon() {
621
670
  }
622
671
 
623
672
  async function cmdConnect() {
624
- // Bulletproof connect: relay + Chrome + trigger attach via HTTP
673
+ // Bulletproof connect: relay + browser + trigger attach via HTTP
625
674
  log.info('Connecting...');
626
675
 
627
676
  // 1. Ensure relay is running
@@ -630,12 +679,17 @@ async function cmdConnect() {
630
679
  await new Promise(r => setTimeout(r, 1000));
631
680
  }
632
681
 
633
- // 2. Ensure Chrome is running
682
+ // 2. Ensure browser is running (see getBrowserConfig + docs/BROWSERS.md)
683
+ const browser = getBrowserConfig();
634
684
  try {
635
- execSync('pgrep -x "Google Chrome"', { stdio: 'ignore' });
685
+ execSync(`pgrep -x "${browser.processName}"`, { stdio: 'ignore' });
636
686
  } catch {
637
- log.info('Starting Chrome...');
638
- execSync('open -a "Google Chrome"');
687
+ log.info(`Starting ${browser.name}...`);
688
+ if (browser.path) {
689
+ execSync(`open "${browser.path}"`, { stdio: 'ignore' });
690
+ } else {
691
+ execSync(`open -a "${browser.name}"`);
692
+ }
639
693
  await new Promise(r => setTimeout(r, 3000));
640
694
  }
641
695
 
@@ -647,7 +701,7 @@ async function cmdConnect() {
647
701
 
648
702
  if (!await checkExtension()) {
649
703
  log.fail('Extension not connected to relay');
650
- log.info('Make sure Glider extension is installed in Chrome');
704
+ log.info(`Make sure Glider extension is installed in ${browser.name} (Chromium-based only; see glider docs/BROWSERS.md)`);
651
705
  process.exit(1);
652
706
  }
653
707
  log.ok('Extension connected');
@@ -665,18 +719,18 @@ async function cmdConnect() {
665
719
  return;
666
720
  }
667
721
 
668
- // 5. Ensure we have a real tab (not chrome://)
722
+ // 5. Ensure we have a real tab (not chrome:// or arc://)
669
723
  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://')) {
724
+ const tabUrl = execSync(`osascript -e 'tell application "${browser.name}" to return URL of active tab of front window'`).toString().trim();
725
+ if (tabUrl.startsWith('chrome://') || tabUrl.startsWith('chrome-extension://') || tabUrl.startsWith('arc://')) {
672
726
  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"}'`);
727
+ execSync(`osascript -e 'tell application "${browser.name}" to make new tab at front window with properties {URL:"https://google.com"}'`);
674
728
  await new Promise(r => setTimeout(r, 2000));
675
729
  }
676
730
  } catch {
677
731
  // No window, create one
678
732
  log.info('Creating new window...');
679
- execSync(`osascript -e 'tell application "Google Chrome" to make new window with properties {URL:"https://google.com"}'`);
733
+ execSync(`osascript -e 'tell application "${browser.name}" to make new window with properties {URL:"https://google.com"}'`);
680
734
  await new Promise(r => setTimeout(r, 2000));
681
735
  }
682
736
 
@@ -700,7 +754,7 @@ async function cmdConnect() {
700
754
 
701
755
  // 7. Fallback: create fresh tab and retry
702
756
  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"}'`);
757
+ execSync(`osascript -e 'tell application "${browser.name}" to make new tab at front window with properties {URL:"https://google.com"}'`);
704
758
  await new Promise(r => setTimeout(r, 2000));
705
759
 
706
760
  try {
@@ -717,13 +771,13 @@ async function cmdConnect() {
717
771
  }
718
772
  } catch {}
719
773
 
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'`);
774
+ // 8. Need manual click - activate browser and show instructions
775
+ log.warn(`Click the Glider extension icon in ${browser.name}`);
776
+ console.log(` ${B5}(on any real webpage, not chrome:// or arc:// pages)${NC}`);
777
+ execSync(`osascript -e 'tell application "${browser.name}" to activate'`);
724
778
 
725
779
  // 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);
780
+ notify('Glider', `Click the extension icon in ${browser.name} to connect`, true);
727
781
 
728
782
  // Wait for user to click
729
783
  log.info('Waiting for connection...');
@@ -745,6 +799,40 @@ async function cmdConnect() {
745
799
  log.info('Make sure you clicked the extension icon on a real webpage');
746
800
  }
747
801
 
802
+ function cmdBrowser() {
803
+ const b = getBrowserConfig();
804
+ console.log('Browser config (used by glider connect):');
805
+ console.log(` name: ${b.name}`);
806
+ console.log(` path: ${b.path || '(default launch via name)'}`);
807
+ console.log(` processName: ${b.processName}`);
808
+ if (BROWSER_CONFIG.use) {
809
+ console.log(` use: ${BROWSER_CONFIG.use} ${DIM}(from registry)${NC}`);
810
+ }
811
+ console.log('');
812
+ console.log('Source: GLIDER_BROWSER* env → ~/.glider/config/browser.json { "use": "<key>" } or { name, path } → default "Google Chrome"');
813
+ console.log('Registry: GLIDER_BROWSERS_REGISTRY or ~/.cursor/registry/browsers.json. Keys: ' + Object.keys(BROWSERS_REGISTRY).join(', ') || '(none loaded)');
814
+ console.log('See docs/BROWSERS.md for compatibility and examples.');
815
+ }
816
+
817
+ function cmdUse(key) {
818
+ if (!key) {
819
+ console.log('Usage: glider use <key>');
820
+ console.log('Keys in registry: ' + (Object.keys(BROWSERS_REGISTRY).length ? Object.keys(BROWSERS_REGISTRY).join(', ') : '(no registry loaded)'));
821
+ if (BROWSER_CONFIG.use) console.log('Current: ' + BROWSER_CONFIG.use);
822
+ return;
823
+ }
824
+ if (!BROWSERS_REGISTRY[key]) {
825
+ console.error('Unknown key: ' + key + '. Available: ' + Object.keys(BROWSERS_REGISTRY).join(', '));
826
+ process.exit(1);
827
+ }
828
+ const configDir = path.join(os.homedir(), '.glider', 'config');
829
+ const browserPath = path.join(configDir, 'browser.json');
830
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
831
+ fs.writeFileSync(browserPath, JSON.stringify({ use: key }, null, 2) + '\n');
832
+ console.log('Set browser to: ' + key + ' → ' + BROWSERS_REGISTRY[key].name);
833
+ console.log('Run: glider connect');
834
+ }
835
+
748
836
  async function cmdTest() {
749
837
  showBanner();
750
838
  log.box('DIAGNOSTICS');
@@ -1342,11 +1430,13 @@ async function cmdExplore(url, opts = []) {
1342
1430
  let depth = 2;
1343
1431
  let outputDir = '/tmp/glider-explore';
1344
1432
  let harFile = null;
1433
+ let sessionId = null;
1345
1434
 
1346
1435
  for (let i = 0; i < opts.length; i++) {
1347
1436
  if (opts[i] === '--depth' || opts[i] === '-d') depth = parseInt(opts[++i], 10);
1348
1437
  else if (opts[i] === '--output' || opts[i] === '-o') outputDir = opts[++i];
1349
1438
  else if (opts[i] === '--har') harFile = opts[++i];
1439
+ else if (opts[i] === '--session-id') sessionId = opts[++i];
1350
1440
  }
1351
1441
 
1352
1442
  log.info(`Exploring: ${url} (depth: ${depth})`);
@@ -1357,6 +1447,7 @@ async function cmdExplore(url, opts = []) {
1357
1447
  const { spawn } = require('child_process');
1358
1448
  const spawnArgs = [bexplorePath, url, '--depth', String(depth), '--output', outputDir];
1359
1449
  if (harFile) spawnArgs.push('--har', harFile);
1450
+ if (sessionId) spawnArgs.push('--session-id', sessionId);
1360
1451
 
1361
1452
  const child = spawn('node', spawnArgs, {
1362
1453
  stdio: 'inherit'
@@ -1659,6 +1750,8 @@ ${B5}SETUP${NC}
1659
1750
 
1660
1751
  ${B5}STATUS${NC}
1661
1752
  ${BW}status${NC} Check server, extension, tabs
1753
+ ${BW}browser${NC} Show browser config ${DIM}(name, path, processName, or use key)${NC}
1754
+ ${BW}use${NC} <key> Set browser by registry key ${DIM}(e.g. arc, brave, chrome)${NC}
1662
1755
  ${BW}test${NC} Run diagnostics
1663
1756
 
1664
1757
  ${B5}NAVIGATION${NC}
@@ -1755,7 +1848,7 @@ ${YELLOW}DOMAIN EXTENSIONS:${NC}
1755
1848
  Add custom domain commands via ~/.glider/config/domains.json:
1756
1849
  {
1757
1850
  "mysite": { "url": "https://mysite.com/dashboard" },
1758
- "mytool": { "script": "~/.cursor/tools/scripts/mytool.sh" }
1851
+ "mytool": { "script": "~/scripts/mytool.sh" }
1759
1852
  }
1760
1853
  Then: glider mysite -> navigates to that URL
1761
1854
  glider mytool -> runs that script
@@ -1887,6 +1980,12 @@ async function main() {
1887
1980
  case 'connect':
1888
1981
  await cmdConnect();
1889
1982
  break;
1983
+ case 'browser':
1984
+ cmdBrowser();
1985
+ break;
1986
+ case 'use':
1987
+ cmdUse(args[1]);
1988
+ break;
1890
1989
  case 'test':
1891
1990
  await cmdTest();
1892
1991
  break;
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "Arc",
3
+ "path": "/Applications/Arc.app",
4
+ "processName": "Arc"
5
+ }
@@ -0,0 +1,185 @@
1
+ # Glider browser support and configuration
2
+
3
+ | | |
4
+ |---|---|
5
+ | **Install / usage** | [README](../README.md) |
6
+ | **How it works** | Chrome extension → WebSocket relay → CDP. Browser must support that extension (Chromium-based). |
7
+
8
+ ---
9
+
10
+ ## Browser support
11
+
12
+ Icons: `https://raw.githubusercontent.com/vdutts7/squircle/main/webp/{slug}.webp` ([squircle](https://github.com/vdutts7/squircle)).
13
+
14
+ **Extension:** Install [Glider](https://chromewebstore.google.com/detail/glider/njbidokkffhgpofcejgcfcgcinmeoalj) from the Chrome Web Store — same for every browser in this table.
15
+
16
+ | | Browser | Config |
17
+ |:---:|--------|--------|
18
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/chrome.webp" width="16" alt=""> | Google Chrome | Default for `glider connect`. |
19
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/arc.webp" width="16" alt=""> | Arc | `GLIDER_BROWSER=Arc` or [browser.json](../config/browser.json.example). |
20
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/microsoft/microsoft-edge.webp" width="16" alt=""> | Microsoft Edge | — |
21
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/brave.webp" width="16" alt=""> | Brave | — |
22
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/opera-gx.webp" width="16" alt=""> | Opera | — |
23
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/vivaldi.webp" width="16" alt=""> | Vivaldi | — |
24
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/duckduckgo.webp" width="16" alt=""> | DuckDuckGo Desktop | — |
25
+ | <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. |
26
+
27
+ See **[Future](#future)** for browsers not supported today.
28
+
29
+ ---
30
+
31
+ ## Future
32
+
33
+ Not supported today: Glider needs a **Chromium-based** browser that can install the extension from the **Chrome Web Store**. No timeline implied; listed for clarity.
34
+
35
+ Same icon base as above: `https://raw.githubusercontent.com/vdutts7/squircle/main/webp/{slug}.webp`.
36
+
37
+ | | Browser | Notes |
38
+ |:---:|--------|--------|
39
+ | <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. |
40
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/librewolf.webp" width="16" alt=""> | LibreWolf | Gecko — same constraints as Firefox. |
41
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/waterfox.webp" width="16" alt=""> | Waterfox | Gecko — same constraints as Firefox. |
42
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/zen.webp" width="16" alt=""> | Zen | Gecko — same constraints as Firefox. |
43
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/floorp.webp" width="16" alt=""> | Floorp | Gecko — same constraints as Firefox. |
44
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/tor-browser.webp" width="16" alt=""> | Tor Browser | Gecko — same constraints as Firefox. |
45
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/mullvad-browser.webp" width="16" alt=""> | Mullvad Browser | Gecko — same constraints as Firefox. |
46
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/icecat.webp" width="16" alt=""> | IceCat | Gecko — same constraints as Firefox. |
47
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/firefox-focus.webp" width="16" alt=""> | Firefox Focus | Gecko — same constraints as Firefox. |
48
+ | <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. |
49
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/safari.webp" width="16" alt=""> | Safari | WebKit (Apple desktop). Not Chromium. |
50
+ | <img src="https://raw.githubusercontent.com/vdutts7/squircle/main/webp/orion.webp" width="16" alt=""> | Orion | WebKit-based desktop browser. Not Chromium. |
51
+ | <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. |
52
+ | <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. |
53
+ | <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. |
54
+ | <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. |
55
+ | <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. |
56
+
57
+ ---
58
+
59
+ ## Configuring the browser
60
+
61
+ **Priority (highest first):** env vars → config file → default `Google Chrome`.
62
+
63
+ ### Environment variables
64
+
65
+ | Variable | Purpose | Example |
66
+ |----------|---------|---------|
67
+ | `GLIDER_BROWSER` | App name (`open -a`, AppleScript) | `Arc`, `Google Chrome`, `Microsoft Edge` |
68
+ | `GLIDER_BROWSER_PATH` | (Optional) Path to app bundle | `/Applications/My Apps/Chrome.app` |
69
+ | `GLIDER_BROWSER_PROCESS` | (Optional) Process name for `pgrep` | Defaults to same as `GLIDER_BROWSER` |
70
+
71
+ **Examples:**
72
+
73
+ | Use case | Command |
74
+ |----------|---------|
75
+ | Arc | `export GLIDER_BROWSER=Arc` then `glider connect` |
76
+ | Custom Chrome path | `export GLIDER_BROWSER="Google Chrome"` and `export GLIDER_BROWSER_PATH="/Applications/My Apps/Google Chrome.app"` |
77
+
78
+ ### Config file: `$HOME/.glider/config/browser.json`
79
+
80
+ Same keys as env, or use a **registry key**. Env overrides file.
81
+
82
+ **Option A — Registry key (recommended):**
83
+
84
+ Set browser by key from the browsers registry. Run `glider use <key>` to write this.
85
+
86
+ ```json
87
+ {
88
+ "use": "arc"
89
+ }
90
+ ```
91
+
92
+ Registry is loaded from (first found): `GLIDER_BROWSERS_REGISTRY` env, `$HOME/.cursor/registry/browsers.json`, `$HOME/.glider/config/browsers-registry.json`. Keys are predefined (e.g. `arc`, `brave`, `chrome`, `edge`, `opera`, `vivaldi`, `duckduckgo`, `chromium`). Edit the registry to add or change paths.
93
+
94
+ **Option B — Explicit name/path:**
95
+
96
+ | Field | Required | Description |
97
+ |-------|:--------:|-------------|
98
+ | `name` | Yes* | App name for `open -a` / AppleScript. Must match system (e.g. `Arc`, `Google Chrome`). |
99
+ | `path` | No | If set, use `open "<path>"` instead of `open -a "<name>"`. For non-default install location. |
100
+ | `processName` | No | For `pgrep -x`. Defaults to `name`. |
101
+
102
+ \* Omit `name` when using `use` (registry key).
103
+
104
+ **Example:**
105
+
106
+ ```json
107
+ {
108
+ "name": "Arc",
109
+ "path": "/Applications/Arc.app",
110
+ "processName": "Arc"
111
+ }
112
+ ```
113
+
114
+ **By browser:**
115
+
116
+ | Browser | `name` | `path` (optional) | `processName` (optional) |
117
+ |---------|--------|-------------------|---------------------------|
118
+ | Arc | `Arc` | `/Applications/Arc.app` | `Arc` |
119
+ | Edge | `Microsoft Edge` | — | `Microsoft Edge` |
120
+ | Chrome (custom) | `Google Chrome` | `/Users/me/Applications/Google Chrome.app` | `Google Chrome` |
121
+ | DuckDuckGo | `DuckDuckGo` | — | `DuckDuckGo` |
122
+
123
+ Check app name in Finder/Spotlight; process name: `ps aux | grep -i <name>`.
124
+
125
+ ---
126
+
127
+ ## Browser registry (keymap)
128
+
129
+ A single registry file can define all Chromium browsers; Glider picks one by key.
130
+
131
+ **Registry location (first found):**
132
+
133
+ - `GLIDER_BROWSERS_REGISTRY` (env, path to JSON file)
134
+ - `$HOME/.cursor/registry/browsers.json`
135
+ - `$HOME/.glider/config/browsers-registry.json`
136
+
137
+ **Registry format:**
138
+
139
+ ```json
140
+ {
141
+ "version": "1.0",
142
+ "registry": {
143
+ "arc": { "name": "Arc", "path": "/Applications/Arc.app", "processName": "Arc" },
144
+ "brave": { "name": "Brave Browser", "path": "/Applications/Brave Browser.app", "processName": "Brave Browser" },
145
+ "chrome": { "name": "Google Chrome", "path": "/Applications/Google Chrome.app", "processName": "Google Chrome" },
146
+ "edge": { "name": "Microsoft Edge", "path": "/Applications/Microsoft Edge.app", "processName": "Microsoft Edge" }
147
+ }
148
+ }
149
+ ```
150
+
151
+ **Commands:**
152
+
153
+ | Command | Effect |
154
+ |---------|--------|
155
+ | `glider use arc` | Set `$HOME/.glider/config/browser.json` to `{ "use": "arc" }` (resolved from registry). |
156
+ | `glider use brave` | Switch to Brave. |
157
+ | `glider use` | Show current key and list of registry keys. |
158
+ | `glider browser` | Show resolved name, path, processName (and `use` key if set). |
159
+
160
+ 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.
161
+
162
+ ---
163
+
164
+ ## Platform
165
+
166
+ | Platform | Behavior |
167
+ |----------|----------|
168
+ | macOS | `open -a "<name>"` or `open "<path>"`; AppleScript for tab/window. `name` = exact app name. |
169
+ | Linux / Windows | Not fully implemented. Future: `path` may be executable. |
170
+
171
+ ---
172
+
173
+ ## Summary
174
+
175
+ | Topic | Detail |
176
+ |-------|--------|
177
+ | Supported | Chromium-based + Chrome Web Store extension (see table above). |
178
+ | Not supported | See [Future](#future). |
179
+ | Configure | `$HOME/.glider/config/browser.json` (use key or name/path) and/or `GLIDER_BROWSER*`. Registry: `$HOME/.cursor/registry/browsers.json` or `GLIDER_BROWSERS_REGISTRY`. |
180
+ | Switch | `glider use <key>` (e.g. `glider use arc`, `glider use brave`). |
181
+ | Path | Optional; use when app is not in default location. |
182
+
183
+ ---
184
+
185
+ [← README](../README.md)
@@ -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 docs/BROWSERS.md",
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();
@@ -1,13 +1,26 @@
1
1
  #!/bin/bash
2
- # Glider daemon - respawns relay forever, fuck launchd throttling
2
+ # Glider daemon - respawns relay forever with log rotation
3
3
 
4
4
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
5
  BSERVE="$SCRIPT_DIR/bserve.js"
6
6
  LOG_DIR="$HOME/.glider"
7
+ LOG_FILE="$LOG_DIR/daemon.log"
7
8
  PID_FILE="$LOG_DIR/daemon.pid"
9
+ MAX_LOG_SIZE=10485760 # 10MB
8
10
 
9
11
  mkdir -p "$LOG_DIR"
10
12
 
13
+ # Rotate log if > 10MB
14
+ rotate_log() {
15
+ if [ -f "$LOG_FILE" ] && [ $(stat -f%z "$LOG_FILE" 2>/dev/null || echo 0) -gt $MAX_LOG_SIZE ]; then
16
+ rm -f "$LOG_FILE.3"
17
+ [ -f "$LOG_FILE.2" ] && mv "$LOG_FILE.2" "$LOG_FILE.3"
18
+ [ -f "$LOG_FILE.1" ] && mv "$LOG_FILE.1" "$LOG_FILE.2"
19
+ mv "$LOG_FILE" "$LOG_FILE.1"
20
+ echo "[$(date)] Log rotated" > "$LOG_FILE"
21
+ fi
22
+ }
23
+
11
24
  # Kill any existing
12
25
  if [ -f "$PID_FILE" ]; then
13
26
  kill $(cat "$PID_FILE") 2>/dev/null
@@ -23,9 +36,10 @@ cleanup() {
23
36
  trap cleanup SIGTERM SIGINT
24
37
 
25
38
  while true; do
26
- echo "[$(date)] Starting relay..." >> "$LOG_DIR/daemon.log"
27
- node "$BSERVE" >> "$LOG_DIR/daemon.log" 2>&1
39
+ rotate_log
40
+ echo "[$(date)] Starting relay..." >> "$LOG_FILE"
41
+ node "$BSERVE" >> "$LOG_FILE" 2>&1
28
42
  EXIT_CODE=$?
29
- echo "[$(date)] Relay exited with code $EXIT_CODE, restarting in 2s..." >> "$LOG_DIR/daemon.log"
43
+ echo "[$(date)] Relay exited with code $EXIT_CODE, restarting in 2s..." >> "$LOG_FILE"
30
44
  sleep 2
31
45
  done
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glidercli",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
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
  ]