ghostterm 1.1.1 → 1.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ ## 1.1.3 (2026-03-17)
4
+
5
+ ### Features
6
+ - **12345 numpad popup** — quick number selection for CLI surveys/prompts (raw keypress without Enter)
7
+ - **Screen button** — renamed from "Shot" for clarity
8
+ - **Paste button shows filename** — after uploading, displays shortened filename instead of generic "Paste"
9
+ - **Session persistence** — refreshing the page restores your last active terminal session
10
+ - **PM2 support** — can run in background without a terminal window
11
+
12
+ ### Security & Stability
13
+ - **Heartbeat ping/pong** — relay pings every 20s; mobile detects dead connections within 30s and auto-reconnects
14
+ - **Disconnect overlay** — clear full-screen prompt when companion goes offline
15
+ - **Session loading spinner** — visual feedback when switching sessions
16
+ - **Improved toast notifications** — slide-in animation
17
+
18
+ ### Docs
19
+ - Updated README with new features, PM2 instructions, heartbeat details
20
+ - Added CHANGELOG
21
+
22
+ ## 1.1.1 (2026-03-16)
23
+
24
+ ### Security Hardening
25
+ - **Rate limiting** — 50 messages/second per WebSocket connection
26
+ - **IP connection limit** — max 5 concurrent connections per IP
27
+ - **Brute force protection** — pair code entry locked after 3 failed attempts (60s cooldown)
28
+ - **Origin verification** — only ghostterm.pages.dev allowed
29
+ - **Max payload** — 1MB limit per WebSocket message
30
+ - **Timing-safe HMAC** — prevents timing attacks on token verification
31
+ - **Upload validation** — 5MB size limit + extension whitelist
32
+ - **Pair code format validation** — must be exactly 6 digits
33
+ - **WSS enforcement** — prevents MITM downgrade attacks
34
+ - **Exponential backoff** — reconnection delay 1s → 30s max
35
+
36
+ ### Bug Fixes
37
+ - Fixed ghost duplication (stale session list cleared on reconnect)
38
+ - Fixed auto-scroll during thinking output (touch/button scroll disables auto-scroll)
39
+ - Fixed smartScroll jumping to top of terminal
40
+
41
+ ## 1.1.0 (2026-03-15)
42
+
43
+ ### Features
44
+ - Google OAuth auto-pairing (sign in once, auto-reconnects)
45
+ - Long-lived token (30 days, no repeated Google sign-in)
46
+ - 4 simultaneous terminal sessions with ghost cell previews
47
+ - Pixel office mode
48
+ - File upload and screenshot support
49
+ - D-pad controls, quick keys (y/n/Tab/Shift+Tab)
50
+ - Copy mode for terminal text selection
51
+
52
+ ## 1.0.0 (2026-03-14)
53
+
54
+ - Initial release
55
+ - Basic terminal relay via WebSocket
56
+ - Pair code pairing
package/README.md CHANGED
@@ -1,39 +1,34 @@
1
- # GhostTerm 👻
2
-
3
- **A mobile terminal for Claude Code fans.** Control your PC from your phone — real CLI, not a toy.
4
-
5
- > *GhostTerm is not affiliated with Anthropic. Just a fan who couldn't stop using Claude Code.*
6
-
7
- ---
8
-
9
- ## Screenshots
10
-
11
1
  <p align="center">
12
2
  <img src="https://ghostterm.pages.dev/img/banner.png" width="500" alt="GhostTerm Banner">
13
3
  </p>
14
4
 
5
+ <h1 align="center">GhostTerm</h1>
15
6
  <p align="center">
16
- <img src="https://ghostterm.pages.dev/img/office-busy.jpg" width="220" alt="Ghosts working">
17
- <img src="https://ghostterm.pages.dev/img/pixel-office.jpg" width="220" alt="Pixel office overview">
18
- <img src="https://ghostterm.pages.dev/img/claude-code.jpg" width="220" alt="Claude Code on phone">
7
+ <strong>A mobile terminal for Claude Code fans.</strong><br>
8
+ Control your PC from your phone — real CLI, not a toy.
19
9
  </p>
