janus-remote 0.1.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 He Who Seeks
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.
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: janus-remote
3
+ Version: 0.1.0
4
+ Summary: Voice-to-text paste bridge for Claude CLI on remote SSH sessions
5
+ Author: He Who Seeks
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/anthropics/janus
8
+ Project-URL: Repository, https://github.com/anthropics/janus
9
+ Keywords: claude,voice,ssh,remote,paste,janus
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: websocket-client>=1.0.0
27
+ Dynamic: license-file
28
+
29
+ # janus-remote
30
+
31
+ Voice-to-text paste bridge for Claude CLI on remote SSH sessions.
32
+
33
+ Use your voice to interact with Claude CLI running on remote servers, with transcriptions pasted directly into the terminal - no window switching needed!
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install janus-remote
39
+ ```
40
+
41
+ ## Requirements
42
+
43
+ 1. **Local Mac**: Janus Electron app running (provides voice recognition + WebSocket server)
44
+ 2. **SSH Config**: Port forwarding enabled (one-time setup)
45
+
46
+ ## SSH Setup (One-Time)
47
+
48
+ Add this to your `~/.ssh/config` on your **local Mac**:
49
+
50
+ ```
51
+ Host *
52
+ RemoteForward 9473 localhost:9473
53
+ ```
54
+
55
+ Or for specific hosts:
56
+
57
+ ```
58
+ Host myserver
59
+ HostName myserver.example.com
60
+ RemoteForward 9473 localhost:9473
61
+ ```
62
+
63
+ This forwards the Janus WebSocket bridge (port 9473) to the remote server.
64
+
65
+ ## Usage
66
+
67
+ On your remote server via SSH:
68
+
69
+ ```bash
70
+ # Start a new Claude session with voice paste support
71
+ claude-janus
72
+
73
+ # Resume a previous session
74
+ claude-janus --resume
75
+ claude-janus -r
76
+ ```
77
+
78
+ ## How It Works
79
+
80
+ ```
81
+ LOCAL MAC REMOTE SERVER (via SSH)
82
+ ┌─────────────────────┐ ┌─────────────────────┐
83
+ │ Janus Electron │ │ claude-janus │
84
+ │ (Voice Recognition) │ │ (This package) │
85
+ │ │ │ │ │ │
86
+ │ ▼ │ │ │ │
87
+ │ WebSocket :9473 ────┼─────────────┼───────► │ │
88
+ │ │ SSH Tunnel │ ▼ │
89
+ │ │ │ Inject into PTY │
90
+ └─────────────────────┘ └─────────────────────┘
91
+ ```
92
+
93
+ 1. Speak into your Mac's microphone
94
+ 2. Janus transcribes and sends via WebSocket
95
+ 3. SSH tunnel forwards to remote server
96
+ 4. `claude-janus` receives and injects text directly into Claude CLI
97
+
98
+ ## Features
99
+
100
+ - **Zero latency feel**: WebSocket connection, no polling
101
+ - **Background paste**: No window switching - text appears directly in terminal
102
+ - **Multi-session support**: Run multiple `claude-janus` sessions on different servers
103
+ - **Auto-reconnect**: Handles connection drops gracefully
104
+
105
+ ## Troubleshooting
106
+
107
+ ### "Bridge connection failed"
108
+ - Ensure Janus Electron is running on your local Mac
109
+ - Verify SSH port forwarding is configured
110
+ - Check that port 9473 isn't blocked
111
+
112
+ ### "Could not find 'claude' binary"
113
+ - Install Claude CLI: `npm install -g @anthropic-ai/claude-cli`
114
+ - Or ensure it's in your PATH
115
+
116
+ ## License
117
+
118
+ MIT
119
+
120
+ ## Author
121
+
122
+ He Who Seeks
@@ -0,0 +1,94 @@
1
+ # janus-remote
2
+
3
+ Voice-to-text paste bridge for Claude CLI on remote SSH sessions.
4
+
5
+ Use your voice to interact with Claude CLI running on remote servers, with transcriptions pasted directly into the terminal - no window switching needed!
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install janus-remote
11
+ ```
12
+
13
+ ## Requirements
14
+
15
+ 1. **Local Mac**: Janus Electron app running (provides voice recognition + WebSocket server)
16
+ 2. **SSH Config**: Port forwarding enabled (one-time setup)
17
+
18
+ ## SSH Setup (One-Time)
19
+
20
+ Add this to your `~/.ssh/config` on your **local Mac**:
21
+
22
+ ```
23
+ Host *
24
+ RemoteForward 9473 localhost:9473
25
+ ```
26
+
27
+ Or for specific hosts:
28
+
29
+ ```
30
+ Host myserver
31
+ HostName myserver.example.com
32
+ RemoteForward 9473 localhost:9473
33
+ ```
34
+
35
+ This forwards the Janus WebSocket bridge (port 9473) to the remote server.
36
+
37
+ ## Usage
38
+
39
+ On your remote server via SSH:
40
+
41
+ ```bash
42
+ # Start a new Claude session with voice paste support
43
+ claude-janus
44
+
45
+ # Resume a previous session
46
+ claude-janus --resume
47
+ claude-janus -r
48
+ ```
49
+
50
+ ## How It Works
51
+
52
+ ```
53
+ LOCAL MAC REMOTE SERVER (via SSH)
54
+ ┌─────────────────────┐ ┌─────────────────────┐
55
+ │ Janus Electron │ │ claude-janus │
56
+ │ (Voice Recognition) │ │ (This package) │
57
+ │ │ │ │ │ │
58
+ │ ▼ │ │ │ │
59
+ │ WebSocket :9473 ────┼─────────────┼───────► │ │
60
+ │ │ SSH Tunnel │ ▼ │
61
+ │ │ │ Inject into PTY │
62
+ └─────────────────────┘ └─────────────────────┘
63
+ ```
64
+
65
+ 1. Speak into your Mac's microphone
66
+ 2. Janus transcribes and sends via WebSocket
67
+ 3. SSH tunnel forwards to remote server
68
+ 4. `claude-janus` receives and injects text directly into Claude CLI
69
+
70
+ ## Features
71
+
72
+ - **Zero latency feel**: WebSocket connection, no polling
73
+ - **Background paste**: No window switching - text appears directly in terminal
74
+ - **Multi-session support**: Run multiple `claude-janus` sessions on different servers
75
+ - **Auto-reconnect**: Handles connection drops gracefully
76
+
77
+ ## Troubleshooting
78
+
79
+ ### "Bridge connection failed"
80
+ - Ensure Janus Electron is running on your local Mac
81
+ - Verify SSH port forwarding is configured
82
+ - Check that port 9473 isn't blocked
83
+
84
+ ### "Could not find 'claude' binary"
85
+ - Install Claude CLI: `npm install -g @anthropic-ai/claude-cli`
86
+ - Or ensure it's in your PATH
87
+
88
+ ## License
89
+
90
+ MIT
91
+
92
+ ## Author
93
+
94
+ He Who Seeks
@@ -0,0 +1,18 @@
1
+ """
2
+ Janus Remote - Voice-to-text paste bridge for Claude CLI on remote SSH sessions
3
+
4
+ Usage:
5
+ pip install janus-remote
6
+ claude-janus # Start Claude with voice paste support
7
+
8
+ Requires:
9
+ - Janus Electron app running on your local Mac
10
+ - SSH port forwarding: RemoteForward 9473 localhost:9473
11
+ """
12
+
13
+ __version__ = "0.1.0"
14
+ __author__ = "He Who Seeks"
15
+
16
+ from .pty_capture import main as run_pty_capture
17
+
18
+ __all__ = ["run_pty_capture", "__version__"]
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ CLI entry point for janus-remote
4
+
5
+ Usage:
6
+ claude-janus # Start new Claude session with voice paste
7
+ claude-janus --resume # Resume previous session
8
+ claude-janus -r # Short form resume
9
+ """
10
+
11
+ import sys
12
+ import os
13
+ import shutil
14
+
15
+
16
+ def find_claude():
17
+ """Find the claude binary location"""
18
+ # Check PATH first
19
+ claude_path = shutil.which('claude')
20
+ if claude_path:
21
+ return claude_path
22
+
23
+ # Common locations
24
+ common_paths = [
25
+ '/usr/local/bin/claude',
26
+ '/opt/homebrew/bin/claude',
27
+ os.path.expanduser('~/.local/bin/claude'),
28
+ os.path.expanduser('~/bin/claude'),
29
+ '/usr/bin/claude',
30
+ ]
31
+
32
+ for path in common_paths:
33
+ if os.path.isfile(path) and os.access(path, os.X_OK):
34
+ return path
35
+
36
+ return None
37
+
38
+
39
+ def main():
40
+ """Main entry point"""
41
+ # Find claude
42
+ claude_path = find_claude()
43
+
44
+ if not claude_path:
45
+ print("Error: Could not find 'claude' binary.", file=sys.stderr)
46
+ print("Please ensure Claude CLI is installed and in your PATH.", file=sys.stderr)
47
+ print("Install: npm install -g @anthropic-ai/claude-cli", file=sys.stderr)
48
+ sys.exit(1)
49
+
50
+ # Check for resume flag
51
+ args = sys.argv[1:]
52
+ if args and args[0] in ('--resume', '-r', 'resume'):
53
+ args[0] = '--resume'
54
+
55
+ # Import and run the PTY capture
56
+ from .pty_capture import run_claude_session
57
+
58
+ try:
59
+ run_claude_session(claude_path, args)
60
+ except KeyboardInterrupt:
61
+ print("\nSession interrupted.")
62
+ sys.exit(0)
63
+ except Exception as e:
64
+ print(f"Error: {e}", file=sys.stderr)
65
+ sys.exit(1)
66
+
67
+
68
+ if __name__ == '__main__':
69
+ main()
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ PTY Capture for Janus Remote
4
+
5
+ Wraps Claude CLI in a PTY and connects to local Janus via WebSocket
6
+ for voice-to-text paste support over SSH.
7
+ """
8
+
9
+ import sys
10
+ import os
11
+ import pty
12
+ import select
13
+ import termios
14
+ import tty
15
+ import subprocess
16
+ from datetime import datetime
17
+ import signal
18
+ import fcntl
19
+ import time
20
+ import json
21
+ import re
22
+ import threading
23
+ import socket
24
+
25
+ # WebSocket bridge port (must match Janus Electron)
26
+ JANUS_BRIDGE_PORT = 9473
27
+
28
+ # Regex to strip title escape sequences
29
+ TITLE_ESCAPE_PATTERN = re.compile(rb'\x1b\][012];[^\x07\x1b]*(?:\x07|\x1b\\)')
30
+
31
+
32
+ def get_janus_title():
33
+ """Get session title from environment"""
34
+ return os.environ.get('JANUS_TITLE', '')
35
+
36
+
37
+ class RemotePasteClient:
38
+ """WebSocket client for receiving pastes from local Janus via SSH port forwarding"""
39
+
40
+ def __init__(self, master_fd, port=JANUS_BRIDGE_PORT):
41
+ self.master_fd = master_fd
42
+ self.port = port
43
+ self.ws = None
44
+ self.running = True
45
+ self.connected = False
46
+ self.client_thread = None
47
+ self.session_id = f"pty-{os.getpid()}-{int(time.time())}"
48
+
49
+ def start(self):
50
+ """Start the WebSocket client in a background thread"""
51
+ self.client_thread = threading.Thread(target=self._run_client, daemon=True)
52
+ self.client_thread.start()
53
+
54
+ def _run_client(self):
55
+ """Main client loop - connect and listen for pastes"""
56
+ try:
57
+ import websocket
58
+ except ImportError:
59
+ print("[janus-remote] websocket-client not installed. Run: pip install websocket-client", file=sys.stderr)
60
+ return
61
+
62
+ while self.running:
63
+ try:
64
+ ws_url = f"ws://localhost:{self.port}"
65
+ print(f"[janus-remote] Connecting to Janus bridge at {ws_url}...", file=sys.stderr)
66
+
67
+ self.ws = websocket.create_connection(ws_url, timeout=5)
68
+ self.connected = True
69
+ print("[janus-remote] Connected to Janus bridge!", file=sys.stderr)
70
+
71
+ # Register this session
72
+ my_title = get_janus_title()
73
+ hostname = socket.gethostname()
74
+ register_msg = json.dumps({
75
+ 'type': 'register',
76
+ 'sessionId': self.session_id,
77
+ 'title': my_title,
78
+ 'hostname': hostname
79
+ })
80
+ self.ws.send(register_msg)
81
+
82
+ # Listen for messages
83
+ while self.running and self.connected:
84
+ try:
85
+ self.ws.settimeout(1.0)
86
+ message = self.ws.recv()
87
+ if message:
88
+ self._handle_message(message)
89
+ except websocket.WebSocketTimeoutException:
90
+ try:
91
+ self.ws.send(json.dumps({'type': 'ping'}))
92
+ except:
93
+ break
94
+ except websocket.WebSocketConnectionClosedException:
95
+ break
96
+ except Exception:
97
+ break
98
+
99
+ except Exception as e:
100
+ if self.running:
101
+ print(f"[janus-remote] Bridge connection failed: {e}", file=sys.stderr)
102
+ self.connected = False
103
+
104
+ if self.running:
105
+ time.sleep(5)
106
+
107
+ def _handle_message(self, message):
108
+ """Handle incoming WebSocket message"""
109
+ try:
110
+ msg = json.loads(message)
111
+ msg_type = msg.get('type')
112
+
113
+ if msg_type == 'paste':
114
+ text = msg.get('text', '')
115
+ if text:
116
+ self._inject_text(text)
117
+ elif msg_type == 'registered':
118
+ print(f"[janus-remote] {msg.get('message', 'Registered')}", file=sys.stderr)
119
+
120
+ except json.JSONDecodeError:
121
+ pass
122
+
123
+ def _inject_text(self, text):
124
+ """Inject text directly into the PTY"""
125
+ try:
126
+ encoded = text.encode('utf-8')
127
+ chunk_size = 256
128
+ for i in range(0, len(encoded), chunk_size):
129
+ chunk = encoded[i:i + chunk_size]
130
+ os.write(self.master_fd, chunk)
131
+ if len(encoded) > chunk_size:
132
+ time.sleep(0.02)
133
+
134
+ time.sleep(0.15)
135
+ os.write(self.master_fd, b'\r')
136
+ except OSError as e:
137
+ print(f"[janus-remote] Paste error: {e}", file=sys.stderr)
138
+
139
+ def stop(self):
140
+ """Stop the client"""
141
+ self.running = False
142
+ self.connected = False
143
+ if self.ws:
144
+ try:
145
+ self.ws.close()
146
+ except:
147
+ pass
148
+
149
+
150
+ def run_claude_session(claude_path, args):
151
+ """Run Claude CLI wrapped in PTY with Janus voice paste support"""
152
+
153
+ # Save original terminal settings
154
+ old_tty = termios.tcgetattr(sys.stdin)
155
+
156
+ try:
157
+ # Create a pseudo-terminal
158
+ master_fd, slave_fd = pty.openpty()
159
+
160
+ # Fork and run Claude in the child process
161
+ pid = os.fork()
162
+
163
+ if pid == 0: # Child process
164
+ os.close(master_fd)
165
+ os.setsid()
166
+ os.dup2(slave_fd, 0) # stdin
167
+ os.dup2(slave_fd, 1) # stdout
168
+ os.dup2(slave_fd, 2) # stderr
169
+
170
+ # Run Claude
171
+ os.execv(claude_path, [claude_path] + args)
172
+
173
+ else: # Parent process
174
+ os.close(slave_fd)
175
+
176
+ # Set stdin to raw mode
177
+ tty.setraw(sys.stdin.fileno())
178
+
179
+ # Make master_fd non-blocking
180
+ flags = fcntl.fcntl(master_fd, fcntl.F_GETFL)
181
+ fcntl.fcntl(master_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
182
+
183
+ # Initialize Remote Paste Client
184
+ remote_client = RemotePasteClient(master_fd)
185
+ remote_client.start()
186
+
187
+ while True:
188
+ rfds, _, _ = select.select([sys.stdin, master_fd], [], [], 0.01)
189
+
190
+ # Check if child has exited
191
+ pid_status = os.waitpid(pid, os.WNOHANG)
192
+ if pid_status[0] != 0:
193
+ break
194
+
195
+ if sys.stdin in rfds:
196
+ try:
197
+ data = os.read(sys.stdin.fileno(), 1024)
198
+ if data:
199
+ os.write(master_fd, data)
200
+ except OSError:
201
+ pass
202
+
203
+ if master_fd in rfds:
204
+ try:
205
+ data = os.read(master_fd, 4096)
206
+ if data:
207
+ # Strip title escape sequences
208
+ data = TITLE_ESCAPE_PATTERN.sub(b'', data)
209
+ os.write(sys.stdout.fileno(), data)
210
+ except OSError:
211
+ pass
212
+
213
+ # Stop remote client
214
+ remote_client.stop()
215
+
216
+ # Get exit status
217
+ _, exit_status = os.waitpid(pid, 0)
218
+ exit_code = os.WEXITSTATUS(exit_status) if os.WIFEXITED(exit_status) else 1
219
+
220
+ finally:
221
+ # Restore terminal settings
222
+ termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
223
+
224
+ sys.exit(exit_code if 'exit_code' in locals() else 0)
225
+
226
+
227
+ def main():
228
+ """Standalone entry point"""
229
+ from .cli import main as cli_main
230
+ cli_main()
231
+
232
+
233
+ if __name__ == '__main__':
234
+ main()
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: janus-remote
3
+ Version: 0.1.0
4
+ Summary: Voice-to-text paste bridge for Claude CLI on remote SSH sessions
5
+ Author: He Who Seeks
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/anthropics/janus
8
+ Project-URL: Repository, https://github.com/anthropics/janus
9
+ Keywords: claude,voice,ssh,remote,paste,janus
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: websocket-client>=1.0.0
27
+ Dynamic: license-file
28
+
29
+ # janus-remote
30
+
31
+ Voice-to-text paste bridge for Claude CLI on remote SSH sessions.
32
+
33
+ Use your voice to interact with Claude CLI running on remote servers, with transcriptions pasted directly into the terminal - no window switching needed!
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install janus-remote
39
+ ```
40
+
41
+ ## Requirements
42
+
43
+ 1. **Local Mac**: Janus Electron app running (provides voice recognition + WebSocket server)
44
+ 2. **SSH Config**: Port forwarding enabled (one-time setup)
45
+
46
+ ## SSH Setup (One-Time)
47
+
48
+ Add this to your `~/.ssh/config` on your **local Mac**:
49
+
50
+ ```
51
+ Host *
52
+ RemoteForward 9473 localhost:9473
53
+ ```
54
+
55
+ Or for specific hosts:
56
+
57
+ ```
58
+ Host myserver
59
+ HostName myserver.example.com
60
+ RemoteForward 9473 localhost:9473
61
+ ```
62
+
63
+ This forwards the Janus WebSocket bridge (port 9473) to the remote server.
64
+
65
+ ## Usage
66
+
67
+ On your remote server via SSH:
68
+
69
+ ```bash
70
+ # Start a new Claude session with voice paste support
71
+ claude-janus
72
+
73
+ # Resume a previous session
74
+ claude-janus --resume
75
+ claude-janus -r
76
+ ```
77
+
78
+ ## How It Works
79
+
80
+ ```
81
+ LOCAL MAC REMOTE SERVER (via SSH)
82
+ ┌─────────────────────┐ ┌─────────────────────┐
83
+ │ Janus Electron │ │ claude-janus │
84
+ │ (Voice Recognition) │ │ (This package) │
85
+ │ │ │ │ │ │
86
+ │ ▼ │ │ │ │
87
+ │ WebSocket :9473 ────┼─────────────┼───────► │ │
88
+ │ │ SSH Tunnel │ ▼ │
89
+ │ │ │ Inject into PTY │
90
+ └─────────────────────┘ └─────────────────────┘
91
+ ```
92
+
93
+ 1. Speak into your Mac's microphone
94
+ 2. Janus transcribes and sends via WebSocket
95
+ 3. SSH tunnel forwards to remote server
96
+ 4. `claude-janus` receives and injects text directly into Claude CLI
97
+
98
+ ## Features
99
+
100
+ - **Zero latency feel**: WebSocket connection, no polling
101
+ - **Background paste**: No window switching - text appears directly in terminal
102
+ - **Multi-session support**: Run multiple `claude-janus` sessions on different servers
103
+ - **Auto-reconnect**: Handles connection drops gracefully
104
+
105
+ ## Troubleshooting
106
+
107
+ ### "Bridge connection failed"
108
+ - Ensure Janus Electron is running on your local Mac
109
+ - Verify SSH port forwarding is configured
110
+ - Check that port 9473 isn't blocked
111
+
112
+ ### "Could not find 'claude' binary"
113
+ - Install Claude CLI: `npm install -g @anthropic-ai/claude-cli`
114
+ - Or ensure it's in your PATH
115
+
116
+ ## License
117
+
118
+ MIT
119
+
120
+ ## Author
121
+
122
+ He Who Seeks
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ janus_remote/__init__.py
5
+ janus_remote/cli.py
6
+ janus_remote/pty_capture.py
7
+ janus_remote.egg-info/PKG-INFO
8
+ janus_remote.egg-info/SOURCES.txt
9
+ janus_remote.egg-info/dependency_links.txt
10
+ janus_remote.egg-info/entry_points.txt
11
+ janus_remote.egg-info/requires.txt
12
+ janus_remote.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ claude-janus = janus_remote.cli:main
3
+ janus-remote = janus_remote.cli:main
@@ -0,0 +1 @@
1
+ websocket-client>=1.0.0
@@ -0,0 +1 @@
1
+ janus_remote
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "janus-remote"
7
+ version = "0.1.0"
8
+ description = "Voice-to-text paste bridge for Claude CLI on remote SSH sessions"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "He Who Seeks"}
13
+ ]
14
+ keywords = ["claude", "voice", "ssh", "remote", "paste", "janus"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Operating System :: MacOS",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.8",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Topic :: Software Development :: Libraries :: Python Modules",
29
+ ]
30
+ requires-python = ">=3.8"
31
+ dependencies = [
32
+ "websocket-client>=1.0.0",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/anthropics/janus"
37
+ Repository = "https://github.com/anthropics/janus"
38
+
39
+ [project.scripts]
40
+ claude-janus = "janus_remote.cli:main"
41
+ janus-remote = "janus_remote.cli:main"
42
+
43
+ [tool.setuptools.packages.find]
44
+ where = ["."]
45
+ include = ["janus_remote*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+