openclaw-navigator 4.3.4 → 4.3.6
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 +136 -43
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -772,53 +772,146 @@ ${BOLD}How it works:${RESET}
|
|
|
772
772
|
ok(`MCP server started (PID ${mcpProcess.pid}) — bridge: http://localhost:${port}`);
|
|
773
773
|
|
|
774
774
|
// ── Auto-register MCP server with mcporter (if available) ─────────
|
|
775
|
-
//
|
|
776
|
-
//
|
|
775
|
+
// Writes directly to ~/.mcporter/mcporter.json for reliability.
|
|
776
|
+
//
|
|
777
|
+
// KEY FIX: We resolve stable paths instead of using process.execPath
|
|
778
|
+
// which may point to a temp npx cache (/Users/x/.npm/_npx/<hash>/node)
|
|
779
|
+
// that disappears after npx exits. We find the REAL node binary and
|
|
780
|
+
// the globally-installed mcp.mjs (or realpath of the current one).
|
|
777
781
|
try {
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
);
|
|
797
|
-
|
|
798
|
-
let regOut = "";
|
|
799
|
-
reg.stdout?.on("data", (d) => {
|
|
800
|
-
regOut += d.toString();
|
|
801
|
-
});
|
|
802
|
-
reg.stderr?.on("data", (d) => {
|
|
803
|
-
regOut += d.toString();
|
|
804
|
-
});
|
|
782
|
+
const { readFileSync, writeFileSync, mkdirSync, realpathSync } = await import("node:fs");
|
|
783
|
+
const { homedir } = await import("node:os");
|
|
784
|
+
|
|
785
|
+
// Resolve stable node binary (follow symlinks out of npx temp dir)
|
|
786
|
+
let stableNode;
|
|
787
|
+
try {
|
|
788
|
+
stableNode = realpathSync(process.execPath);
|
|
789
|
+
} catch {
|
|
790
|
+
stableNode = process.execPath;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Resolve stable mcp.mjs path
|
|
794
|
+
let stableMcpPath;
|
|
795
|
+
try {
|
|
796
|
+
stableMcpPath = realpathSync(mcpPath);
|
|
797
|
+
} catch {
|
|
798
|
+
stableMcpPath = mcpPath;
|
|
799
|
+
}
|
|
805
800
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
info(" mcporter not found — OC agent can still use the MCP server directly");
|
|
801
|
+
// If paths are still in npx temp cache, try to find the real install
|
|
802
|
+
if (stableMcpPath.includes("_npx") || stableMcpPath.includes(".npm/_npx")) {
|
|
803
|
+
// Check if openclaw-navigator is installed globally
|
|
804
|
+
const nodeDir = dirname(stableNode);
|
|
805
|
+
const globalMcp = join(dirname(nodeDir), "lib/node_modules/openclaw-navigator/mcp.mjs");
|
|
806
|
+
if (existsSync(globalMcp)) {
|
|
807
|
+
stableMcpPath = globalMcp;
|
|
814
808
|
}
|
|
815
|
-
|
|
809
|
+
// If still temp, that's OK — mcporter will use the path we give it
|
|
810
|
+
// and the bridge running alongside keeps the MCP server alive anyway
|
|
811
|
+
}
|
|
816
812
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
813
|
+
info(` mcporter: node=${stableNode}`);
|
|
814
|
+
info(` mcporter: mcp=${stableMcpPath}`);
|
|
815
|
+
|
|
816
|
+
// Write directly to ~/.mcporter/mcporter.json
|
|
817
|
+
const mcporterDir = join(homedir(), ".mcporter");
|
|
818
|
+
const mcporterConfigPath = join(mcporterDir, "mcporter.json");
|
|
819
|
+
|
|
820
|
+
let mcporterConfig = { mcpServers: {}, imports: [] };
|
|
821
|
+
try {
|
|
822
|
+
mcporterConfig = JSON.parse(readFileSync(mcporterConfigPath, "utf8"));
|
|
823
|
+
if (!mcporterConfig.mcpServers) {
|
|
824
|
+
mcporterConfig.mcpServers = {};
|
|
825
|
+
}
|
|
826
|
+
} catch {
|
|
827
|
+
// File doesn't exist or invalid — start fresh
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Set/update the navigator entry with stable paths
|
|
831
|
+
mcporterConfig.mcpServers.navigator = {
|
|
832
|
+
command: stableNode,
|
|
833
|
+
args: [stableMcpPath],
|
|
834
|
+
env: { NAVIGATOR_BRIDGE_URL: `http://localhost:${port}` },
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
mkdirSync(mcporterDir, { recursive: true });
|
|
838
|
+
writeFileSync(mcporterConfigPath, JSON.stringify(mcporterConfig, null, 2) + "\n", "utf8");
|
|
839
|
+
ok("Registered MCP server with mcporter (15 browser tools available)");
|
|
840
|
+
info(` Config: ${mcporterConfigPath}`);
|
|
841
|
+
} catch (err) {
|
|
842
|
+
warn(`mcporter registration failed: ${err.message}`);
|
|
843
|
+
info(" You can manually configure mcporter for Navigator MCP");
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// ── Install launchd auto-start (macOS only) ──────────────────────────
|
|
847
|
+
// Creates ~/Library/LaunchAgents/com.openclaw.navigator-bridge.plist
|
|
848
|
+
// so the bridge + MCP server starts automatically on login.
|
|
849
|
+
if (process.platform === "darwin") {
|
|
850
|
+
try {
|
|
851
|
+
const { writeFileSync: writePlist, existsSync: plistExists, mkdirSync: mkPlist } = await import("node:fs");
|
|
852
|
+
const { homedir: homeDir } = await import("node:os");
|
|
853
|
+
const home = homeDir();
|
|
854
|
+
const launchAgentsDir = join(home, "Library/LaunchAgents");
|
|
855
|
+
const plistPath = join(launchAgentsDir, "com.openclaw.navigator-bridge.plist");
|
|
856
|
+
|
|
857
|
+
// Resolve the stable node path (same one we found above for mcporter)
|
|
858
|
+
const { realpathSync: rp } = await import("node:fs");
|
|
859
|
+
let nodeForPlist;
|
|
860
|
+
try { nodeForPlist = rp(process.execPath); } catch { nodeForPlist = process.execPath; }
|
|
861
|
+
|
|
862
|
+
// Find npx next to the stable node
|
|
863
|
+
const npxForPlist = join(dirname(nodeForPlist), "npx");
|
|
864
|
+
|
|
865
|
+
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
866
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
867
|
+
<plist version="1.0">
|
|
868
|
+
<dict>
|
|
869
|
+
<key>Label</key>
|
|
870
|
+
<string>com.openclaw.navigator-bridge</string>
|
|
871
|
+
<key>ProgramArguments</key>
|
|
872
|
+
<array>
|
|
873
|
+
<string>${npxForPlist}</string>
|
|
874
|
+
<string>openclaw-navigator@latest</string>
|
|
875
|
+
<string>--mcp</string>
|
|
876
|
+
<string>--port</string>
|
|
877
|
+
<string>${port}</string>
|
|
878
|
+
</array>
|
|
879
|
+
<key>EnvironmentVariables</key>
|
|
880
|
+
<dict>
|
|
881
|
+
<key>PATH</key>
|
|
882
|
+
<string>${dirname(nodeForPlist)}:/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin</string>
|
|
883
|
+
</dict>
|
|
884
|
+
<key>RunAtLoad</key>
|
|
885
|
+
<true/>
|
|
886
|
+
<key>KeepAlive</key>
|
|
887
|
+
<true/>
|
|
888
|
+
<key>StandardOutPath</key>
|
|
889
|
+
<string>${home}/.openclaw/navigator-bridge.log</string>
|
|
890
|
+
<key>StandardErrorPath</key>
|
|
891
|
+
<string>${home}/.openclaw/navigator-bridge.log</string>
|
|
892
|
+
<key>WorkingDirectory</key>
|
|
893
|
+
<string>${home}</string>
|
|
894
|
+
</dict>
|
|
895
|
+
</plist>
|
|
896
|
+
`;
|
|
897
|
+
mkPlist(launchAgentsDir, { recursive: true });
|
|
898
|
+
mkPlist(join(home, ".openclaw"), { recursive: true });
|
|
899
|
+
writePlist(plistPath, plistContent, "utf8");
|
|
900
|
+
|
|
901
|
+
// Load the service (unload first if already loaded)
|
|
902
|
+
try {
|
|
903
|
+
const { execSync: ex } = await import("node:child_process");
|
|
904
|
+
try { ex(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" }); } catch { /* not loaded */ }
|
|
905
|
+
// Don't load now — we're already running. It'll start on next login.
|
|
906
|
+
} catch { /* launchctl not available */ }
|
|
907
|
+
|
|
908
|
+
ok("Auto-start installed — bridge will start on login");
|
|
909
|
+
info(` Plist: ${plistPath}`);
|
|
910
|
+
info(` Logs: ~/.openclaw/navigator-bridge.log`);
|
|
911
|
+
info(` To disable: launchctl unload "${plistPath}"`);
|
|
912
|
+
} catch (err) {
|
|
913
|
+
info(` Auto-start setup skipped: ${err.message}`);
|
|
914
|
+
}
|
|
822
915
|
}
|
|
823
916
|
|
|
824
917
|
console.log("");
|