20
-
21
10
  <p align="center">
22
- <em>Halloween-themed pixel office · 4 animated ghost terminals · Claude Code on your phone</em>
11
+ <a href="https://www.npmjs.com/package/ghostterm"><img src="https://img.shields.io/npm/v/ghostterm.svg" alt="npm version"></a>
12
+ <a href="https://www.npmjs.com/package/ghostterm"><img src="https://img.shields.io/npm/dm/ghostterm.svg" alt="npm downloads"></a>
13
+ <img src="https://img.shields.io/node/v/ghostterm" alt="node version">
14
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license">
23
15
  </p>
24
16
 
17
+ > *GhostTerm is not affiliated with Anthropic. Just a fan who couldn't stop using Claude Code.*
18
+
25
19
  ---
26
20
 
27
- ## Why GhostTerm?
21
+ ## What is GhostTerm?
22
+
23
+ GhostTerm lets you **control your PC terminal from your phone** over the internet. It's built specifically for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) users who want to:
28
24
 
29
- You're running Claude Code on your PC. You walk away. Now what?
25
+ - Run `claude --dangerously-skip-permissions` and monitor everything from their phone
26
+ - Approve/deny tool calls from anywhere (bus, bed, coffee shop)
27
+ - Manage 4 terminal sessions simultaneously
30
28
 
31
- - **Run `--dangerously-skip-permissions`** let Claude go full auto, monitor from your phone while it codes for you
32
- - **4 terminal sessions at once** — more than Anthropic's official app
33
- - **Real xterm.js terminal** — full ANSI colors, scrollback, not a dumbed-down GUI
34
- - **Built-in shortcut keys** — `y` / `n` for approvals, `Tab`, `Ctrl+C`, arrow keys, all one-tap
35
- - **`claude` quick-launch button** — start new sessions, resume, or continue with one tap
36
- - **Pixel office mode** — see all 4 terminals as cute ghost desks
29
+ No VPN. No Tailscale. No port forwarding. Just one command.
30
+
31
+ ---
37
32
 
38
33
  ## Quick Start
39
34
 
@@ -45,15 +40,96 @@ npx ghostterm
45
40
 
46
41
  First run opens a browser for Google sign-in. After that, it remembers you.
47
42
 
43
+ **Run in background (no terminal window):**
44
+
45
+ ```bash
46
+ pm2 start ghostterm.js --name ghostterm
47
+ pm2 save
48
+ ```
49
+
48
50
  ### 2. On your phone
49
51
 
