claude-relay 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # claude-relay
2
+
3
+ Run `npx claude-relay` in any directory. Access Claude Code on that directory from any device.
4
+
5
+ ```
6
+ $ cd ~/my-project
7
+ $ npx claude-relay
8
+
9
+ Claude Relay running at http://100.64.1.5:3456
10
+ Project: my-project
11
+ Directory: /Users/you/my-project
12
+
13
+ Open the URL on your phone to start chatting.
14
+ ```
15
+
16
+ ## Why?
17
+
18
+ Yes, you can use Claude Code from the Claude app — but it requires a GitHub repo, runs in a sandboxed VM, and comes with limitations. No local tools, no custom skills, no access to your actual dev environment.
19
+
20
+ **claude-relay** gives you the real thing. One command in any directory — even `~` — and you get full Claude Code on **your machine**, from any device. Your files, your tools, your skills, your environment. No GitHub required, no sandbox.
21
+
22
+ ## How it works
23
+
24
+ claude-relay spawns `claude` CLI processes and bridges them to a web UI over WebSocket. Your browser talks to the relay, the relay talks to Claude Code. Sessions persist across reconnects.
25
+
26
+ ```
27
+ Browser (any device) <--> claude-relay (your machine) <--> claude CLI
28
+ WebSocket HTTP + WS stdin/stdout
29
+ ```
30
+
31
+ ## Features
32
+
33
+ - **One command** — `npx claude-relay` and you're live
34
+ - **Mobile-first UI** — designed for phones and tablets, works everywhere
35
+ - **Multi-session** — run multiple Claude Code sessions, switch between them
36
+ - **Streaming** — real-time token streaming, tool execution, thinking blocks
37
+ - **Session persistence** — sessions survive server restarts and reconnects
38
+ - **Tailscale-aware** — prefers Tailscale IP for secure remote access
39
+ - **Slash commands** — full slash command support with autocomplete
40
+ - **Zero config** — no API keys, no setup. Uses your local `claude` installation
41
+
42
+ ## Requirements
43
+
44
+ - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
45
+ - Node.js 18+
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ # Run directly (no install needed)
51
+ npx claude-relay
52
+
53
+ # Or install globally
54
+ npm install -g claude-relay
55
+ claude-relay
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ```bash
61
+ # Start in current directory
62
+ npx claude-relay
63
+
64
+ # Custom port
65
+ npx claude-relay -p 8080
66
+ ```
67
+
68
+ Then open the URL on any device connected to the same network.
69
+
70
+ ### Remote access with Tailscale
71
+
72
+ claude-relay automatically detects [Tailscale](https://tailscale.com) and uses your Tailscale IP. Install Tailscale on your machine and phone, and you can access Claude Code from anywhere — coffee shop, commute, couch.
73
+
74
+ ## Limitations
75
+
76
+ - Permission prompts (tool approval) are not yet relayed to the browser
77
+ - Image/file attachments from the browser are not yet supported
78
+ - Session persistence is unstable
79
+
80
+ These are planned for future releases. Contributions welcome.
81
+
82
+ ## Security
83
+
84
+ **claude-relay has no built-in authentication or encryption.** Anyone with access to the URL gets full Claude Code access to your machine — reading, writing, and executing files with your user permissions.
85
+
86
+ We strongly recommend using a private network layer such as [Tailscale](https://tailscale.com), WireGuard, or a VPN. claude-relay automatically detects Tailscale and prefers its IP for this reason.
87
+
88
+ If you choose to expose it beyond your private network, that's your call. **Entirely at your own risk.** The authors assume no responsibility for any damage, data loss, or security incidents.
89
+
90
+ ## License
91
+
92
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+
3
+ const os = require("os");
4
+ const { createServer } = require("../lib/server");
5
+
6
+ const args = process.argv.slice(2);
7
+ let port = 3456;
8
+
9
+ for (let i = 0; i < args.length; i++) {
10
+ if (args[i] === "-p" || args[i] === "--port") {
11
+ port = parseInt(args[i + 1], 10);
12
+ if (isNaN(port)) {
13
+ console.error("Invalid port number");
14
+ process.exit(1);
15
+ }
16
+ i++;
17
+ } else if (args[i] === "-h" || args[i] === "--help") {
18
+ console.log("Usage: claude-relay [-p|--port <port>]");
19
+ console.log("");
20
+ console.log("Options:");
21
+ console.log(" -p, --port <port> Port to listen on (default: 3456)");
22
+ process.exit(0);
23
+ }
24
+ }
25
+
26
+ const cwd = process.cwd();
27
+
28
+ function getLocalIP() {
29
+ const interfaces = os.networkInterfaces();
30
+
31
+ // Prefer Tailscale IP
32
+ for (const [name, addrs] of Object.entries(interfaces)) {
33
+ if (/^(tailscale|utun)/.test(name)) {
34
+ for (const addr of addrs) {
35
+ if (addr.family === "IPv4" && !addr.internal && addr.address.startsWith("100.")) {
36
+ return addr.address;
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ // Check all interfaces for Tailscale CGNAT range (100.64.0.0/10)
43
+ for (const addrs of Object.values(interfaces)) {
44
+ for (const addr of addrs) {
45
+ if (addr.family === "IPv4" && !addr.internal && addr.address.startsWith("100.")) {
46
+ return addr.address;
47
+ }
48
+ }
49
+ }
50
+
51
+ // Fall back to LAN IP
52
+ for (const addrs of Object.values(interfaces)) {
53
+ for (const addr of addrs) {
54
+ if (addr.family === "IPv4" && !addr.internal) {
55
+ return addr.address;
56
+ }
57
+ }
58
+ }
59
+
60
+ return "localhost";
61
+ }
62
+
63
+ function confirm(callback) {
64
+ const readline = require("readline");
65
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
66
+
67
+ console.log("");
68
+ console.log(" \x1b[1;33m⚠ WARNING — READ BEFORE CONTINUING\x1b[0m");
69
+ console.log("");
70
+ console.log(" claude-relay has \x1b[1mno built-in authentication or encryption.\x1b[0m");
71
+ console.log(" Anyone with access to the URL gets \x1b[1mfull Claude Code access\x1b[0m to");
72
+ console.log(" this machine — reading, writing, and executing files with your");
73
+ console.log(" user permissions.");
74
+ console.log("");
75
+ console.log(" We strongly recommend using a private network layer such as");
76
+ console.log(" Tailscale, WireGuard, or a VPN.");
77
+ console.log("");
78
+ console.log(" If you choose to expose it beyond your private network, that's");
79
+ console.log(" your call. \x1b[1mEntirely at your own risk.\x1b[0m The authors assume no");
80
+ console.log(" responsibility for any damage, data loss, or security incidents.");
81
+ console.log("");
82
+
83
+ rl.question(" Do you understand and accept? (type \x1b[1my\x1b[0m to continue): ", (answer) => {
84
+ rl.close();
85
+ if (/^(y|yes)$/i.test(answer.trim())) {
86
+ callback();
87
+ } else {
88
+ console.log("\n Aborted.\n");
89
+ process.exit(0);
90
+ }
91
+ });
92
+ }
93
+
94
+ function start() {
95
+ const server = createServer(cwd);
96
+
97
+ server.on("error", (err) => {
98
+ if (err.code === "EADDRINUSE") {
99
+ console.error(`\n Port ${port} is already in use.`);
100
+ console.error(` Run with a different port: claude-relay -p <port>`);
101
+ console.error(` Or kill the existing process: lsof -ti :${port} | xargs kill\n`);
102
+ } else {
103
+ console.error(`\n Server error: ${err.message}\n`);
104
+ }
105
+ process.exit(1);
106
+ });
107
+
108
+ server.listen(port, () => {
109
+ const ip = getLocalIP();
110
+ const project = require("path").basename(cwd);
111
+ console.log("");
112
+ console.log(` Claude Relay running at http://${ip}:${port}`);
113
+ console.log(` Project: ${project}`);
114
+ console.log(` Directory: ${cwd}`);
115
+ console.log("");
116
+ console.log(" Open the URL on your phone to start chatting.");
117
+ console.log("");
118
+ });
119
+ }
120
+
121
+ confirm(start);