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 +56 -0
- package/README.md +207 -66
- package/bin/ghostterm.js +12 -1
- package/package.json +1 -1
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
|
-
<
|
|
17
|
-
|
|
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
|
-
<
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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)**
|
|
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
|
-
|
|
128
|
+
---
|
|
53
129
|
|
|
54
130
|
## Use Cases
|
|
55
131
|
|
|
56
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
|
|
148
|
+
---
|
|
73
149
|
|
|
74
|
-
|
|
150
|
+
## System Requirements
|
|
75
151
|
|
|
76
|
-
|
|
152
|
+
### PC (Companion)
|
|
77
153
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
164
|
+
- Any modern browser (iOS Safari 15+, Chrome, Firefox, Edge)
|
|
165
|
+
- Internet connection
|
|
90
166
|
|
|
91
|
-
|
|
167
|
+
---
|
|
92
168
|
|
|
93
|
-
|
|
169
|
+
## Configuration
|
|
94
170
|
|
|
95
|
-
|
|
171
|
+
### Environment Variables
|
|
96
172
|
|
|
97
|
-
|
|
173
|
+
| Variable | Default | Description |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| `GHOSTTERM_RELAY` | `wss://ghostterm-relay.fly.dev` | Custom relay server URL |
|
|
98
176
|
|
|
99
|
-
|
|
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
|
-
|
|
185
|
+
---
|
|
102
186
|
|
|
103
187
|
## Pricing
|
|
104
188
|
|
|
105
|
-
|
|
106
|
-
- **Pro**: $5/month or $12/quarter — unlimited access
|
|
189
|
+
GhostTerm is currently **free** during early access. Pro plans coming soon.
|
|
107
190
|
|
|
108
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
244
|
+
---
|
|
118
245
|
|
|
119
|
-
##
|
|
246
|
+
## Uninstall
|
|
120
247
|
|
|
121
|
-
|
|
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
|
-
|
|
250
|
+
```bash
|
|
251
|
+
rm -rf ~/.ghostterm
|
|
252
|
+
```
|
|
128
253
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
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 });
|