omniwire 3.3.0 → 3.4.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.
@@ -1 +1 @@
1
- {"session_id":"8ef02123-7368-447d-82e3-ee14a27328b0","transcript_path":"C:\\Users\\Admin\\.claude\\projects\\C--Users-Admin\\8ef02123-7368-447d-82e3-ee14a27328b0.jsonl","cwd":"C:\\Users\\Admin\\omniwire","model":{"id":"claude-opus-4-6[1m]","display_name":"Opus 4.6 (1M context)"},"workspace":{"current_dir":"C:\\Users\\Admin\\omniwire","project_dir":"C:\\Users\\Admin","added_dirs":["C:/Users/Admin"]},"version":"2.1.87","output_style":{"name":"default"},"cost":{"total_cost_usd":10.609117700000006,"total_duration_ms":2361015,"total_api_duration_ms":1488385,"total_lines_added":180,"total_lines_removed":39},"context_window":{"total_input_tokens":1132,"total_output_tokens":59608,"context_window_size":1000000,"current_usage":{"input_tokens":1,"output_tokens":293,"cache_creation_input_tokens":257,"cache_read_input_tokens":138910},"used_percentage":14,"remaining_percentage":86},"exceeds_200k_tokens":false,"rate_limits":{"five_hour":{"used_percentage":37,"resets_at":1774828800},"seven_day":{"used_percentage":41,"resets_at":1775206800}}}
1
+ {"session_id":"8ef02123-7368-447d-82e3-ee14a27328b0","transcript_path":"C:\\Users\\Admin\\.claude\\projects\\C--Users-Admin\\8ef02123-7368-447d-82e3-ee14a27328b0.jsonl","cwd":"C:\\Users\\Admin\\omniwire","model":{"id":"claude-opus-4-6[1m]","display_name":"Opus 4.6 (1M context)"},"workspace":{"current_dir":"C:\\Users\\Admin\\omniwire","project_dir":"C:\\Users\\Admin","added_dirs":["C:/Users/Admin"]},"version":"2.1.87","output_style":{"name":"default"},"cost":{"total_cost_usd":17.91894630000001,"total_duration_ms":3140566,"total_api_duration_ms":2378114,"total_lines_added":474,"total_lines_removed":126},"context_window":{"total_input_tokens":180562,"total_output_tokens":100001,"context_window_size":1000000,"current_usage":{"input_tokens":1,"output_tokens":359,"cache_creation_input_tokens":356,"cache_read_input_tokens":184970},"used_percentage":19,"remaining_percentage":81},"exceeds_200k_tokens":false,"rate_limits":{"five_hour":{"used_percentage":2,"resets_at":1774846800},"seven_day":{"used_percentage":41,"resets_at":1775206800}}}
@@ -1,5 +1,5 @@
1
1
  {
2
- "lastCheck": 1774827169153,
2
+ "lastCheck": 1774829196137,
3
3
  "lastVersion": "3.0.1",
4
4
  "autoUpdateEnabled": true,
5
5
  "source": "auto",
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  <p align="center">
10
10
  <a href="https://www.npmjs.com/package/omniwire"><img src="https://img.shields.io/npm/v/omniwire?style=for-the-badge&logo=npm&color=CB3837&labelColor=0D1117" alt="npm" /></a>
11
- <img src="https://img.shields.io/badge/MCP_Tools-86-59C2FF?style=for-the-badge&labelColor=0D1117" alt="tools" />
11
+ <img src="https://img.shields.io/badge/MCP_Tools-88-59C2FF?style=for-the-badge&labelColor=0D1117" alt="tools" />
12
12
  <img src="https://img.shields.io/badge/A2A-Protocol-00C853?style=for-the-badge&labelColor=0D1117" alt="A2A" />
13
13
  <img src="https://img.shields.io/badge/Latency-~80ms-FF6D00?style=for-the-badge&labelColor=0D1117" alt="latency" />
14
14
  <img src="https://img.shields.io/badge/CyberBase-Sync-CC93E6?style=for-the-badge&labelColor=0D1117" alt="cyberbase" />
@@ -19,7 +19,7 @@
19
19
 
20
20
  **The infrastructure layer for AI agent swarms.**
21
21
 
22
- 87 MCP tools · A2A protocol · OmniMesh VPN · nftables firewall · CDP browser · cookie sync · 2FA TOTP · bi-directional sync · CyberBase persistence
22
+ 88 MCP tools · A2A protocol · OmniMesh VPN · nftables firewall · CDP browser · cookie sync · 2FA TOTP · bi-directional sync · CyberBase persistence
23
23
 
24
24
  </div>
25
25
 
@@ -214,7 +214,7 @@ graph TB
214
214
  direction TB
215
215
  MCP["MCP Protocol Layer<br/>stdio | SSE | REST"]
216
216
 
217
- subgraph tools["86 Tools"]
217
+ subgraph tools["88 Tools"]
218
218
  direction LR
219
219
  EXEC["Execution<br/>exec run batch<br/>broadcast pipeline bg"]
220
220
  AGENT["Agentic<br/>store watch task<br/>a2a events locks"]
@@ -348,7 +348,7 @@ watch(assert="ready") poll until
348
348
 
349
349
  ---
350
350
 
351
- ## All 81 Tools
351
+ ## All 88 Tools
352
352
 
353
353
  > **Every tool** supports `background: true` — returns a task ID immediately. Poll with `omniwire_bg`.
354
354
 
@@ -632,7 +632,7 @@ Create `~/.omniwire/mesh.json`:
632
632
  <details>
633
633
  <summary><b>v2.5.1 -- Universal Background Dispatch</b></summary>
634
634
 
635
- **`background: true`** auto-injected into all 86 tools via server-level wrapper. Returns task ID, poll with `omniwire_bg`. New `omniwire_bg` tool for list/poll/result.
635
+ **`background: true`** auto-injected into all 88 tools via server-level wrapper. Returns task ID, poll with `omniwire_bg`. New `omniwire_bg` tool for list/poll/result.
636
636
 
637
637
  </details>
638
638
 
@@ -671,7 +671,7 @@ Security fixes, multi-path SSH failover, CyberBase integration, VaultBridge Obsi
671
671
  ```
672
672
  omniwire/
673
673
  src/
674
- mcp/ MCP server (86 tools, 3 transports)
674
+ mcp/ MCP server (88 tools, 3 transports)
675
675
  nodes/ SSH2 pool, transfer engine, PTY, tunnels
676
676
  sync/ CyberSync + CyberBase (PostgreSQL, Obsidian, encryption)
677
677
  protocol/ Mesh config, types, path parsing
@@ -687,7 +687,9 @@ omniwire/
687
687
 
688
688
  | Version | Date | Changes |
689
689
  |---------|------|---------|
690
- | **v3.3.0** | 2026-03-30 | New: `omniwire_coc` tool unified CyberBase + Obsidian + Canvas sync. Auto-creates vault + canvas. `mirror-db` exports entire DB as .md. Configurable vault via `OMNIWIRE_VAULT_ROOT` env. 87 tools. |
690
+ | **v3.4.0** | 2026-03-30 | Rewrite: `omniwire_scrape` — OmniMesh-routed Scrapling with auto-install, VPN routing, adaptive selectors, XPath, bulk sessions. install/status actions. Full README audit (88 tools everywhere). |
691
+ | **v3.3.1** | 2026-03-30 | New: `omniwire_scrape` tool — Scrapling-powered web scraping (static/browser/stealth modes, Cloudflare bypass, TLS spoofing). |
692
+ | **v3.3.0** | 2026-03-30 | New: `omniwire_coc` tool — unified CyberBase + Obsidian + Canvas sync. Auto-creates vault + canvas. `mirror-db` exports entire DB as .md. Configurable vault via `OMNIWIRE_VAULT_ROOT` env. |
691
693
  | **v3.2.2** | 2026-03-30 | Fix: sync GitHub/npm metadata — badge, description, mermaid diagram all reflect 86 tools |
692
694
  | **v3.2.1** | 2026-03-30 | New: 5 bi-directional sync tools (`omniwire_sync`, `omniwire_sync_rules`, `omniwire_sync_hooks`, `omniwire_sync_memory`, `omniwire_sync_agents`) — 86 tools total |
693
695
  | **v3.2.0** | 2026-03-29 | New: `omniwire_2fa` TOTP manager — add/generate/verify/import/export 2FA codes, CyberBase + 1Password persistence, otpauth:// URI import, bulk code generation |
@@ -61,23 +61,25 @@
61
61
 
62
62
  <!-- Stats bar -->
63
63
  <g font-family="'Segoe UI Mono', 'SF Mono', monospace" font-size="12" fill="#59C2FF" opacity="0.7">
64
- <text x="112" y="175" text-anchor="middle">81 MCP Tools</text>
65
- <text x="250" y="175" text-anchor="middle">A2A Protocol</text>
66
- <text x="375" y="175" text-anchor="middle">OmniMesh</text>
67
- <text x="490" y="175" text-anchor="middle">nftables FW</text>
68
- <text x="612" y="175" text-anchor="middle">CyberBase</text>
69
- <text x="728" y="175" text-anchor="middle">~80ms</text>
70
- <text x="815" y="175" text-anchor="middle">v3.1</text>
64
+ <text x="100" y="175" text-anchor="middle">88 MCP Tools</text>
65
+ <text x="225" y="175" text-anchor="middle">A2A Protocol</text>
66
+ <text x="338" y="175" text-anchor="middle">OmniMesh</text>
67
+ <text x="440" y="175" text-anchor="middle">COC Sync</text>
68
+ <text x="545" y="175" text-anchor="middle">Scrapling</text>
69
+ <text x="650" y="175" text-anchor="middle">CyberBase</text>
70
+ <text x="750" y="175" text-anchor="middle">~80ms</text>
71
+ <text x="830" y="175" text-anchor="middle">v3.3</text>
71
72
  </g>
72
73
 
73
74
  <!-- Separator dots between stats -->
74
75
  <g fill="#59C2FF" opacity="0.3">
75
- <circle cx="182" cy="172" r="1.5"/>
76
- <circle cx="313" cy="172" r="1.5"/>
77
- <circle cx="432" cy="172" r="1.5"/>
78
- <circle cx="550" cy="172" r="1.5"/>
79
- <circle cx="670" cy="172" r="1.5"/>
80
- <circle cx="770" cy="172" r="1.5"/>
76
+ <circle cx="163" cy="172" r="1.5"/>
77
+ <circle cx="282" cy="172" r="1.5"/>
78
+ <circle cx="389" cy="172" r="1.5"/>
79
+ <circle cx="493" cy="172" r="1.5"/>
80
+ <circle cx="598" cy="172" r="1.5"/>
81
+ <circle cx="700" cy="172" r="1.5"/>
82
+ <circle cx="790" cy="172" r="1.5"/>
81
83
  </g>
82
84
 
83
85
  <!-- Bottom wave -->
@@ -54,23 +54,25 @@
54
54
 
55
55
  <!-- Stats bar -->
56
56
  <g font-family="'Segoe UI Mono', 'SF Mono', monospace" font-size="12" fill="#1A3A5C" opacity="0.6">
57
- <text x="112" y="175" text-anchor="middle">81 MCP Tools</text>
58
- <text x="250" y="175" text-anchor="middle">A2A Protocol</text>
59
- <text x="375" y="175" text-anchor="middle">OmniMesh</text>
60
- <text x="490" y="175" text-anchor="middle">nftables FW</text>
61
- <text x="612" y="175" text-anchor="middle">CyberBase</text>
62
- <text x="728" y="175" text-anchor="middle">~80ms</text>
63
- <text x="815" y="175" text-anchor="middle">v3.1</text>
57
+ <text x="100" y="175" text-anchor="middle">88 MCP Tools</text>
58
+ <text x="225" y="175" text-anchor="middle">A2A Protocol</text>
59
+ <text x="338" y="175" text-anchor="middle">OmniMesh</text>
60
+ <text x="440" y="175" text-anchor="middle">COC Sync</text>
61
+ <text x="545" y="175" text-anchor="middle">Scrapling</text>
62
+ <text x="650" y="175" text-anchor="middle">CyberBase</text>
63
+ <text x="750" y="175" text-anchor="middle">~80ms</text>
64
+ <text x="830" y="175" text-anchor="middle">v3.3</text>
64
65
  </g>
65
66
 
66
67
  <!-- Separator dots between stats -->
67
68
  <g fill="#1A3A5C" opacity="0.25">
68
- <circle cx="182" cy="172" r="1.5"/>
69
- <circle cx="313" cy="172" r="1.5"/>
70
- <circle cx="432" cy="172" r="1.5"/>
71
- <circle cx="550" cy="172" r="1.5"/>
72
- <circle cx="670" cy="172" r="1.5"/>
73
- <circle cx="770" cy="172" r="1.5"/>
69
+ <circle cx="163" cy="172" r="1.5"/>
70
+ <circle cx="282" cy="172" r="1.5"/>
71
+ <circle cx="389" cy="172" r="1.5"/>
72
+ <circle cx="493" cy="172" r="1.5"/>
73
+ <circle cx="598" cy="172" r="1.5"/>
74
+ <circle cx="700" cy="172" r="1.5"/>
75
+ <circle cx="790" cy="172" r="1.5"/>
74
76
  </g>
75
77
 
76
78
  <!-- Bottom wave -->
@@ -4145,6 +4145,172 @@ echo "port-knock configured: ${ports.join(' -> ')} -> port ${target}"`;
4145
4145
  }
