openclaw-navigator 4.3.2 → 4.3.4

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.
Files changed (2) hide show
  1. package/cli.mjs +91 -52
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -16,7 +16,7 @@
16
16
  import { spawn } from "node:child_process";
17
17
  import { randomUUID } from "node:crypto";
18
18
  import { existsSync } from "node:fs";
19
- import { createServer } from "node:http";
19
+ import { createServer, request as httpRequest } from "node:http";
20
20
  import { networkInterfaces, hostname, userInfo } from "node:os";
21
21
  import { dirname, join } from "node:path";
22
22
  import { fileURLToPath } from "node:url";
@@ -55,6 +55,9 @@ const recentEvents = [];
55
55
  const MAX_EVENTS = 200;
56
56
  const validTokens = new Set();
57
57
 
58
+ // OC Web UI reverse proxy target (configurable via --ui-port or env)
59
+ let ocUIPort = parseInt(process.env.OPENCLAW_UI_PORT ?? "4000", 10);
60
+
58
61
  // Pairing code state
59
62
  let pairingCode = null;
60
63
  let pairingData = null;
@@ -443,8 +446,84 @@ function handleRequest(req, res) {
443
446
  }
444
447
 
445
448
  // ── Health check ──
446
- if (req.method === "GET" && (path === "/" || path === "/health")) {
447
- sendJSON(res, 200, { ok: true, service: "openclaw-navigator-bridge", version: "4.0.0" });
449
+ if (req.method === "GET" && path === "/health") {
450
+ sendJSON(res, 200, { ok: true, service: "openclaw-navigator-bridge", version: "4.3.4" });
451
+ return;
452
+ }
453
+
454
+ // ── Reverse proxy: /ui/* → OC Web UI (localhost:ocUIPort) ──────────────
455
+ // Strips /ui prefix so /ui/dashboard → localhost:4000/dashboard
456
+ if (path === "/ui" || path.startsWith("/ui/")) {
457
+ const targetPath = path === "/ui" ? "/" : path.slice(3); // strip "/ui"
458
+ const targetURL = `${targetPath}${url.search}`;
459
+
460
+ const proxyOpts = {
461
+ hostname: "127.0.0.1",
462
+ port: ocUIPort,
463
+ path: targetURL,
464
+ method: req.method,
465
+ headers: {
466
+ ...req.headers,
467
+ host: `127.0.0.1:${ocUIPort}`,
468
+ },
469
+ };
470
+
471
+ const proxyReq = httpRequest(proxyOpts, (proxyRes) => {
472
+ // Forward status + headers (add CORS for cross-origin tunnel access)
473
+ const headers = { ...proxyRes.headers };
474
+ headers["access-control-allow-origin"] = "*";
475
+ headers["access-control-allow-methods"] = "GET, POST, PUT, DELETE, OPTIONS";
476
+ headers["access-control-allow-headers"] = "Content-Type, Authorization";
477
+ res.writeHead(proxyRes.statusCode ?? 502, headers);
478
+ proxyRes.pipe(res, { end: true });
479
+ });
480
+
481
+ proxyReq.on("error", (err) => {
482
+ sendJSON(res, 502, {
483
+ ok: false,
484
+ error: `OC Web UI not reachable on port ${ocUIPort}`,
485
+ detail: err.message,
486
+ hint: "Make sure the OC gateway is running (openclaw gateway start)",
487
+ });
488
+ });
489
+
490
+ // Forward request body for POST/PUT
491
+ req.pipe(proxyReq, { end: true });
492
+ return;
493
+ }
494
+
495
+ // ── Root → redirect to /ui/ if OC Web UI is available ──
496
+ if (req.method === "GET" && path === "") {
497
+ // Quick probe to check if OC UI is running
498
+ const probe = httpRequest(
499
+ { hostname: "127.0.0.1", port: ocUIPort, path: "/", method: "HEAD", timeout: 1000 },
500
+ (probeRes) => {
501
+ probeRes.resume(); // drain
502
+ // OC UI is running — redirect to it
503
+ res.writeHead(302, { Location: "/ui/" });
504
+ res.end();
505
+ },
506
+ );
507
+ probe.on("error", () => {
508
+ // OC UI not running — show bridge status
509
+ sendJSON(res, 200, {
510
+ ok: true,
511
+ service: "openclaw-navigator-bridge",
512
+ version: "4.3.4",
513
+ ui: { available: false, port: ocUIPort, hint: "Start the OC gateway to enable /ui/" },
514
+ navigator: { connected: bridgeState.connected },
515
+ });
516
+ });
517
+ probe.on("timeout", () => {
518
+ probe.destroy();
519
+ sendJSON(res, 200, {
520
+ ok: true,
521
+ service: "openclaw-navigator-bridge",
522
+ version: "4.3.4",
523
+ ui: { available: false, port: ocUIPort, hint: "OC UI timed out" },
524
+ });
525
+ });
526
+ probe.end();
448
527
  return;
449
528
  }
450
529
 
@@ -523,6 +602,9 @@ async function main() {
523
602
  if (args[i] === "--mcp") {
524
603
  withMcp = true;
525
604
  }
605
+ if (args[i] === "--ui-port" && args[i + 1]) {
606
+ ocUIPort = parseInt(args[i + 1], 10);
607
+ }
526
608
  if (args[i] === "--help" || args[i] === "-h") {
527
609
  console.log(`
528
610
  ${BOLD}openclaw-navigator${RESET} — One-command bridge + tunnel for Navigator
@@ -536,6 +618,7 @@ ${BOLD}Usage:${RESET}
536
618
  ${BOLD}Options:${RESET}
537
619
  --port <port> Bridge server port (default: 18790)
538
620
  --mcp Also start the MCP server (stdio) for OpenClaw agent
621
+ --ui-port <port> OC web UI port to reverse-proxy (default: 4000)
539
622
  --no-tunnel Skip auto-tunnel, use SSH or LAN instead
540
623
  --bind <host> Bind address (default: 127.0.0.1)
541
624
  --help Show this help
@@ -655,6 +738,11 @@ ${BOLD}How it works:${RESET}
655
738
  info(` Token: ${token}`);
656
739
  }
657
740
 
741
+ // ── Show OC Web UI access ────────────────────────────────────────────
742
+ const uiURL = tunnelURL ? `${tunnelURL}/ui/` : `http://localhost:${port}/ui/`;
743
+ console.log(` ${BOLD}OC Web UI:${RESET} ${CYAN}${uiURL}${RESET}`);
744
+ info(` (reverse-proxies to localhost:${ocUIPort} — make sure OC gateway is running)`);
745
+
658
746
  console.log("");
659
747
  console.log(`${BOLD}${GREEN}Bridge is running.${RESET} Waiting for Navigator to connect...`);
660
748
  console.log(`${DIM}Press Ctrl+C to stop.${RESET}\n`);
@@ -733,55 +821,6 @@ ${BOLD}How it works:${RESET}
733
821
  // mcporter not installed — skip silently
734
822
  }
735
823
 
736
- // ── Auto-register with OpenClaw agent config (~/.openclaw/openclaw.json) ──
737
- // The OC agent reads MCP servers from this file, not mcporter.
738
- // This ensures the 15 Navigator tools show up in the agent's tool schema.
739
- try {
740
- const { readFileSync, writeFileSync, mkdirSync } = await import("node:fs");
741
- const { homedir } = await import("node:os");
742
- const ocDir = join(homedir(), ".openclaw");
743
- const ocConfigPath = join(ocDir, "openclaw.json");
744
-
745
- let ocConfig = {};
746
- try {
747
- ocConfig = JSON.parse(readFileSync(ocConfigPath, "utf8"));
748
- } catch {
749
- // File doesn't exist or invalid — start fresh
750
- }
751
-
752
- // Ensure the nested structure exists
753
- if (!ocConfig.agents) ocConfig.agents = {};
754
- if (!ocConfig.agents.defaults) ocConfig.agents.defaults = {};
755
- if (!ocConfig.agents.defaults.mcp) ocConfig.agents.defaults.mcp = {};
756
- if (!ocConfig.agents.defaults.mcp.servers) ocConfig.agents.defaults.mcp.servers = {};
757
-
758
- // Check if navigator is already configured correctly
759
- const existing = ocConfig.agents.defaults.mcp.servers.navigator;
760
- const desired = {
761
- command: process.execPath,
762
- args: [mcpPath],
763
- env: { NAVIGATOR_BRIDGE_URL: `http://localhost:${port}` },
764
- };
765
-
766
- const needsUpdate =
767
- !existing ||
768
- existing.command !== desired.command ||
769
- JSON.stringify(existing.args) !== JSON.stringify(desired.args);
770
-
771
- if (needsUpdate) {
772
- ocConfig.agents.defaults.mcp.servers.navigator = desired;
773
- mkdirSync(ocDir, { recursive: true });
774
- writeFileSync(ocConfigPath, JSON.stringify(ocConfig, null, 2) + "\n", "utf8");
775
- ok("Registered Navigator MCP in ~/.openclaw/openclaw.json (15 tools → OC agent)");
776
- info(" Restart the OC gateway to pick up the new tools");
777
- } else {
778
- info(" Navigator already registered in ~/.openclaw/openclaw.json");
779
- }
780
- } catch (err) {
781
- warn(`Could not auto-register with OpenClaw config: ${err.message}`);
782
- info(" Manually add to ~/.openclaw/openclaw.json → agents.defaults.mcp.servers.navigator");
783
- }
784
-
785
824
  console.log("");
786
825
  }
787
826
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-navigator",
3
- "version": "4.3.2",
3
+ "version": "4.3.4",
4
4
  "description": "One-command bridge + tunnel for the Navigator browser — works on any machine, any OS",
5
5
  "keywords": [
6
6
  "browser",