openclaw-navigator 2.0.0 → 2.1.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/cli.mjs +61 -3
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -79,6 +79,35 @@ function getTailscaleIP() {
|
|
|
79
79
|
return null;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
function getTailscaleDNS() {
|
|
83
|
+
try {
|
|
84
|
+
const raw = execSync("tailscale status --json", { encoding: "utf8", timeout: 5000 });
|
|
85
|
+
const status = JSON.parse(raw);
|
|
86
|
+
const dns = status?.Self?.DNSName;
|
|
87
|
+
if (dns) return dns.replace(/\.$/, "");
|
|
88
|
+
} catch { /* ignore */ }
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function setupTailscaleServe(localPort, httpsPort = 8443) {
|
|
93
|
+
try {
|
|
94
|
+
// Set up tailscale serve to proxy HTTPS → our local HTTP server
|
|
95
|
+
execSync(`tailscale serve --bg --https=${httpsPort} http://localhost:${localPort}`, {
|
|
96
|
+
stdio: "ignore",
|
|
97
|
+
timeout: 10_000,
|
|
98
|
+
});
|
|
99
|
+
return true;
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function teardownTailscaleServe(httpsPort = 8443) {
|
|
106
|
+
try {
|
|
107
|
+
execSync(`tailscale serve --https=${httpsPort} off`, { stdio: "ignore", timeout: 5000 });
|
|
108
|
+
} catch { /* ignore */ }
|
|
109
|
+
}
|
|
110
|
+
|
|
82
111
|
function commandExists(cmd) {
|
|
83
112
|
try {
|
|
84
113
|
execSync(`which ${cmd}`, { stdio: "ignore" });
|
|
@@ -396,9 +425,12 @@ ${BOLD}What this does:${RESET}
|
|
|
396
425
|
const tailscaleIP = getTailscaleIP();
|
|
397
426
|
const localIP = getLocalIP();
|
|
398
427
|
|
|
428
|
+
const tailscaleDNS = tailscaleIP ? getTailscaleDNS() : null;
|
|
429
|
+
|
|
399
430
|
const methods = [];
|
|
400
431
|
if (hasCloudflared) methods.push({ value: "cloudflare", label: "Cloudflare Tunnel (recommended)", hint: "works anywhere, no config" });
|
|
401
|
-
if (
|
|
432
|
+
if (tailscaleDNS) methods.push({ value: "tailscale-https", label: "Tailscale HTTPS (recommended)", hint: tailscaleDNS });
|
|
433
|
+
else if (tailscaleIP) methods.push({ value: "tailscale", label: "Tailscale (raw IP)", hint: tailscaleIP });
|
|
402
434
|
methods.push({ value: "ssh", label: "SSH Tunnel", hint: "run SSH on your Mac" });
|
|
403
435
|
if (localIP) methods.push({ value: "lan", label: "Direct LAN", hint: localIP });
|
|
404
436
|
|
|
@@ -406,6 +438,8 @@ ${BOLD}What this does:${RESET}
|
|
|
406
438
|
|
|
407
439
|
// ── Step 3: Resolve gateway URL ───────────────────────────────────────
|
|
408
440
|
let gatewayURL;
|
|
441
|
+
let usedTailscaleServe = false;
|
|
442
|
+
const tailscaleHttpsPort = 8443;
|
|
409
443
|
|
|
410
444
|
switch (method) {
|
|
411
445
|
case "cloudflare": {
|
|
@@ -421,6 +455,22 @@ ${BOLD}What this does:${RESET}
|
|
|
421
455
|
gatewayURL = tunnelURL;
|
|
422
456
|
break;
|
|
423
457
|
}
|
|
458
|
+
case "tailscale-https": {
|
|
459
|
+
process.stdout.write(`\n${DIM}Setting up Tailscale HTTPS on port ${tailscaleHttpsPort}...${RESET}`);
|
|
460
|
+
const served = setupTailscaleServe(port, tailscaleHttpsPort);
|
|
461
|
+
process.stdout.write("\r" + " ".repeat(70) + "\r");
|
|
462
|
+
if (served) {
|
|
463
|
+
gatewayURL = `https://${tailscaleDNS}:${tailscaleHttpsPort}`;
|
|
464
|
+
usedTailscaleServe = true;
|
|
465
|
+
ok(`Tailscale HTTPS active: ${gatewayURL}`);
|
|
466
|
+
} else {
|
|
467
|
+
// Fallback to raw IP
|
|
468
|
+
warn("tailscale serve failed, falling back to raw IP");
|
|
469
|
+
gatewayURL = `http://${tailscaleIP}:${port}`;
|
|
470
|
+
ok(`Using Tailscale IP: ${tailscaleIP}:${port}`);
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
424
474
|
case "tailscale": {
|
|
425
475
|
gatewayURL = `http://${tailscaleIP}:${port}`;
|
|
426
476
|
ok(`Using Tailscale: ${tailscaleIP}:${port}`);
|
|
@@ -457,14 +507,22 @@ ${BOLD}What this does:${RESET}
|
|
|
457
507
|
console.log(`${DIM}Press Ctrl+C to stop.${RESET}\n`);
|
|
458
508
|
|
|
459
509
|
// Graceful shutdown
|
|
510
|
+
const cleanup = () => {
|
|
511
|
+
if (usedTailscaleServe) {
|
|
512
|
+
console.log(`${DIM}Removing tailscale serve...${RESET}`);
|
|
513
|
+
teardownTailscaleServe(tailscaleHttpsPort);
|
|
514
|
+
}
|
|
515
|
+
server.close();
|
|
516
|
+
};
|
|
517
|
+
|
|
460
518
|
process.on("SIGINT", () => {
|
|
461
519
|
console.log(`\n${DIM}Shutting down bridge...${RESET}`);
|
|
462
|
-
|
|
520
|
+
cleanup();
|
|
463
521
|
process.exit(0);
|
|
464
522
|
});
|
|
465
523
|
|
|
466
524
|
process.on("SIGTERM", () => {
|
|
467
|
-
|
|
525
|
+
cleanup();
|
|
468
526
|
process.exit(0);
|
|
469
527
|
});
|
|
470
528
|
}
|