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.
Files changed (3) hide show
  1. package/README.md +140 -0
  2. package/package.json +30 -6
  3. 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
+ [![npm](https://img.shields.io/npm/v/claudelink-bridge?color=7c3aed&label=npm)](https://www.npmjs.com/package/claudelink-bridge)
8
+ [![license](https://img.shields.io/npm/l/claudelink-bridge?color=7c3aed)](LICENSE)
9
+ [![node](https://img.shields.io/node/v/claudelink-bridge?color=7c3aed)](https://nodejs.org)
10
+ [![platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-7c3aed)](#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.0",
4
- "description": "Local bridge server connecting ClaudeLink Chrome extension to Claude Code CLI",
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
- "chrome-extension"
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": "DevOps-Monk",
25
- "license": "MIT"
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
- }