glidercli 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/glider.js +186 -5
- package/lib/bcdp.js +482 -0
- package/lib/beval.js +78 -0
- package/lib/bserve.js +311 -0
- package/package.json +8 -2
- package/.git-personal-enforced +0 -4
- package/.github/hooks/post-checkout +0 -24
- package/.github/hooks/post-commit +0 -13
- package/.github/hooks/pre-commit +0 -30
- package/.github/hooks/pre-push +0 -13
- package/.github/scripts/health-check.sh +0 -127
- package/.github/scripts/setup.sh +0 -19
- package/.github/workflows/release.yml +0 -19
- package/assets/icons/.gitkeep +0 -0
- package/assets/icons/claude.webp +0 -0
- package/assets/icons/glider-blue-squircle.webp +0 -0
- package/assets/icons/ralph-wiggum.webp +0 -0
- package/repo.config.json +0 -31
package/bin/glider.js
CHANGED
|
@@ -32,7 +32,7 @@ const YAML = require('yaml');
|
|
|
32
32
|
// Config
|
|
33
33
|
const PORT = process.env.GLIDER_PORT || 19988;
|
|
34
34
|
const SERVER_URL = `http://127.0.0.1:${PORT}`;
|
|
35
|
-
const
|
|
35
|
+
const LIB_DIR = path.join(__dirname, '..', 'lib');
|
|
36
36
|
const STATE_FILE = '/tmp/glider-state.json';
|
|
37
37
|
const LOG_FILE = '/tmp/glider.log';
|
|
38
38
|
|
|
@@ -213,7 +213,7 @@ async function cmdStart() {
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
log.info('Starting glider server...');
|
|
216
|
-
const bserve = path.join(
|
|
216
|
+
const bserve = path.join(LIB_DIR, 'bserve.js');
|
|
217
217
|
|
|
218
218
|
if (!fs.existsSync(bserve)) {
|
|
219
219
|
log.fail(`bserve not found at ${bserve}`);
|
|
@@ -401,6 +401,151 @@ async function cmdText() {
|
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
405
|
+
// NEW COMMANDS: restart, test, tabs, domains, open, html, title, url
|
|
406
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
407
|
+
|
|
408
|
+
async function cmdRestart() {
|
|
409
|
+
await cmdStop();
|
|
410
|
+
await new Promise(r => setTimeout(r, 500));
|
|
411
|
+
await cmdStart();
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async function cmdTest() {
|
|
415
|
+
showBanner();
|
|
416
|
+
console.log('═══════════════════════════════════════');
|
|
417
|
+
console.log(' GLIDER TEST');
|
|
418
|
+
console.log('═══════════════════════════════════════');
|
|
419
|
+
|
|
420
|
+
// Test 1: Server
|
|
421
|
+
const serverOk = await checkServer();
|
|
422
|
+
console.log(serverOk ? `${GREEN}[1/4]${NC} Server: OK` : `${RED}[1/4]${NC} Server: FAIL`);
|
|
423
|
+
if (!serverOk) {
|
|
424
|
+
log.info('Starting server...');
|
|
425
|
+
await cmdStart();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Test 2: Extension
|
|
429
|
+
const extOk = await checkExtension();
|
|
430
|
+
console.log(extOk ? `${GREEN}[2/4]${NC} Extension: OK` : `${RED}[2/4]${NC} Extension: NOT CONNECTED`);
|
|
431
|
+
|
|
432
|
+
// Test 3: Tab
|
|
433
|
+
const tabOk = await checkTab();
|
|
434
|
+
console.log(tabOk ? `${GREEN}[3/4]${NC} Tab: OK` : `${RED}[3/4]${NC} Tab: NO TABS`);
|
|
435
|
+
|
|
436
|
+
// Test 4: CDP command
|
|
437
|
+
if (tabOk) {
|
|
438
|
+
try {
|
|
439
|
+
const result = await httpPost('/cdp', {
|
|
440
|
+
method: 'Runtime.evaluate',
|
|
441
|
+
params: { expression: '1+1', returnByValue: true }
|
|
442
|
+
});
|
|
443
|
+
const cdpOk = result.result?.value === 2;
|
|
444
|
+
console.log(cdpOk ? `${GREEN}[4/4]${NC} CDP: OK` : `${RED}[4/4]${NC} CDP: FAIL`);
|
|
445
|
+
} catch {
|
|
446
|
+
console.log(`${RED}[4/4]${NC} CDP: FAIL`);
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
console.log(`${YELLOW}[4/4]${NC} CDP: SKIPPED (no tab)`);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
console.log('═══════════════════════════════════════');
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
async function cmdTabs() {
|
|
456
|
+
const targets = await getTargets();
|
|
457
|
+
if (targets.length === 0) {
|
|
458
|
+
log.warn('No tabs connected');
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
console.log(`${GREEN}${targets.length}${NC} tab(s) connected:\n`);
|
|
462
|
+
targets.forEach((t, i) => {
|
|
463
|
+
const url = t.targetInfo?.url || 'unknown';
|
|
464
|
+
const title = t.targetInfo?.title || '';
|
|
465
|
+
console.log(` ${CYAN}[${i + 1}]${NC} ${title}`);
|
|
466
|
+
console.log(` ${DIM}${url}${NC}`);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
async function cmdDomains() {
|
|
471
|
+
const domainKeys = Object.keys(DOMAINS);
|
|
472
|
+
if (domainKeys.length === 0) {
|
|
473
|
+
log.warn('No domains configured');
|
|
474
|
+
log.info('Add domains to ~/.cursor/glider/domains.json or ~/.glider/domains.json');
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
console.log(`${GREEN}${domainKeys.length}${NC} domain(s) configured:\n`);
|
|
478
|
+
for (const key of domainKeys) {
|
|
479
|
+
const d = DOMAINS[key];
|
|
480
|
+
const type = d.script ? 'script' : 'url';
|
|
481
|
+
const target = d.script || d.url || '';
|
|
482
|
+
console.log(` ${CYAN}${key}${NC} ${DIM}(${type})${NC}`);
|
|
483
|
+
if (d.description) console.log(` ${d.description}`);
|
|
484
|
+
console.log(` ${DIM}${target}${NC}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async function cmdOpen(url) {
|
|
489
|
+
if (!url) {
|
|
490
|
+
log.fail('Usage: glider open <url>');
|
|
491
|
+
process.exit(1);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Open URL in default browser (not in connected tab)
|
|
495
|
+
const { exec } = require('child_process');
|
|
496
|
+
const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
497
|
+
exec(`${cmd} "${url}"`, (err) => {
|
|
498
|
+
if (err) {
|
|
499
|
+
log.fail(`Failed to open: ${err.message}`);
|
|
500
|
+
process.exit(1);
|
|
501
|
+
}
|
|
502
|
+
log.ok(`Opened: ${url}`);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
async function cmdHtml(selector) {
|
|
507
|
+
try {
|
|
508
|
+
const expression = selector
|
|
509
|
+
? `document.querySelector('${selector.replace(/'/g, "\\'")}')?.outerHTML || 'Element not found'`
|
|
510
|
+
: 'document.documentElement.outerHTML';
|
|
511
|
+
|
|
512
|
+
const result = await httpPost('/cdp', {
|
|
513
|
+
method: 'Runtime.evaluate',
|
|
514
|
+
params: { expression, returnByValue: true }
|
|
515
|
+
});
|
|
516
|
+
console.log(result.result?.value || '');
|
|
517
|
+
} catch (e) {
|
|
518
|
+
log.fail(`HTML extraction failed: ${e.message}`);
|
|
519
|
+
process.exit(1);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async function cmdTitle() {
|
|
524
|
+
try {
|
|
525
|
+
const result = await httpPost('/cdp', {
|
|
526
|
+
method: 'Runtime.evaluate',
|
|
527
|
+
params: { expression: 'document.title', returnByValue: true }
|
|
528
|
+
});
|
|
529
|
+
console.log(result.result?.value || '');
|
|
530
|
+
} catch (e) {
|
|
531
|
+
log.fail(`Title extraction failed: ${e.message}`);
|
|
532
|
+
process.exit(1);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async function cmdUrl() {
|
|
537
|
+
try {
|
|
538
|
+
const result = await httpPost('/cdp', {
|
|
539
|
+
method: 'Runtime.evaluate',
|
|
540
|
+
params: { expression: 'window.location.href', returnByValue: true }
|
|
541
|
+
});
|
|
542
|
+
console.log(result.result?.value || '');
|
|
543
|
+
} catch (e) {
|
|
544
|
+
log.fail(`URL extraction failed: ${e.message}`);
|
|
545
|
+
process.exit(1);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
404
549
|
// YAML Task Runner
|
|
405
550
|
async function cmdRun(taskFile) {
|
|
406
551
|
if (!taskFile || !fs.existsSync(taskFile)) {
|
|
@@ -665,19 +810,31 @@ ${YELLOW}SERVER:${NC}
|
|
|
665
810
|
status Check server, extension, tabs
|
|
666
811
|
start Start relay server
|
|
667
812
|
stop Stop relay server
|
|
813
|
+
restart Stop then start relay server
|
|
814
|
+
test Run connectivity test
|
|
668
815
|
|
|
669
816
|
${YELLOW}NAVIGATION:${NC}
|
|
670
817
|
goto <url> Navigate current tab to URL
|
|
818
|
+
open <url> Open URL in default browser
|
|
671
819
|
eval <js> Execute JavaScript, return result
|
|
672
820
|
click <selector> Click element
|
|
673
821
|
type <sel> <text> Type into input
|
|
674
822
|
screenshot [path] Take screenshot
|
|
823
|
+
|
|
824
|
+
${YELLOW}PAGE INFO:${NC}
|
|
675
825
|
text Get page text content
|
|
826
|
+
html [selector] Get page HTML (or element HTML)
|
|
827
|
+
title Get page title
|
|
828
|
+
url Get current URL
|
|
829
|
+
tabs List connected tabs
|
|
676
830
|
|
|
677
831
|
${YELLOW}AUTOMATION:${NC}
|
|
678
832
|
run <task.yaml> Execute YAML task file
|
|
679
833
|
loop <task> [opts] Run in Ralph Wiggum loop until complete
|
|
680
834
|
|
|
835
|
+
${YELLOW}CONFIG:${NC}
|
|
836
|
+
domains List configured domain shortcuts
|
|
837
|
+
|
|
681
838
|
${YELLOW}LOOP OPTIONS:${NC}
|
|
682
839
|
-n, --max-iterations N Max iterations (default: 10)
|
|
683
840
|
-t, --timeout N Max runtime in seconds (default: 3600)
|
|
@@ -700,6 +857,7 @@ ${YELLOW}EXAMPLES:${NC}
|
|
|
700
857
|
glider start
|
|
701
858
|
glider goto "https://google.com"
|
|
702
859
|
glider eval "document.title"
|
|
860
|
+
glider html "div.main"
|
|
703
861
|
glider run mytask.yaml
|
|
704
862
|
glider loop mytask.yaml -n 20 -t 600
|
|
705
863
|
|
|
@@ -712,7 +870,6 @@ ${YELLOW}RALPH WIGGUM PATTERN:${NC}
|
|
|
712
870
|
|
|
713
871
|
${YELLOW}REQUIREMENTS:${NC}
|
|
714
872
|
- Node.js 18+
|
|
715
|
-
- bserve relay server (~/scripts/bserve)
|
|
716
873
|
- Glider Chrome extension connected
|
|
717
874
|
|
|
718
875
|
${YELLOW}DOMAIN EXTENSIONS:${NC}
|
|
@@ -721,8 +878,8 @@ ${YELLOW}DOMAIN EXTENSIONS:${NC}
|
|
|
721
878
|
"mysite": { "url": "https://mysite.com/dashboard" },
|
|
722
879
|
"mytool": { "script": "~/.cursor/tools/scripts/mytool.sh" }
|
|
723
880
|
}
|
|
724
|
-
Then: glider mysite
|
|
725
|
-
glider mytool
|
|
881
|
+
Then: glider mysite -> navigates to that URL
|
|
882
|
+
glider mytool -> runs that script
|
|
726
883
|
`);
|
|
727
884
|
|
|
728
885
|
// Show loaded domains if any
|
|
@@ -766,10 +923,25 @@ async function main() {
|
|
|
766
923
|
case 'stop':
|
|
767
924
|
await cmdStop();
|
|
768
925
|
break;
|
|
926
|
+
case 'restart':
|
|
927
|
+
await cmdRestart();
|
|
928
|
+
break;
|
|
929
|
+
case 'test':
|
|
930
|
+
await cmdTest();
|
|
931
|
+
break;
|
|
932
|
+
case 'tabs':
|
|
933
|
+
await cmdTabs();
|
|
934
|
+
break;
|
|
935
|
+
case 'domains':
|
|
936
|
+
await cmdDomains();
|
|
937
|
+
break;
|
|
769
938
|
case 'goto':
|
|
770
939
|
case 'navigate':
|
|
771
940
|
await cmdGoto(args[1]);
|
|
772
941
|
break;
|
|
942
|
+
case 'open':
|
|
943
|
+
await cmdOpen(args[1]);
|
|
944
|
+
break;
|
|
773
945
|
case 'eval':
|
|
774
946
|
case 'js':
|
|
775
947
|
await cmdEval(args.slice(1).join(' '));
|
|
@@ -786,6 +958,15 @@ async function main() {
|
|
|
786
958
|
case 'text':
|
|
787
959
|
await cmdText();
|
|
788
960
|
break;
|
|
961
|
+
case 'html':
|
|
962
|
+
await cmdHtml(args[1]);
|
|
963
|
+
break;
|
|
964
|
+
case 'title':
|
|
965
|
+
await cmdTitle();
|
|
966
|
+
break;
|
|
967
|
+
case 'url':
|
|
968
|
+
await cmdUrl();
|
|
969
|
+
break;
|
|
789
970
|
case 'run':
|
|
790
971
|
await cmdRun(args[1]);
|
|
791
972
|
break;
|