omniwire 3.1.1 → 3.1.3
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 +126 -91
- package/dist/mcp/server.js +153 -49
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -350,131 +350,166 @@ watch(assert="ready") poll until
|
|
|
350
350
|
|
|
351
351
|
## All 81 Tools
|
|
352
352
|
|
|
353
|
-
> **Every tool** supports `background: true`
|
|
353
|
+
> **Every tool** supports `background: true` — returns a task ID immediately. Poll with `omniwire_bg`.
|
|
354
354
|
|
|
355
|
-
|
|
355
|
+
<details>
|
|
356
|
+
<summary><b>Execution (6)</b></summary>
|
|
356
357
|
|
|
357
358
|
| Tool | Description |
|
|
358
359
|
|------|-------------|
|
|
359
|
-
| `omniwire_exec` | Run command on any node. `retry`, `assert`, `store_as`, `format:"json"`, `{{key}}`, `via_vpn
|
|
360
|
-
| `omniwire_run` |
|
|
361
|
-
| `omniwire_batch` | N commands in 1 call. Chaining
|
|
362
|
-
| `omniwire_broadcast` | Execute on all nodes simultaneously.
|
|
363
|
-
| `omniwire_pipeline` | Multi-step DAG
|
|
364
|
-
| `omniwire_bg` | List
|
|
360
|
+
| `omniwire_exec` | Run command on any node. `retry`, `assert`, `store_as`, `format:"json"`, `{{key}}`, `via_vpn`. |
|
|
361
|
+
| `omniwire_run` | Multi-line scripts via temp file. |
|
|
362
|
+
| `omniwire_batch` | N commands in 1 call. Chaining `{{prev}}`, `abort_on_fail`, parallel/sequential. |
|
|
363
|
+
| `omniwire_broadcast` | Execute on all nodes simultaneously. |
|
|
364
|
+
| `omniwire_pipeline` | Multi-step DAG with `{{prev}}`/`{{stepN}}` interpolation. |
|
|
365
|
+
| `omniwire_bg` | List/poll/retrieve background task results. |
|
|
365
366
|
|
|
366
|
-
|
|
367
|
+
</details>
|
|
368
|
+
|
|
369
|
+
<details>
|
|
370
|
+
<summary><b>Agentic / A2A (12)</b></summary>
|
|
367
371
|
|
|
368
372
|
| Tool | Description |
|
|
369
373
|
|------|-------------|
|
|
370
|
-
| `omniwire_store` | Session key-value store
|
|
371
|
-
| `omniwire_watch` | Poll
|
|
372
|
-
| `omniwire_healthcheck` | Parallel health probe
|
|
373
|
-
| `omniwire_agent_task` |
|
|
374
|
-
| `omniwire_a2a_message` | Agent-to-agent message queues
|
|
375
|
-
| `omniwire_semaphore` | Distributed locking
|
|
376
|
-
| `omniwire_event` | Pub/sub events
|
|
377
|
-
| `omniwire_workflow` |
|
|
378
|
-
| `omniwire_agent_registry` |
|
|
379
|
-
| `omniwire_blackboard` | Shared blackboard for
|
|
380
|
-
| `omniwire_task_queue` | Distributed
|
|
381
|
-
| `omniwire_capability` | Query node capabilities
|
|
382
|
-
|
|
383
|
-
|
|
374
|
+
| `omniwire_store` | Session key-value store for cross-call chaining. |
|
|
375
|
+
| `omniwire_watch` | Poll until assert matches — deploys, builds, readiness. |
|
|
376
|
+
| `omniwire_healthcheck` | Parallel health probe all nodes (disk, mem, load, docker). |
|
|
377
|
+
| `omniwire_agent_task` | Background task dispatch with poll/retrieve. |
|
|
378
|
+
| `omniwire_a2a_message` | Agent-to-agent message queues (send/receive/peek). |
|
|
379
|
+
| `omniwire_semaphore` | Distributed locking — atomic acquire/release. |
|
|
380
|
+
| `omniwire_event` | Pub/sub events per topic. |
|
|
381
|
+
| `omniwire_workflow` | Reusable named workflow DAGs. |
|
|
382
|
+
| `omniwire_agent_registry` | Agent capability discovery + heartbeat. |
|
|
383
|
+
| `omniwire_blackboard` | Shared blackboard for swarm coordination. |
|
|
384
|
+
| `omniwire_task_queue` | Distributed priority queue — enqueue/dequeue/complete. |
|
|
385
|
+
| `omniwire_capability` | Query node capabilities for intelligent routing. |
|
|
386
|
+
|
|
387
|
+
</details>
|
|
388
|
+
|
|
389
|
+
<details>
|
|
390
|
+
<summary><b>Files & Transfer (6)</b></summary>
|
|
384
391
|
|
|
385
392
|
| Tool | Description |
|
|
386
393
|
|------|-------------|
|
|
387
|
-
| `omniwire_read_file` | Read file from any node
|
|
394
|
+
| `omniwire_read_file` | Read file from any node (`node:/path`). |
|
|
388
395
|
| `omniwire_write_file` | Write/create file on any node. |
|
|
389
396
|
| `omniwire_list_files` | List directory contents. |
|
|
390
|
-
| `omniwire_find_files` | Glob search across
|
|
391
|
-
| `omniwire_transfer_file` | Copy between nodes
|
|
392
|
-
| `omniwire_deploy` | Deploy
|
|
397
|
+
| `omniwire_find_files` | Glob search across nodes. |
|
|
398
|
+
| `omniwire_transfer_file` | Copy between nodes (auto SFTP/netcat/aria2c). |
|
|
399
|
+
| `omniwire_deploy` | Deploy one file to all nodes in parallel. |
|
|
400
|
+
|
|
401
|
+
</details>
|
|
393
402
|
|
|
394
|
-
|
|
403
|
+
<details>
|
|
404
|
+
<summary><b>Monitoring (3)</b></summary>
|
|
395
405
|
|
|
396
406
|
| Tool | Description |
|
|
397
407
|
|------|-------------|
|
|
398
|
-
| `omniwire_mesh_status` | Health, latency, CPU/mem/disk
|
|
399
|
-
| `omniwire_node_info` | Detailed info for
|
|
408
|
+
| `omniwire_mesh_status` | Health, latency, CPU/mem/disk — all nodes. |
|
|
409
|
+
| `omniwire_node_info` | Detailed info for one node. |
|
|
400
410
|
| `omniwire_live_monitor` | Snapshot metrics: cpu, memory, disk, network. |
|
|
401
411
|
|
|
402
|
-
|
|
412
|
+
</details>
|
|
413
|
+
|
|
414
|
+
<details>
|
|
415
|
+
<summary><b>System & DevOps (12)</b></summary>
|
|
403
416
|
|
|
404
417
|
| Tool | Description |
|
|
405
418
|
|------|-------------|
|
|
406
|
-
| `omniwire_process_list` | List/filter processes across nodes |
|
|
407
|
-
| `omniwire_disk_usage` | Disk usage for all nodes |
|
|
408
|
-
| `omniwire_tail_log` | Last N lines of a log file |
|
|
409
|
-
| `omniwire_install_package` | Install via apt/npm/pip |
|
|
410
|
-
| `omniwire_service_control` | systemd start/stop/restart/status |
|
|
411
|
-
| `omniwire_docker` | Docker commands on any node |
|
|
412
|
-
| `omniwire_kernel` | dmesg, sysctl, modprobe, lsmod, strace, perf |
|
|
413
|
-
| `omniwire_cron` | List/add/remove cron jobs |
|
|
414
|
-
| `omniwire_env` | Get/set persistent environment variables |
|
|
415
|
-
| `omniwire_network` | ping, traceroute, dns, ports, speed, connections |
|
|
416
|
-
| `omniwire_git` | Git commands on repos on any node |
|
|
417
|
-
| `omniwire_syslog` | Query journalctl with filters |
|
|
418
|
-
|
|
419
|
-
|
|
419
|
+
| `omniwire_process_list` | List/filter processes across nodes. |
|
|
420
|
+
| `omniwire_disk_usage` | Disk usage for all nodes. |
|
|
421
|
+
| `omniwire_tail_log` | Last N lines of a log file. |
|
|
422
|
+
| `omniwire_install_package` | Install via apt/npm/pip. |
|
|
423
|
+
| `omniwire_service_control` | systemd start/stop/restart/status. |
|
|
424
|
+
| `omniwire_docker` | Docker commands on any node. |
|
|
425
|
+
| `omniwire_kernel` | dmesg, sysctl, modprobe, lsmod, strace, perf. |
|
|
426
|
+
| `omniwire_cron` | List/add/remove cron jobs. |
|
|
427
|
+
| `omniwire_env` | Get/set persistent environment variables. |
|
|
428
|
+
| `omniwire_network` | ping, traceroute, dns, ports, speed, connections. |
|
|
429
|
+
| `omniwire_git` | Git commands on repos on any node. |
|
|
430
|
+
| `omniwire_syslog` | Query journalctl with filters. |
|
|
431
|
+
|
|
432
|
+
</details>
|
|
433
|
+
|
|
434
|
+
<details>
|
|
435
|
+
<summary><b>Network, VPN & Security (9)</b></summary>
|
|
420
436
|
|
|
421
437
|
| Tool | Description |
|
|
422
438
|
|------|-------------|
|
|
423
|
-
| `omniwire_firewall` | nftables
|
|
424
|
-
| `omniwire_vpn` |
|
|
425
|
-
| `omniwire_cookies` | Cookie management
|
|
426
|
-
| `omniwire_cdp` | Chrome DevTools Protocol
|
|
427
|
-
| `omniwire_proxy` | HTTP/SOCKS proxy management
|
|
428
|
-
| `omniwire_dns` | DNS
|
|
429
|
-
| `omniwire_port_forward` |
|
|
430
|
-
| `omniwire_shell` | Persistent PTY session (preserves cwd/env) |
|
|
431
|
-
| `omniwire_clipboard` | Shared clipboard buffer across mesh |
|
|
432
|
-
|
|
433
|
-
|
|
439
|
+
| `omniwire_firewall` | nftables engine — presets, rate-limit, geo-block, port-knock, ban/unban. Mesh whitelisted. |
|
|
440
|
+
| `omniwire_vpn` | Mullvad/OpenVPN/WireGuard/Tailscale — multi-hop, DAITA, quantum, killswitch. Mesh-safe. |
|
|
441
|
+
| `omniwire_cookies` | Cookie management — JSON/Header/Netscape, browser extract, CyberBase + 1Password sync. |
|
|
442
|
+
| `omniwire_cdp` | Chrome DevTools Protocol — headless Chrome, screenshot, PDF, DOM, cookies. |
|
|
443
|
+
| `omniwire_proxy` | HTTP/SOCKS proxy management on any node. |
|
|
444
|
+
| `omniwire_dns` | DNS resolve, set server, flush cache, block domains. |
|
|
445
|
+
| `omniwire_port_forward` | SSH tunnels — create/list/close/mesh-expose. |
|
|
446
|
+
| `omniwire_shell` | Persistent PTY session (preserves cwd/env). |
|
|
447
|
+
| `omniwire_clipboard` | Shared clipboard buffer across mesh. |
|
|
448
|
+
|
|
449
|
+
</details>
|
|
450
|
+
|
|
451
|
+
<details>
|
|
452
|
+
<summary><b>Infrastructure (9)</b></summary>
|
|
434
453
|
|
|
435
454
|
| Tool | Description |
|
|
436
455
|
|------|-------------|
|
|
437
|
-
| `omniwire_backup` | Snapshot/restore paths
|
|
438
|
-
| `omniwire_container` |
|
|
439
|
-
| `omniwire_cert` | TLS
|
|
440
|
-
| `omniwire_user` | User & SSH key management
|
|
441
|
-
| `omniwire_schedule` | Distributed cron with failover.
|
|
442
|
-
| `omniwire_alert` | Threshold alerting
|
|
443
|
-
| `omniwire_log_aggregate` | Cross-node log search
|
|
444
|
-
| `omniwire_benchmark` |
|
|
445
|
-
| `omniwire_stream` | Capture streaming output (tail -f, watch) |
|
|
446
|
-
|
|
447
|
-
|
|
456
|
+
| `omniwire_backup` | Snapshot/restore paths. Diff, cleanup, retention. |
|
|
457
|
+
| `omniwire_container` | Docker lifecycle — compose, build, push, logs, prune, stats. |
|
|
458
|
+
| `omniwire_cert` | TLS certs — Let's Encrypt, check expiry, self-signed. |
|
|
459
|
+
| `omniwire_user` | User & SSH key management, sudo config. |
|
|
460
|
+
| `omniwire_schedule` | Distributed cron with failover. |
|
|
461
|
+
| `omniwire_alert` | Threshold alerting — disk/mem/load/offline + webhook notify. |
|
|
462
|
+
| `omniwire_log_aggregate` | Cross-node log search in parallel. |
|
|
463
|
+
| `omniwire_benchmark` | CPU/memory/disk/network benchmarks. |
|
|
464
|
+
| `omniwire_stream` | Capture streaming output (tail -f, watch). |
|
|
465
|
+
|
|
466
|
+
</details>
|
|
467
|
+
|
|
468
|
+
<details>
|
|
469
|
+
<summary><b>OmniMesh & Events (6)</b></summary>
|
|
448
470
|
|
|
449
471
|
| Tool | Description |
|
|
450
472
|
|------|-------------|
|
|
451
|
-
| `
|
|
452
|
-
| `
|
|
453
|
-
| `
|
|
454
|
-
| `
|
|
455
|
-
| `
|
|
456
|
-
| `
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
| `omniwire_knowledge` | CyberBase knowledge CRUD + text/semantic search + health + vacuum + bulk-set + export. |
|
|
463
|
-
|
|
464
|
-
### CyberSync (9)
|
|
473
|
+
| `omniwire_omnimesh` | WireGuard mesh manager — init/up/down/add-peer/sync-peers/health/rotate-keys/topology. All OS. |
|
|
474
|
+
| `omniwire_mesh_expose` | Expose localhost services to mesh — discover/expose/unexpose/expose-remote. |
|
|
475
|
+
| `omniwire_mesh_gateway` | Auto-expose all localhost services mesh-wide. |
|
|
476
|
+
| `omniwire_events` | Webhook + WebSocket + SSE event bus. Publish, manage webhooks, query log. |
|
|
477
|
+
| `omniwire_knowledge` | CyberBase knowledge CRUD, text/semantic search, health, vacuum, bulk-set, export. |
|
|
478
|
+
| `omniwire_update` | Self-update from npm + GitHub. Auto-update, mesh-wide push. |
|
|
479
|
+
|
|
480
|
+
</details>
|
|
481
|
+
|
|
482
|
+
<details>
|
|
483
|
+
<summary><b>Agent Toolkit (7)</b></summary>
|
|
465
484
|
|
|
466
485
|
| Tool | Description |
|
|
467
486
|
|------|-------------|
|
|
468
|
-
| `
|
|
469
|
-
| `
|
|
470
|
-
| `
|
|
471
|
-
| `
|
|
472
|
-
| `
|
|
473
|
-
| `
|
|
474
|
-
| `
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
487
|
+
| `omniwire_snippet` | Reusable command templates with `{{var}}` substitution. |
|
|
488
|
+
| `omniwire_alias` | In-session command shortcuts. |
|
|
489
|
+
| `omniwire_trace` | Distributed tracing — span waterfalls across nodes. |
|
|
490
|
+
| `omniwire_doctor` | Health diagnostics — SSH, disk, mem, docker, WireGuard, CyberBase. |
|
|
491
|
+
| `omniwire_metrics` | Prometheus-compatible metrics scrape/export. |
|
|
492
|
+
| `omniwire_audit` | Command audit log — view/search/stats. |
|
|
493
|
+
| `omniwire_plugin` | Plugin system — list/load from `~/.omniwire/plugins/`. |
|
|
494
|
+
|
|
495
|
+
</details>
|
|
496
|
+
|
|
497
|
+
<details>
|
|
498
|
+
<summary><b>CyberSync (9)</b></summary>
|
|
499
|
+
|
|
500
|
+
| Tool | Description |
|
|
501
|
+
|------|-------------|
|
|
502
|
+
| `cybersync_status` | Sync status, item counts, pending syncs. |
|
|
503
|
+
| `cybersync_sync_now` | Trigger immediate reconciliation. |
|
|
504
|
+
| `cybersync_diff` | Local vs database differences. |
|
|
505
|
+
| `cybersync_history` | Sync event log. |
|
|
506
|
+
| `cybersync_search_knowledge` | Full-text search unified knowledge base. |
|
|
507
|
+
| `cybersync_get_memory` | Retrieve Claude memory from PostgreSQL. |
|
|
508
|
+
| `cybersync_manifest` | Tracked files per tool. |
|
|
509
|
+
| `cybersync_force_push` | Force push file to all nodes. |
|
|
510
|
+
| `omniwire_secrets` | Secrets management (1Password, file, env). |
|
|
511
|
+
|
|
512
|
+
</details>
|
|
478
513
|
|
|
479
514
|
---
|
|
480
515
|
|
package/dist/mcp/server.js
CHANGED
|
@@ -1766,73 +1766,177 @@ echo "port-knock configured: ${ports.join(' -> ')} -> port ${target}"`;
|
|
|
1766
1766
|
return fail('Invalid action or missing params');
|
|
1767
1767
|
});
|
|
1768
1768
|
// --- Tool 33: omniwire_cdp ---
|
|
1769
|
-
|
|
1770
|
-
|
|
1769
|
+
// Uses the persistent cdp-browser Docker container (puppeteer-core) for all operations.
|
|
1770
|
+
// Falls back to direct Chrome CLI for nodes without the container.
|
|
1771
|
+
const cdpScript = (js) => `docker exec cdp-browser node -e ${JSON.stringify(`const puppeteer=require('puppeteer-core');(async()=>{` +
|
|
1772
|
+
`const r=await fetch('http://127.0.0.1:9222/json/version');const{webSocketDebuggerUrl:ws}=await r.json();` +
|
|
1773
|
+
`const browser=await puppeteer.connect({browserWSEndpoint:ws});` +
|
|
1774
|
+
js +
|
|
1775
|
+
`})().catch(e=>{console.error('ERR:',e.message);process.exit(1)});`)} 2>&1`;
|
|
1776
|
+
server.tool('omniwire_cdp', 'Chrome DevTools Protocol — persistent headless browser via Docker container. Navigate, screenshot, HTML, PDF, cookies, evaluate JS, click, type, wait, network intercept, set-cookies, clear. Reuses pages across calls for speed.', {
|
|
1777
|
+
action: z.enum([
|
|
1778
|
+
'navigate', 'screenshot', 'html', 'text', 'pdf', 'cookies', 'set-cookies', 'clear-cookies',
|
|
1779
|
+
'tabs', 'close-tab', 'evaluate', 'click', 'type', 'wait', 'select',
|
|
1780
|
+
'network', 'status', 'viewport',
|
|
1781
|
+
]).describe('navigate=open URL, screenshot=capture PNG, html=DOM dump, text=innerText, pdf=save PDF, ' +
|
|
1782
|
+
'cookies=get all, set-cookies=inject cookies, clear-cookies=wipe, tabs=list pages, close-tab=close page, ' +
|
|
1783
|
+
'evaluate=run JS in page, click=click selector, type=type into selector, wait=wait for selector, ' +
|
|
1784
|
+
'select=querySelector extract, network=recent requests, status=container health, viewport=set size'),
|
|
1771
1785
|
node: z.string().optional().describe('Node (default: contabo)'),
|
|
1772
|
-
url: z.string().optional().describe('URL for navigate
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1786
|
+
url: z.string().optional().describe('URL for navigate'),
|
|
1787
|
+
selector: z.string().optional().describe('CSS selector for click/type/wait/select'),
|
|
1788
|
+
value: z.string().optional().describe('Text for type action, JS for evaluate, cookies JSON for set-cookies'),
|
|
1789
|
+
file: z.string().optional().describe('Output path for screenshot/pdf (default: /tmp/cdp-*)'),
|
|
1790
|
+
tab: z.number().optional().describe('Tab index (0-based, default: 0 = most recent)'),
|
|
1791
|
+
width: z.number().optional().describe('Viewport width for viewport action (default: 1920)'),
|
|
1792
|
+
height: z.number().optional().describe('Viewport height for viewport action (default: 1080)'),
|
|
1793
|
+
wait_ms: z.number().optional().describe('Wait timeout in ms (default: 10000)'),
|
|
1794
|
+
full_page: z.boolean().optional().describe('Full page screenshot (default: true)'),
|
|
1795
|
+
}, async ({ action, node, url, selector, value, file: outFile, tab, width, height, wait_ms, full_page }) => {
|
|
1776
1796
|
const nodeId = node ?? 'contabo';
|
|
1777
|
-
const
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
const
|
|
1782
|
-
`
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
if (
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
const r = await manager.exec(nodeId, cmd);
|
|
1795
|
-
return ok(nodeId, r.durationMs, r.stdout, `navigate`);
|
|
1797
|
+
const tabIdx = tab ?? 0;
|
|
1798
|
+
const timeout = wait_ms ?? 10000;
|
|
1799
|
+
const getPage = `const pages=await browser.pages();const page=pages[${tabIdx}]||pages[0];if(!page){console.log('no pages open');process.exit(0);}`;
|
|
1800
|
+
if (action === 'status') {
|
|
1801
|
+
const r = await manager.exec(nodeId, `docker inspect cdp-browser --format '{{.State.Status}} uptime={{.State.StartedAt}}' 2>/dev/null; ` +
|
|
1802
|
+
`curl -sf http://127.0.0.1:9222/json/version 2>/dev/null | python3 -c "import json,sys;d=json.load(sys.stdin);print(f\\"chrome={d.get('Browser','')} proto={d.get('Protocol-Version','')}\\")" 2>/dev/null; ` +
|
|
1803
|
+
`curl -sf http://127.0.0.1:9222/json/list 2>/dev/null | python3 -c "import json,sys;tabs=json.load(sys.stdin);print(f\\"{len(tabs)} tabs open\\");[print(f\\" {t['id'][:8]} {t.get('url','')[:80]}\\") for t in tabs[:10]]" 2>/dev/null`);
|
|
1804
|
+
return ok(nodeId, r.durationMs, r.stdout, 'cdp status');
|
|
1805
|
+
}
|
|
1806
|
+
if (action === 'navigate') {
|
|
1807
|
+
if (!url)
|
|
1808
|
+
return fail('url required');
|
|
1809
|
+
const u = url.replace(/'/g, "\\'");
|
|
1810
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}` +
|
|
1811
|
+
`await page.goto('${u}',{waitUntil:'networkidle2',timeout:${timeout}});` +
|
|
1812
|
+
`console.log('url='+page.url());console.log('title='+await page.title());`));
|
|
1813
|
+
return ok(nodeId, r.durationMs, r.stdout, 'navigate');
|
|
1796
1814
|
}
|
|
1797
1815
|
if (action === 'screenshot') {
|
|
1798
|
-
const
|
|
1799
|
-
const
|
|
1800
|
-
const
|
|
1801
|
-
|
|
1816
|
+
const out = outFile ?? `/tmp/cdp-screenshot-${Date.now()}.png`;
|
|
1817
|
+
const fp = full_page !== false;
|
|
1818
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}` +
|
|
1819
|
+
`await page.screenshot({path:'${out}',fullPage:${fp}});` +
|
|
1820
|
+
`const fs=require('fs');const sz=fs.statSync('${out}').size;` +
|
|
1821
|
+
`console.log('saved: ${out} ('+Math.round(sz/1024)+'KB) '+page.url());`));
|
|
1802
1822
|
return ok(nodeId, r.durationMs, r.stdout, 'screenshot');
|
|
1803
1823
|
}
|
|
1804
1824
|
if (action === 'html') {
|
|
1805
|
-
const
|
|
1806
|
-
|
|
1807
|
-
|
|
1825
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}` +
|
|
1826
|
+
`const html=await page.content();` +
|
|
1827
|
+
`console.log(html.substring(0,${url ? '50000' : '10000'}));`));
|
|
1808
1828
|
return ok(nodeId, r.durationMs, r.stdout, 'html');
|
|
1809
1829
|
}
|
|
1830
|
+
if (action === 'text') {
|
|
1831
|
+
const sel = selector ? `.replace(/'/g,"\\\\'")` : '';
|
|
1832
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}` +
|
|
1833
|
+
(selector
|
|
1834
|
+
? `const el=await page.$('${selector.replace(/'/g, "\\'")}');const t=el?await page.evaluate(e=>e.innerText,el):'(not found)';console.log(t.substring(0,20000));`
|
|
1835
|
+
: `const t=await page.evaluate(()=>document.body.innerText);console.log(t.substring(0,20000));`)));
|
|
1836
|
+
return ok(nodeId, r.durationMs, r.stdout, 'text');
|
|
1837
|
+
}
|
|
1810
1838
|
if (action === 'pdf') {
|
|
1811
|
-
const
|
|
1812
|
-
const
|
|
1813
|
-
|
|
1814
|
-
|
|
1839
|
+
const out = outFile ?? `/tmp/cdp-page-${Date.now()}.pdf`;
|
|
1840
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}` +
|
|
1841
|
+
`await page.pdf({path:'${out}',format:'A4',printBackground:true});` +
|
|
1842
|
+
`const fs=require('fs');const sz=fs.statSync('${out}').size;` +
|
|
1843
|
+
`console.log('saved: ${out} ('+Math.round(sz/1024)+'KB)');`));
|
|
1815
1844
|
return ok(nodeId, r.durationMs, r.stdout, 'pdf');
|
|
1816
1845
|
}
|
|
1817
1846
|
if (action === 'cookies') {
|
|
1818
|
-
const
|
|
1819
|
-
|
|
1820
|
-
|
|
1847
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}const cookies=await page.cookies();` +
|
|
1848
|
+
`cookies.forEach(c=>console.log(c.domain+'\\t'+c.name+'='+c.value.substring(0,60)+(c.value.length>60?'...':'')));` +
|
|
1849
|
+
`console.log('--- '+cookies.length+' cookies ---');`));
|
|
1850
|
+
return ok(nodeId, r.durationMs, r.stdout, 'cookies');
|
|
1851
|
+
}
|
|
1852
|
+
if (action === 'set-cookies') {
|
|
1853
|
+
if (!value)
|
|
1854
|
+
return fail('value required (JSON array of cookie objects)');
|
|
1855
|
+
const v = value.replace(/'/g, "\\'").replace(/\n/g, '');
|
|
1856
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}const cookies=JSON.parse('${v}');` +
|
|
1857
|
+
`await page.setCookie(...cookies);console.log('set '+cookies.length+' cookies');`));
|
|
1858
|
+
return ok(nodeId, r.durationMs, r.stdout, 'set-cookies');
|
|
1859
|
+
}
|
|
1860
|
+
if (action === 'clear-cookies') {
|
|
1861
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}const client=await page.createCDPSession();` +
|
|
1862
|
+
`await client.send('Network.clearBrowserCookies');console.log('cookies cleared');`));
|
|
1863
|
+
return ok(nodeId, r.durationMs, r.stdout, 'clear-cookies');
|
|
1821
1864
|
}
|
|
1822
1865
|
if (action === 'tabs') {
|
|
1823
|
-
const
|
|
1824
|
-
|
|
1866
|
+
const r = await manager.exec(nodeId, cdpScript(`const pages=await browser.pages();` +
|
|
1867
|
+
`pages.forEach((p,i)=>console.log(i+' '+p.url().substring(0,100)));` +
|
|
1868
|
+
`console.log('--- '+pages.length+' tabs ---');`));
|
|
1825
1869
|
return ok(nodeId, r.durationMs, r.stdout, 'tabs');
|
|
1826
1870
|
}
|
|
1827
|
-
if (action === 'close') {
|
|
1828
|
-
const
|
|
1829
|
-
|
|
1830
|
-
|
|
1871
|
+
if (action === 'close-tab') {
|
|
1872
|
+
const r = await manager.exec(nodeId, cdpScript(`const pages=await browser.pages();` +
|
|
1873
|
+
`if(pages.length<=${tabIdx}){console.log('tab ${tabIdx} not found');process.exit(0);}` +
|
|
1874
|
+
`const url=pages[${tabIdx}].url();await pages[${tabIdx}].close();` +
|
|
1875
|
+
`console.log('closed tab ${tabIdx}: '+url);console.log((pages.length-1)+' tabs remaining');`));
|
|
1876
|
+
return ok(nodeId, r.durationMs, r.stdout, 'close-tab');
|
|
1877
|
+
}
|
|
1878
|
+
if (action === 'evaluate') {
|
|
1879
|
+
if (!value)
|
|
1880
|
+
return fail('value required (JavaScript to evaluate in page context)');
|
|
1881
|
+
const js = value.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/\n/g, '\\n');
|
|
1882
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}const result=await page.evaluate(()=>{${js}});` +
|
|
1883
|
+
`console.log(typeof result==='object'?JSON.stringify(result,null,2):String(result));`));
|
|
1884
|
+
return ok(nodeId, r.durationMs, r.stdout, 'evaluate');
|
|
1885
|
+
}
|
|
1886
|
+
if (action === 'click') {
|
|
1887
|
+
if (!selector)
|
|
1888
|
+
return fail('selector required');
|
|
1889
|
+
const sel = selector.replace(/'/g, "\\'");
|
|
1890
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}await page.waitForSelector('${sel}',{timeout:${timeout}});` +
|
|
1891
|
+
`await page.click('${sel}');console.log('clicked: ${sel}');` +
|
|
1892
|
+
`await new Promise(r=>setTimeout(r,500));console.log('url='+page.url());`));
|
|
1893
|
+
return ok(nodeId, r.durationMs, r.stdout, 'click');
|
|
1894
|
+
}
|
|
1895
|
+
if (action === 'type') {
|
|
1896
|
+
if (!selector || !value)
|
|
1897
|
+
return fail('selector and value required');
|
|
1898
|
+
const sel = selector.replace(/'/g, "\\'");
|
|
1899
|
+
const val = value.replace(/'/g, "\\'");
|
|
1900
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}await page.waitForSelector('${sel}',{timeout:${timeout}});` +
|
|
1901
|
+
`await page.type('${sel}','${val}');console.log('typed ${value.length} chars into ${sel}');`));
|
|
1902
|
+
return ok(nodeId, r.durationMs, r.stdout, 'type');
|
|
1903
|
+
}
|
|
1904
|
+
if (action === 'wait') {
|
|
1905
|
+
if (!selector)
|
|
1906
|
+
return fail('selector required');
|
|
1907
|
+
const sel = selector.replace(/'/g, "\\'");
|
|
1908
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}const el=await page.waitForSelector('${sel}',{timeout:${timeout}});` +
|
|
1909
|
+
`const tag=await page.evaluate(e=>e.tagName+' '+e.className,el);` +
|
|
1910
|
+
`console.log('found: ${sel} → '+tag);`));
|
|
1911
|
+
return ok(nodeId, r.durationMs, r.stdout, 'wait');
|
|
1912
|
+
}
|
|
1913
|
+
if (action === 'select') {
|
|
1914
|
+
if (!selector)
|
|
1915
|
+
return fail('selector required');
|
|
1916
|
+
const sel = selector.replace(/'/g, "\\'");
|
|
1917
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}const els=await page.$$('${sel}');` +
|
|
1918
|
+
`const results=[];for(const el of els.slice(0,20)){` +
|
|
1919
|
+
`const d=await page.evaluate(e=>({tag:e.tagName,text:e.innerText?.substring(0,200),href:e.href||'',src:e.src||''}),el);` +
|
|
1920
|
+
`results.push(d);}` +
|
|
1921
|
+
`console.log(JSON.stringify(results,null,2));console.log('--- '+els.length+' matches ---');`));
|
|
1922
|
+
return ok(nodeId, r.durationMs, r.stdout, 'select');
|
|
1831
1923
|
}
|
|
1832
|
-
if (action === '
|
|
1833
|
-
const
|
|
1834
|
-
|
|
1835
|
-
|
|
1924
|
+
if (action === 'network') {
|
|
1925
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}const client=await page.createCDPSession();` +
|
|
1926
|
+
`const entries=[];client.on('Network.responseReceived',e=>{entries.push({url:e.response.url.substring(0,100),status:e.response.status,type:e.type});});` +
|
|
1927
|
+
`await client.send('Network.enable');` +
|
|
1928
|
+
`await page.reload({waitUntil:'networkidle2',timeout:${timeout}});` +
|
|
1929
|
+
`await client.send('Network.disable');` +
|
|
1930
|
+
`entries.slice(0,30).forEach(e=>console.log(e.status+' '+e.type.padEnd(12)+' '+e.url));` +
|
|
1931
|
+
`console.log('--- '+entries.length+' requests ---');`));
|
|
1932
|
+
return ok(nodeId, r.durationMs, r.stdout, 'network');
|
|
1933
|
+
}
|
|
1934
|
+
if (action === 'viewport') {
|
|
1935
|
+
const w = width ?? 1920;
|
|
1936
|
+
const h = height ?? 1080;
|
|
1937
|
+
const r = await manager.exec(nodeId, cdpScript(`${getPage}await page.setViewport({width:${w},height:${h}});` +
|
|
1938
|
+
`console.log('viewport set to ${w}x${h}');`));
|
|
1939
|
+
return ok(nodeId, r.durationMs, r.stdout, 'viewport');
|
|
1836
1940
|
}
|
|
1837
1941
|
return fail('Invalid action or missing params');
|
|
1838
1942
|
});
|