4146
4146
  return fail('invalid action');
4147
4147
  });
4148
+ // --- Tool: omniwire_scrape ---
4149
+ // Scrapling-powered web scraping routed through the OmniMesh WireGuard/Tailscale network.
4150
+ // Auto-installs Scrapling on target node if missing. Supports VPN routing for anonymity.
4151
+ // MCP server runs on Contabo:8931 (systemd), Python CLI fallback on any node.
4152
+ server.tool('omniwire_scrape', 'Scrape web pages using Scrapling via OmniMesh. Modes: http (TLS-spoofed, ~200ms), browser (Playwright JS rendering), stealth (Camoufox + Cloudflare Turnstile bypass). Auto-installs on target node if missing. Routes through WireGuard mesh. Supports VPN routing (via_vpn), bulk URLs with session pooling, CSS/XPath selectors, adaptive self-healing selectors. Actions: scrape (default), install, status.', {
4153
+ action: z.enum(['scrape', 'install', 'status']).default('scrape').describe('scrape=fetch pages, install=setup Scrapling on node, status=check Scrapling health on node'),
4154
+ url: z.string().optional().describe('Target URL to scrape'),
4155
+ urls: z.array(z.string()).optional().describe('Multiple URLs for bulk scraping (uses session pooling)'),
4156
+ mode: z.enum(['http', 'browser', 'stealth']).default('http').describe('http=fast TLS-spoofed, browser=Playwright JS, stealth=Camoufox+CF bypass'),
4157
+ extraction_type: z.enum(['markdown', 'html', 'text']).default('markdown').describe('Output format'),
4158
+ css_selector: z.string().optional().describe('CSS selector to extract specific elements'),
4159
+ xpath: z.string().optional().describe('XPath selector (alternative to css_selector)'),
4160
+ solve_cloudflare: z.boolean().optional().describe('Solve Cloudflare Turnstile (stealth mode)'),
4161
+ wait_selector: z.string().optional().describe('Wait for CSS selector before extracting (browser/stealth)'),
4162
+ network_idle: z.boolean().optional().describe('Wait for network idle before extracting'),
4163
+ proxy: z.string().optional().describe('Proxy URL (http://user:pass@host:port)'),
4164
+ via_vpn: z.string().optional().describe('Route through VPN: "mullvad", "mullvad:se", "wg:wg-vpn"'),
4165
+ timeout: z.number().default(30).describe('Timeout in seconds'),
4166
+ impersonate: z.string().default('chrome').describe('TLS fingerprint: chrome, safari, firefox (http mode)'),
4167
+ adaptive: z.boolean().optional().describe('Enable adaptive self-healing selectors (stores element signatures)'),
4168
+ disable_resources: z.array(z.string()).optional().describe('Block resource types: image, font, stylesheet, script'),
4169
+ node: z.string().optional().describe('Node to run on (default: auto-selects best available)'),
4170
+ label: z.string().optional().describe('Short label for task tracking'),
4171
+ }, async ({ action, url, urls, mode, extraction_type, css_selector, xpath, solve_cloudflare, wait_selector, network_idle, proxy, via_vpn, timeout, impersonate, adaptive, disable_resources, node: targetNode, label }) => {
4172
+ if (!manager)
4173
+ return fail('NodeManager not initialized');
4174
+ // Auto-select best node: prefer contabo (has Scrapling + browsers installed)
4175
+ const target = targetNode ?? 'contabo';
4176
+ // --- Action: install ---
4177
+ if (action === 'install') {
4178
+ const installScript = `
4179
+ pip install "scrapling[all]" 2>&1 | tail -3
4180
+ scrapling install 2>&1 | tail -3
4181
+ python3 -c "import scrapling; print('scrapling', scrapling.__version__)" 2>&1
4182
+ # Set up systemd service if not exists
4183
+ if [ ! -f /etc/systemd/system/scrapling-mcp.service ]; then
4184
+ cat > /etc/systemd/system/scrapling-mcp.service << 'UNIT'
4185
+ [Unit]
4186
+ Description=Scrapling MCP HTTP Server
4187
+ After=network.target
4188
+ [Service]
4189
+ Type=simple
4190
+ ExecStart=/usr/local/bin/scrapling mcp --http --port 8931
4191
+ Restart=always
4192
+ RestartSec=5
4193
+ Environment=HOME=/root
4194
+ [Install]
4195
+ WantedBy=multi-user.target
4196
+ UNIT
4197
+ systemctl daemon-reload
4198
+ systemctl enable scrapling-mcp
4199
+ systemctl start scrapling-mcp
4200
+ echo "systemd service created and started"
4201
+ else
4202
+ systemctl restart scrapling-mcp
4203
+ echo "systemd service restarted"
4204
+ fi`.trim();
4205
+ const r = await manager.exec(target, installScript);
4206
+ return okBrief(`Scrapling install on ${target}:\n${r.stdout.trim()}`);
4207
+ }
4208
+ // --- Action: status ---
4209
+ if (action === 'status') {
4210
+ const r = await manager.exec(target, `python3 -c "import scrapling; print('version:', scrapling.__version__)" 2>&1; systemctl is-active scrapling-mcp 2>/dev/null || echo "no systemd"; curl -s --connect-timeout 2 http://localhost:8931/ 2>&1 | head -1 || echo "MCP server not reachable"`);
4211
+ return okBrief(`Scrapling on ${target}:\n${r.stdout.trim()}`);
4212
+ }
4213
+ // --- Action: scrape ---
4214
+ if (!url && !urls?.length)
4215
+ return fail('url or urls required for scrape action');
4216
+ const allUrls = urls?.length ? urls : [url];
4217
+ // Map mode to Scrapling fetcher
4218
+ const fetcherMap = {
4219
+ http: 'Fetcher',
4220
+ browser: 'DynamicFetcher',
4221
+ stealth: 'StealthyFetcher',
4222
+ };
4223
+ const fetcher = fetcherMap[mode] ?? 'Fetcher';
4224
+ const isSession = allUrls.length > 1;
4225
+ const sessionClass = isSession ? { http: 'FetcherSession', browser: 'AsyncDynamicFetcher', stealth: 'AsyncStealthyFetcher' }[mode] ?? 'FetcherSession' : '';
4226
+ // Build Python kwargs
4227
+ const kwargs = [];
4228
+ if (proxy)
4229
+ kwargs.push(`proxy='${proxy.replace(/'/g, "'\\''")}'`);
4230
+ if (impersonate && mode === 'http')
4231
+ kwargs.push(`impersonate='${impersonate}'`);
4232
+ if (timeout)
4233
+ kwargs.push(`timeout=${timeout}`);
4234
+ if (solve_cloudflare)
4235
+ kwargs.push('solve_cloudflare=True');
4236
+ if (wait_selector)
4237
+ kwargs.push(`wait_selector='${wait_selector.replace(/'/g, "'\\''")}'`);
4238
+ if (network_idle)
4239
+ kwargs.push('network_idle=True');
4240
+ if (disable_resources?.length)
4241
+ kwargs.push(`disable_resources=${JSON.stringify(disable_resources)}`);
4242
+ const kwargsStr = kwargs.length ? ', ' + kwargs.join(', ') : '';
4243
+ // Build selector chain
4244
+ let selectorChain = '';
4245
+ if (css_selector) {
4246
+ selectorChain = adaptive
4247
+ ? `.css('${css_selector.replace(/'/g, "\\'")}', adaptive=True, auto_save=True)`
4248
+ : `.css('${css_selector.replace(/'/g, "\\'")}')`;
4249
+ }
4250
+ else if (xpath) {
4251
+ selectorChain = `.xpath('${xpath.replace(/'/g, "\\'")}')`;
4252
+ }
4253
+ // Build extraction
4254
+ const extractExpr = selectorChain
4255
+ ? `${selectorChain}.getall()`
4256
+ : extraction_type === 'html'
4257
+ ? '.body.decode("utf-8", errors="replace") if hasattr(page, "body") else str(page)'
4258
+ : '.get_all_text()';
4259
+ // Auto-install check: try import, install if missing
4260
+ const autoInstall = `
4261
+ try:
4262
+ from scrapling import ${fetcher}${isSession && sessionClass ? ', ' + sessionClass : ''}
4263
+ except ImportError:
4264
+ import subprocess, sys
4265
+ subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'scrapling[all]', '-q'])
4266
+ subprocess.check_call(['scrapling', 'install'])
4267
+ from scrapling import ${fetcher}${isSession && sessionClass ? ', ' + sessionClass : ''}`;
4268
+ const script = `
4269
+ import json, sys
4270
+ ${autoInstall}
4271
+ results = []
4272
+ urls = ${JSON.stringify(allUrls)}
4273
+ try:
4274
+ fetcher = ${fetcher}()
4275
+ for u in urls:
4276
+ try:
4277
+ page = fetcher.get(u${kwargsStr})
4278
+ content = page${extractExpr}
4279
+ if isinstance(content, list):
4280
+ content = '\\n'.join(str(c) for c in content[:200])
4281
+ results.append({"url": u, "status": getattr(page, 'status', 200), "content": str(content)[:50000], "size": len(str(content))})
4282
+ except Exception as e:
4283
+ results.append({"url": u, "status": 0, "error": str(e)[:500]})
4284
+ except Exception as e:
4285
+ results.append({"error": f"init failed: {e}"})
4286
+ print(json.dumps(results))
4287
+ `.trim();
4288
+ try {
4289
+ // Route through VPN if requested, otherwise direct exec via WireGuard mesh
4290
+ let execCmd = `python3 -c ${JSON.stringify(script)}`;
4291
+ if (via_vpn)
4292
+ execCmd = buildVpnWrappedCmd(via_vpn, execCmd);
4293
+ const r = await manager.exec(target, execCmd);
4294
+ const output = r.stdout.trim();
4295
+ try {
4296
+ const results = JSON.parse(output);
4297
+ if (results.length === 1) {
4298
+ const res = results[0];
4299
+ if (res.error)
4300
+ return fail(`scrape error: ${res.error}`);
4301
+ return okBrief(`[${res.status}] ${res.url} (${res.size ?? 0} chars, ${mode})\n\n${res.content}`);
4302
+ }
4303
+ const summary = results.map(r => `[${r.status ?? 'ERR'}] ${r.url ?? '?'}: ${r.error ?? `${r.size ?? 0} chars`}`).join('\n');
4304
+ return okBrief(`Scraped ${results.length} URLs (${mode}):\n${summary}\n\n${results.map(r => r.content ?? '').join('\n---\n').slice(0, 50000)}`);
4305
+ }
4306
+ catch {
4307
+ return okBrief(output.slice(0, 10000));
4308
+ }
4309
+ }
4310
+ catch (e) {
4311
+ return fail(`scrape failed on ${target}: ${e.message}`);
4312
+ }
4313
+ });
4148
4314
  // --- Tool 54: omniwire_omnimesh ---
4149
4315
  server.tool('omniwire_omnimesh', 'OmniMesh — built-in WireGuard mesh network manager. Create, manage, and monitor a full-mesh or hub-spoke WireGuard VPN across all nodes and any OS (Linux/Windows/macOS). Actions: status, init, add-peer, remove-peer, genkeys, deploy-config, up, down, install, health, rotate-keys, discover-endpoint, topology, sync-peers.', {
4150
4316
  action: z.enum([