claudelink-bridge 0.1.0 → 0.1.2
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/README.md +140 -0
- package/package.json +30 -6
- package/bridge.js +0 -92
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# claudelink-bridge
|
|
2
|
+
|
|
3
|
+
**Bridge your browser to Claude Code CLI.**
|
|
4
|
+
|
|
5
|
+
The local server for the [ClaudeLink Chrome extension](https://github.com/devops-monk/claude-link). Send screenshots, selected text, page content, and custom commands from any webpage directly to your local Claude Code — without leaving the browser.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/claudelink-bridge)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://nodejs.org)
|
|
10
|
+
[](#installation)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## How it works
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Chrome Extension ←── WebSocket (localhost:9999) ──→ claudelink-bridge ──→ claude CLI
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The bridge runs a local WebSocket server. The ClaudeLink extension connects to it, sends prompts and context, and the bridge passes them to your local `claude` binary — streaming the response back token by token. **Everything stays on your machine.**
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick start
|
|
25
|
+
|
|
26
|
+
**Step 1 — Install Claude Code CLI** (if you haven't already)
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install -g @anthropic-ai/claude-code
|
|
30
|
+
claude # log in
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Step 2 — Install the bridge as a background service**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx claudelink-bridge setup
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That's it. The bridge starts automatically on every login — no manual steps after this.
|
|
40
|
+
|
|
41
|
+
**Step 3 — Install the ClaudeLink Chrome extension**
|
|
42
|
+
|
|
43
|
+
Download from the [latest GitHub release](https://github.com/devops-monk/claude-link/releases/latest), unzip, and load it in `chrome://extensions` with Developer Mode enabled.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
| Command | Description |
|
|
50
|
+
|---------|-------------|
|
|
51
|
+
| `npx claudelink-bridge setup` | Install as auto-start background service (**run once**) |
|
|
52
|
+
| `npx claudelink-bridge start` | Run manually in the foreground |
|
|
53
|
+
| `npx claudelink-bridge status` | Check if the service is running |
|
|
54
|
+
| `npx claudelink-bridge stop` | Stop the background service |
|
|
55
|
+
| `npx claudelink-bridge kill` | Force-kill whatever is on port 9999 |
|
|
56
|
+
| `npx claudelink-bridge uninstall` | Remove the background service |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Requirements
|
|
61
|
+
|
|
62
|
+
- **Node.js** v18+
|
|
63
|
+
- **Claude Code CLI** — `npm install -g @anthropic-ai/claude-code`
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Auto-start method by platform
|
|
68
|
+
|
|
69
|
+
| Platform | Method | Config location |
|
|
70
|
+
|----------|--------|----------------|
|
|
71
|
+
| **macOS** | launchd | `~/Library/LaunchAgents/com.devops-monk.claudelink.plist` |
|
|
72
|
+
| **Linux** | systemd user service | `~/.config/systemd/user/claudelink.service` |
|
|
73
|
+
| **Windows** | Task Scheduler | Task name: `ClaudeLinkBridge` |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
**Custom port** (default: `9999`):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
CLAUDELINK_PORT=9998 npx claudelink-bridge setup
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Then update the port in the extension popup → **Settings → Bridge port**.
|
|
86
|
+
|
|
87
|
+
**Logs** (macOS/Linux):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
tail -f ~/.claudelink/bridge.log # live output
|
|
91
|
+
cat ~/.claudelink/bridge-error.log # errors
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Troubleshooting
|
|
97
|
+
|
|
98
|
+
**Red dot / "Disconnected" in extension**
|
|
99
|
+
```bash
|
|
100
|
+
npx claudelink-bridge status
|
|
101
|
+
npx claudelink-bridge start
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Port already in use**
|
|
105
|
+
```bash
|
|
106
|
+
npx claudelink-bridge kill
|
|
107
|
+
npx claudelink-bridge start
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**"Failed to start claude"** — Claude Code CLI not found or not logged in:
|
|
111
|
+
```bash
|
|
112
|
+
npm install -g @anthropic-ai/claude-code
|
|
113
|
+
claude
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Bridge stopped after system update**
|
|
117
|
+
```bash
|
|
118
|
+
npx claudelink-bridge setup # re-registers the service
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Security
|
|
124
|
+
|
|
125
|
+
- Accepts connections **only from `chrome-extension://` origins** — no other apps or websites can connect
|
|
126
|
+
- All data stays local — the bridge only talks to your local `claude` binary
|
|
127
|
+
- No telemetry, no analytics, no external requests
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Links
|
|
132
|
+
|
|
133
|
+
- [ClaudeLink Chrome Extension](https://github.com/devops-monk/claude-link)
|
|
134
|
+
- [Claude Code CLI docs](https://docs.anthropic.com/en/docs/claude-code)
|
|
135
|
+
- [Report an issue](https://github.com/devops-monk/claude-link/issues)
|
|
136
|
+
- [DevOps-Monk](https://devops-monk.com)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
MIT © [DevOps-Monk](https://devops-monk.com)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudelink-bridge",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Bridge your browser to Claude Code CLI. The local server for the ClaudeLink Chrome extension — send screenshots, page content, and custom commands from any webpage directly to Claude Code.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"claudelink-bridge": "bin/cli.js"
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node lib/server.js"
|
|
11
11
|
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"lib/",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
12
17
|
"dependencies": {
|
|
13
18
|
"ws": "^8.18.0"
|
|
14
19
|
},
|
|
@@ -18,9 +23,28 @@
|
|
|
18
23
|
"keywords": [
|
|
19
24
|
"claude",
|
|
20
25
|
"claude-code",
|
|
21
|
-
"cli",
|
|
22
|
-
"
|
|
26
|
+
"claude-code-cli",
|
|
27
|
+
"anthropic",
|
|
28
|
+
"chrome-extension",
|
|
29
|
+
"browser-extension",
|
|
30
|
+
"ai",
|
|
31
|
+
"llm",
|
|
32
|
+
"devtools",
|
|
33
|
+
"websocket",
|
|
34
|
+
"bridge",
|
|
35
|
+
"devops"
|
|
23
36
|
],
|
|
24
|
-
"author":
|
|
25
|
-
|
|
37
|
+
"author": {
|
|
38
|
+
"name": "DevOps-Monk",
|
|
39
|
+
"url": "https://devops-monk.com"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"homepage": "https://github.com/devops-monk/claude-link#readme",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/devops-monk/claude-link.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/devops-monk/claude-link/issues"
|
|
49
|
+
}
|
|
26
50
|
}
|
package/bridge.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// ClaudeLink bridge — run once: node bridge/bridge.js
|
|
3
|
-
// Connects Claude Code CLI to the browser extension via WebSocket.
|
|
4
|
-
|
|
5
|
-
import { WebSocketServer } from 'ws';
|
|
6
|
-
import { spawn } from 'child_process';
|
|
7
|
-
import { writeFileSync, unlinkSync } from 'fs';
|
|
8
|
-
import { tmpdir } from 'os';
|
|
9
|
-
import { join } from 'path';
|
|
10
|
-
|
|
11
|
-
const PORT = process.env.CLAUDELINK_PORT ? parseInt(process.env.CLAUDELINK_PORT) : 9999;
|
|
12
|
-
const ALLOWED_ORIGIN = 'chrome-extension://';
|
|
13
|
-
|
|
14
|
-
const wss = new WebSocketServer({ port: PORT });
|
|
15
|
-
|
|
16
|
-
console.log(`\n⚡ ClaudeLink bridge running on ws://localhost:${PORT}`);
|
|
17
|
-
console.log(` Waiting for extension to connect…\n`);
|
|
18
|
-
|
|
19
|
-
wss.on('connection', (ws, req) => {
|
|
20
|
-
const origin = req.headers['origin'] ?? '';
|
|
21
|
-
if (!origin.startsWith(ALLOWED_ORIGIN)) {
|
|
22
|
-
ws.close(1008, 'Forbidden');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
console.log(`[+] Extension connected`);
|
|
27
|
-
|
|
28
|
-
ws.on('message', async (raw) => {
|
|
29
|
-
let msg;
|
|
30
|
-
try { msg = JSON.parse(raw.toString()); }
|
|
31
|
-
catch { ws.send(JSON.stringify({ type: 'error', text: 'Invalid JSON' })); return; }
|
|
32
|
-
|
|
33
|
-
if (msg.type === 'ping') {
|
|
34
|
-
ws.send(JSON.stringify({ type: 'pong' }));
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (msg.type === 'prompt') {
|
|
39
|
-
console.log(`[>] Prompt: ${String(msg.prompt).slice(0, 80)}…`);
|
|
40
|
-
runClaude(['--print', msg.prompt], ws);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (msg.type === 'file-prompt') {
|
|
45
|
-
const tmpFile = join(tmpdir(), `claudelink-${Date.now()}.md`);
|
|
46
|
-
writeFileSync(tmpFile, msg.content);
|
|
47
|
-
console.log(`[>] File prompt: ${tmpFile}`);
|
|
48
|
-
runClaude(['-p', tmpFile], ws, () => { try { unlinkSync(tmpFile); } catch {} });
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (msg.type === 'run-script') {
|
|
53
|
-
const tmpScript = join(tmpdir(), `claudelink-script-${Date.now()}.sh`);
|
|
54
|
-
writeFileSync(tmpScript, msg.script, { mode: 0o755 });
|
|
55
|
-
console.log(`[>] Running script: ${tmpScript}`);
|
|
56
|
-
runScript(tmpScript, ws, () => { try { unlinkSync(tmpScript); } catch {} });
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
ws.on('close', () => console.log(`[-] Extension disconnected`));
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
function runClaude(args, ws, onClose) {
|
|
65
|
-
const proc = spawn('claude', args, { env: { ...process.env } });
|
|
66
|
-
proc.stdout.on('data', (d) => ws.send(JSON.stringify({ type: 'chunk', text: d.toString() })));
|
|
67
|
-
proc.stderr.on('data', (d) => ws.send(JSON.stringify({ type: 'error', text: d.toString() })));
|
|
68
|
-
proc.on('close', (code) => {
|
|
69
|
-
onClose?.();
|
|
70
|
-
ws.send(JSON.stringify({ type: 'done', exitCode: code }));
|
|
71
|
-
console.log(`[✓] Done (exit ${code})`);
|
|
72
|
-
});
|
|
73
|
-
proc.on('error', (e) => {
|
|
74
|
-
ws.send(JSON.stringify({ type: 'error', text: `Failed to start claude: ${e.message}\nMake sure Claude Code CLI is installed: npm install -g @anthropic-ai/claude-code` }));
|
|
75
|
-
ws.send(JSON.stringify({ type: 'done', exitCode: 1 }));
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function runScript(scriptPath, ws, onClose) {
|
|
80
|
-
const proc = spawn('bash', [scriptPath], { env: { ...process.env } });
|
|
81
|
-
proc.stdout.on('data', (d) => ws.send(JSON.stringify({ type: 'chunk', text: d.toString() })));
|
|
82
|
-
proc.stderr.on('data', (d) => ws.send(JSON.stringify({ type: 'error', text: d.toString() })));
|
|
83
|
-
proc.on('close', (code) => {
|
|
84
|
-
onClose?.();
|
|
85
|
-
ws.send(JSON.stringify({ type: 'done', exitCode: code }));
|
|
86
|
-
console.log(`[✓] Script done (exit ${code})`);
|
|
87
|
-
});
|
|
88
|
-
proc.on('error', (e) => {
|
|
89
|
-
ws.send(JSON.stringify({ type: 'error', text: `Script error: ${e.message}` }));
|
|
90
|
-
ws.send(JSON.stringify({ type: 'done', exitCode: 1 }));
|
|
91
|
-
});
|
|
92
|
-
}
|