50
- Open **[ghostterm.pages.dev](https://ghostterm.pages.dev)** sign in with the same Google account.
52
+ Open **[ghostterm.pages.dev](https://ghostterm.pages.dev)** in any mobile browser. Sign in with the same Google account.
53
+
54
+ **That's it.** Your terminal appears on your phone.
55
+
56
+ ---
57
+
58
+ ## Screenshots
59
+
60
+ <p align="center">
61
+ <img src="https://ghostterm.pages.dev/img/office-busy.jpg" width="220" alt="Ghosts working">
62
+ <img src="https://ghostterm.pages.dev/img/pixel-office.jpg" width="220" alt="Pixel office">
63
+ <img src="https://ghostterm.pages.dev/img/claude-code.jpg" width="220" alt="Claude Code on phone">
64
+ </p>
65
+ <p align="center">
66
+ <em>Pixel ghost office · 4 terminal sessions · Claude Code on your phone</em>
67
+ </p>
68
+
69
+ ---
70
+
71
+ ## Features
72
+
73
+ ### Terminal
74
+
75
+ - **Real xterm.js terminal** — full ANSI colors, 256-color, scrollback buffer
76
+ - **4 simultaneous sessions** — more than Anthropic's official mobile app
77
+ - **Auto-resize** — terminal adapts to your phone's screen size
78
+ - **Scrollback history** — scroll up to see previous output, page up/down buttons
79
+
80
+ ### Controls
81
+
82
+ - **Quick keys** — one-tap `y`/`n` for Claude Code approvals
83
+ - **12345 numpad** — tap to pop up number selection for CLI surveys/prompts (raw keypress, no Enter)
84
+ - **D-pad** — arrow keys, Enter, Tab, Shift+Tab, Space
85
+ - **`claude` button** — quick-launch menu: new session, resume, continue, dangerous mode
86
+ - **Ctrl+C (Stop)** — interrupt running processes
87
+ - **Text input** — full keyboard input with Send button
88
+ - **Copy mode** — select and copy terminal text
89
+
90
+ ### File Transfer
91
+
92
+ - **Screen** — capture your terminal screen and send it to your PC as a file
93
+ - **File upload** — upload files directly from your phone to your desktop
94
+ - **Paste button** — after uploading, shows shortened filename; tap to paste the file path into the terminal
95
+
96
+ ### Visual
97
+
98
+ - **Pixel office mode** — see all 4 terminals as cute ghost desks in a Halloween-themed pixel office
99
+ - **Ghost cell previews** — live miniature terminal previews in the header
100
+ - **Dark theme** — easy on the eyes, matches terminal aesthetics
101
+
102
+ ### Connection
103
+
104
+ - **Google auto-pairing** — sign in once, auto-reconnects forever
105
+ - **Encrypted relay** — all traffic over WSS (WebSocket Secure)
106
+ - **Zero data stored** — the relay only forwards messages
107
+ - **Heartbeat** — relay pings every 20s; dead connections detected and auto-reconnected within 30s
108
+ - **Auto-reconnect** — exponential backoff (1s → 30s max), handles network drops gracefully
109
+ - **Session persistence** — refreshing the page restores your last active terminal session
110
+
111
+ ---
112
+
113
+ ## How It Works
114
+
115
+ ```
116
+ Phone (browser) ──WSS──> Relay (Fly.io Tokyo) <──WSS── PC (ghostterm)
117
+ encrypted WebSocket
118
+ auto-pairs by Google account
119
+ zero data stored
120
+ ```
121
+
122
+ 1. `npx ghostterm` starts a companion process on your PC that connects to the relay server
123
+ 2. The companion spawns a real PTY (pseudo-terminal) using `node-pty`
124
+ 3. Your phone connects to the same relay via WebSocket
125
+ 4. The relay matches both sides by Google account and forwards messages
126
+ 5. Terminal output streams to your phone; your input streams to the PTY
51
127
 
52
- That's it. Your terminal appears on your phone. No VPN. No Tailscale. No port forwarding.
128
+ ---
53
129
 
54
130
  ## Use Cases
55
131
 
56
- ### 🔥 The "Dangerous" Workflow
132
+ ### The "Dangerous" Workflow
57
133
 
58
134
  ```bash
59
135
  claude --dangerously-skip-permissions
@@ -61,75 +137,140 @@ claude --dangerously-skip-permissions
61
137
 
62
138
  Let Claude Code run fully autonomous on your PC. Monitor everything from your phone. Intervene when needed. Go make coffee.
63
139
 
64
- ### 🖥️ Multi-Session Power
140
+ ### Multi-Session Power
65
141
 
66
142
  4 ghost cells = 4 terminals. Run Claude Code in one, `git log` in another, `npm test` in a third. Switch between them with a tap.
67
143
 
68
- ### 📱 On-the-Go Approval
144
+ ### On-the-Go Approval
69
145
 
70
146
  Claude Code asking "May I edit server.js?" — tap `y` from the bus. No need to rush back to your desk.
71
147
 
72
- ### 📸 Screenshot & Upload
148
+ ---
73
149
 
74
- Take a screenshot of your phone screen and send it to your PC terminal. Upload files directly from your phone to your desktop.
150
+ ## System Requirements
75
151
 
76
- ## Features
152
+ ### PC (Companion)
77
153
 
78
- | Feature | GhostTerm | Anthropic Mobile |
79
- |---|---|---|
80
- | Real CLI terminal | ✅ | ❌ |
81
- | Simultaneous sessions | 4 | 1 |
82
- | `--dangerously-skip-permissions` | monitor from phone | ❌ |
83
- | Custom shortcut keys | ✅ y/n/Tab/Ctrl+C | ❌ |
84
- | Pixel office view | ✅ | ❌ |
85
- | File upload to PC | ✅ | ❌ |
86
- | No VPN needed | ✅ | N/A |
87
- | Google auto-pairing | ✅ | - |
154
+ - **Node.js** 18 or later
155
+ - **Operating System**: Windows, macOS, or Linux
156
+ - **Platform-specific build tools** (for `node-pty`):
157
+ - **Windows**: Visual Studio Build Tools or `npm install -g windows-build-tools`
158
+ - **macOS**: `xcode-select --install`
159
+ - **Linux**: `apt install build-essential` (Debian/Ubuntu) or equivalent
160
+ - **Google account** for pairing
161
+
162
+ ### Phone (Client)
88
163
 
89
- ## Controls
164
+ - Any modern browser (iOS Safari 15+, Chrome, Firefox, Edge)
165
+ - Internet connection
90
166
 
91
- **Top bar**: 4 ghost cells (tap to switch terminals, `+` to create new) · `🏠` pixel office view · `A` font size · `▼` hide controls
167
+ ---
92
168
 
93
- **Quick keys**: `y` / `n` (approve/deny) · `S+Tab` (shift-tab) · `/ cmd` (slash commands) · `Tab` · `←Bksp`
169
+ ## Configuration
94
170
 
95
- **Left column**: `⏻ claude` (launch menu: new / resume / continue / dangerous mode) · `Stop` (Ctrl+C) · `Close` (kill session)
171
+ ### Environment Variables
96
172
 
97
- **Center**: D-pad (↑↓←→) + `Enter`
173
+ | Variable | Default | Description |
174
+ |---|---|---|
175
+ | `GHOSTTERM_RELAY` | `wss://ghostterm-relay.fly.dev` | Custom relay server URL |
98
176
 
99
- **Right column**: `Line↵` (newline) · `⬇` (scroll to bottom) · `Space` · `▲▼` (page up/down) · `Copy` (select mode)
177
+ ### Custom Relay
178
+
179
+ If you want to self-host the relay:
180
+
181
+ ```bash
182
+ GHOSTTERM_RELAY=wss://your-relay.example.com npx ghostterm
183
+ ```
100
184
 
101
- **Bottom**: Text input + `Send` · `📷 Shot` (screenshot to PC) · `📁 File` (upload to PC)
185
+ ---
102
186
 
103
187
  ## Pricing
104
188
 
105
- - **Free**: 1 hour/day, full features
106
- - **Pro**: $5/month or $12/quarter — unlimited access
189
+ GhostTerm is currently **free** during early access. Pro plans coming soon.
107
190
 
108
- ## How It Works
191
+ ---
192
+
193
+ ## Troubleshooting
194
+
195
+ ### "Failed to install node-pty" / build errors
196
+
197
+ `node-pty` requires native compilation. Make sure you have build tools installed:
109
198
 
199
+ ```bash
200
+ # Windows (run as Administrator)
201
+ npm install -g windows-build-tools
202
+
203
+ # macOS
204
+ xcode-select --install
205
+
206
+ # Linux (Debian/Ubuntu)
207
+ sudo apt install build-essential python3
110
208
  ```
111
- Phone (browser) ──WSS──▶ Relay (Fly.io Tokyo) ◀──WSS── PC (ghostterm)
112
- encrypted WebSocket
113
- auto-pairs by Google account
114
- zero data stored
209
+
210
+ ### "Google sign-in window doesn't open"
211
+
212
+ - Make sure your default browser isn't blocking pop-ups
213
+ - Try running `npx ghostterm` again — it retries automatically
214
+ - If behind a corporate proxy, ensure `accounts.google.com` is accessible
215
+
216
+ ### "Phone can't connect" / "Waiting for companion..."
217
+
218
+ - Ensure the PC companion is still running (`npx ghostterm`)
219
+ - Both devices must use the **same Google account**
220
+ - Check your phone's internet connection
221
+ - Try refreshing the page on your phone
222
+
223
+ ### "Terminal shows garbled text"
224
+
225
+ - Make sure your phone browser supports modern CSS/JS
226
+ - Try switching to a different terminal session (tap a ghost cell)
227
+ - Clear browser cache and reload
228
+
229
+ ### "Session keeps disconnecting"
230
+
231
+ - Check your network stability on both PC and phone
232
+ - The relay auto-reconnects with exponential backoff
233
+ - If using a VPN, try disabling it (GhostTerm doesn't need one)
234
+
235
+ ### node-pty on Apple Silicon (M1/M2/M3)
236
+
237
+ If you see architecture mismatch errors:
238
+
239
+ ```bash
240
+ # Force rebuild for current architecture
241
+ npm rebuild node-pty
115
242
  ```
116
243
 
117
- All traffic is encrypted (WSS). The relay only forwards messages — no terminal data is stored.
244
+ ---
118
245
 
119
- ## Requirements
246
+ ## Uninstall
120
247
 
121
- - **PC**: Node.js 18+
122
- - Windows: may need `npm install -g windows-build-tools`
123
- - macOS: `xcode-select --install`
124
- - Linux: `apt install build-essential`
125
- - **Phone**: Any modern browser (iOS Safari, Chrome, etc.)
248
+ GhostTerm stores a refresh token in `~/.ghostterm/` for auto-login. To fully remove:
126
249
 
127
- ## Environment Variables
250
+ ```bash
251
+ rm -rf ~/.ghostterm
252
+ ```
128
253
 
129
- | Variable | Default | Description |
130
- |---|---|---|
131
- | `GHOSTTERM_RELAY` | `wss://ghostterm-relay.fly.dev` | Custom relay server URL |
254
+ ---
255
+
256
+ ## Security
257
+
258
+ - All communication is encrypted via WSS (WebSocket Secure)
259
+ - Google OAuth 2.0 for authentication — GhostTerm never sees your Google password
260
+ - The relay server is stateless — no terminal data is stored
261
+ - Pair codes expire after 5 minutes
262
+ - Brute-force protection on pair code entry
263
+ - Rate limiting on all WebSocket connections
264
+ - Connection limits per IP address
265
+
266
+ ---
132
267
 
133
268
  ## License
134
269
 
135
270
  MIT
271
+
272
+ ---
273
+
274
+ <p align="center">
275
+ Built with frustration and love by a Claude Code addict.
276
+ </p>
package/bin/ghostterm.js CHANGED
@@ -409,8 +409,19 @@ function handleRelayMessage(msg) {
409
409
 
410
410
  case 'upload':
411
411
  try {
412
+ const UPLOAD_MAX_SIZE = 5 * 1024 * 1024; // 5MB
413
+ const UPLOAD_EXT_WHITELIST = ['.png', '.jpg', '.jpeg', '.pdf', '.txt', '.md', '.json', '.csv', '.py', '.js', '.ts', '.html', '.css'];
414
+ const ext = (msg.ext || '.png').toLowerCase();
415
+ if (!UPLOAD_EXT_WHITELIST.includes(ext)) {
416
+ sendToRelay({ type: 'upload_error', message: `File type not allowed: ${ext}` });
417
+ break;
418
+ }
412
419
  const buf = Buffer.from(msg.data, 'base64');
413
- const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 6)}${msg.ext || '.png'}`;
420
+ if (buf.length > UPLOAD_MAX_SIZE) {
421
+ sendToRelay({ type: 'upload_error', message: `File too large: ${(buf.length / 1024 / 1024).toFixed(1)}MB (max 5MB)` });
422
+ break;
423
+ }
424
+ const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 6)}${ext}`;
414
425
  const filePath = path.join(UPLOAD_DIR, filename);
415
426
  fs.writeFileSync(filePath, buf);
416
427
  sendToRelay({ type: 'upload_result', path: filePath, filename, size: buf.length });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghostterm",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Mobile terminal for Claude Code — control your PC from your phone",
5
5
  "bin": {
6
6
  "ghostterm": "bin/ghostterm.js"