claude-browser-bridge 4.0.1 → 4.0.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/bin/cli.js +25 -8
- package/gen-token.js +58 -13
- package/index.js +41 -13
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { dirname, join, resolve } from "node:path";
|
|
12
12
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
13
|
-
import { randomBytes } from "node:crypto";
|
|
13
|
+
import { randomBytes, createHash } from "node:crypto";
|
|
14
14
|
import { execSync } from "node:child_process";
|
|
15
15
|
|
|
16
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -44,14 +44,31 @@ Docs: https://github.com/HimanshuKanwar2001/claude-browser-bridge
|
|
|
44
44
|
`);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
function init() {
|
|
47
|
+
async function init() {
|
|
48
48
|
const extPath = args[args.indexOf("init") + 1] || null;
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
const os = await import("node:os");
|
|
50
|
+
const home = os.homedir();
|
|
51
|
+
const port = process.env.BRIDGE_PORT || "8787";
|
|
52
|
+
|
|
53
|
+
// Use deterministic token by default (same every time on this machine)
|
|
54
|
+
const useRandom = args.includes("--random");
|
|
55
|
+
const token = useRandom
|
|
56
|
+
? randomBytes(24).toString("hex")
|
|
57
|
+
: createHash("sha256").update(`claude-browser-bridge:${os.userInfo().username}@${os.hostname()}:${port}`).digest("hex");
|
|
58
|
+
|
|
59
|
+
// Write to canonical path: ~/.claude/browser-bridge-token
|
|
60
|
+
const claudeDir = join(home, ".claude");
|
|
61
|
+
if (!existsSync(claudeDir)) mkdirSync(claudeDir, { recursive: true });
|
|
62
|
+
const canonicalPath = join(home, ".claude", "browser-bridge-token");
|
|
63
|
+
writeFileSync(canonicalPath, token + "\n");
|
|
64
|
+
console.log(`✓ Token written to ${canonicalPath}`);
|
|
65
|
+
|
|
66
|
+
// Also write to server/.bridge-token (legacy fallback)
|
|
67
|
+
try {
|
|
68
|
+
const legacyPath = join(SERVER_DIR, ".bridge-token");
|
|
69
|
+
writeFileSync(legacyPath, token + "\n");
|
|
70
|
+
console.log(`✓ Token written to ${legacyPath}`);
|
|
71
|
+
} catch {}
|
|
55
72
|
|
|
56
73
|
// Write extension config if we can find the extension directory
|
|
57
74
|
const searchPaths = [
|
package/gen-token.js
CHANGED
|
@@ -1,13 +1,58 @@
|
|
|
1
|
-
// Generates the
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
writeFileSync
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
// Generates the auth token for the browser bridge.
|
|
2
|
+
// By default uses a deterministic token derived from the machine identity
|
|
3
|
+
// (username + hostname) so it's always the same — no sync issues.
|
|
4
|
+
// Pass --random for a cryptographically random token instead.
|
|
5
|
+
|
|
6
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
7
|
+
import { writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { homedir, hostname, userInfo } from "node:os";
|
|
10
|
+
|
|
11
|
+
const PORT = Number(process.env.BRIDGE_PORT) || 8787;
|
|
12
|
+
const useRandom = process.argv.includes("--random");
|
|
13
|
+
|
|
14
|
+
let token;
|
|
15
|
+
if (useRandom) {
|
|
16
|
+
token = randomBytes(24).toString("hex");
|
|
17
|
+
console.log("Generated random token (unique, not machine-derived)");
|
|
18
|
+
} else {
|
|
19
|
+
const identity = `claude-browser-bridge:${userInfo().username}@${hostname()}:${PORT}`;
|
|
20
|
+
token = createHash("sha256").update(identity).digest("hex");
|
|
21
|
+
console.log("Generated deterministic token (same every time on this machine)");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 1. Write to ~/.claude/browser-bridge-token (canonical path)
|
|
25
|
+
const claudeDir = join(homedir(), ".claude");
|
|
26
|
+
if (!existsSync(claudeDir)) mkdirSync(claudeDir, { recursive: true });
|
|
27
|
+
const canonicalPath = join(claudeDir, "browser-bridge-token");
|
|
28
|
+
writeFileSync(canonicalPath, token + "\n");
|
|
29
|
+
console.log(`✓ Token written to ${canonicalPath}`);
|
|
30
|
+
|
|
31
|
+
// 2. Write to server/.bridge-token (legacy fallback)
|
|
32
|
+
try {
|
|
33
|
+
writeFileSync(new URL("./.bridge-token", import.meta.url), token + "\n");
|
|
34
|
+
console.log("✓ Token written to server/.bridge-token");
|
|
35
|
+
} catch {}
|
|
36
|
+
|
|
37
|
+
// 3. Write extension/config.js
|
|
38
|
+
const searchPaths = [
|
|
39
|
+
new URL("../extension/config.js", import.meta.url).pathname,
|
|
40
|
+
join(process.cwd(), "extension", "config.js"),
|
|
41
|
+
];
|
|
42
|
+
let extensionWritten = false;
|
|
43
|
+
for (const p of searchPaths) {
|
|
44
|
+
try {
|
|
45
|
+
if (existsSync(join(p, "..", "manifest.json"))) {
|
|
46
|
+
writeFileSync(p, `// Generated by gen-token.js — keep out of version control.\nconst BRIDGE_TOKEN = ${JSON.stringify(token)};\n`);
|
|
47
|
+
console.log(`✓ Extension config written to ${p}`);
|
|
48
|
+
extensionWritten = true;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
53
|
+
if (!extensionWritten) {
|
|
54
|
+
console.log(`⚠ Extension directory not found — create extension/config.js manually:`);
|
|
55
|
+
console.log(` const BRIDGE_TOKEN = "${token}";`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log("\n✓ Done. Reload the extension in chrome://extensions to apply.");
|
package/index.js
CHANGED
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
// "owns" the bridge; later sessions detect EADDRINUSE and relay their tool
|
|
7
7
|
// calls through the owner. If the owner exits, a relay takes over the port.
|
|
8
8
|
|
|
9
|
-
import { readFileSync } from "node:fs";
|
|
9
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { homedir, hostname, userInfo } from "node:os";
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
10
13
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
14
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
15
|
import {
|
|
@@ -17,21 +20,46 @@ import WebSocket, { WebSocketServer } from "ws";
|
|
|
17
20
|
|
|
18
21
|
const PORT = Number(process.env.BRIDGE_PORT) || 8787;
|
|
19
22
|
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
+
// Deterministic token: derived from machine identity (username + hostname).
|
|
24
|
+
// Same token every time on the same machine — no file sync issues, no
|
|
25
|
+
// regeneration needed, no stale-token bugs across sessions.
|
|
26
|
+
// Falls back to file-based token if BRIDGE_TOKEN env var or token file exists.
|
|
27
|
+
function deriveToken() {
|
|
28
|
+
const identity = `claude-browser-bridge:${userInfo().username}@${hostname()}:${PORT}`;
|
|
29
|
+
return createHash("sha256").update(identity).digest("hex");
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
function readToken() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
// 1. Explicit env var override
|
|
34
|
+
if (process.env.BRIDGE_TOKEN) return process.env.BRIDGE_TOKEN;
|
|
35
|
+
// 2. File-based token (legacy — checked for backwards compatibility)
|
|
36
|
+
const filePaths = [
|
|
37
|
+
process.env.BRIDGE_TOKEN_PATH,
|
|
38
|
+
join(homedir(), ".claude", "browser-bridge-token"),
|
|
39
|
+
new URL("./.bridge-token", import.meta.url).pathname,
|
|
40
|
+
join(process.cwd(), "server", ".bridge-token"),
|
|
41
|
+
join(process.cwd(), ".bridge-token"),
|
|
42
|
+
].filter(Boolean);
|
|
43
|
+
for (const p of filePaths) {
|
|
44
|
+
try {
|
|
45
|
+
const t = readFileSync(p, "utf8").trim();
|
|
46
|
+
if (t) return t;
|
|
47
|
+
} catch {}
|
|
28
48
|
}
|
|
49
|
+
// 3. Deterministic token (always works, no files needed)
|
|
50
|
+
return deriveToken();
|
|
29
51
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
|
|
53
|
+
// Write the deterministic token to the canonical location so gen-token.js
|
|
54
|
+
// isn't required anymore (but still works for custom tokens).
|
|
55
|
+
const canonicalDir = join(homedir(), ".claude");
|
|
56
|
+
const canonicalPath = join(canonicalDir, "browser-bridge-token");
|
|
57
|
+
if (!existsSync(canonicalPath)) {
|
|
58
|
+
try {
|
|
59
|
+
if (!existsSync(canonicalDir)) mkdirSync(canonicalDir, { recursive: true });
|
|
60
|
+
writeFileSync(canonicalPath, deriveToken() + "\n");
|
|
61
|
+
console.error(`[bridge] Auto-generated token at ${canonicalPath}`);
|
|
62
|
+
} catch {}
|
|
35
63
|
}
|
|
36
64
|
|
|
37
65
|
// --- WebSocket bridge (owner or relay) -------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-browser-bridge",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "Connect your live Chrome tabs to Claude Code — 65 tools for debugging, performance, accessibility, visual inspection, and browser automation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|