hop2 0.8.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.
Files changed (50) hide show
  1. package/.hop-tmux.conf +18 -0
  2. package/INTEGRATION.md +92 -0
  3. package/README.md +260 -0
  4. package/hay/CHANGELOG.md +46 -0
  5. package/hay/DEV_NOTES.md +39 -0
  6. package/hay/README.md +290 -0
  7. package/hay/apps/cli/package.json +25 -0
  8. package/hay/apps/cli/src/index.ts +1250 -0
  9. package/hay/apps/cli/tsconfig.json +8 -0
  10. package/hay/apps/server/package.json +37 -0
  11. package/hay/apps/server/src/index.ts +103 -0
  12. package/hay/apps/server/src/lib.ts +161 -0
  13. package/hay/apps/server/src/pty.ts +68 -0
  14. package/hay/apps/server/src/rooms.ts +421 -0
  15. package/hay/apps/server/src/utils.ts +20 -0
  16. package/hay/apps/server/test/rooms.test.ts +146 -0
  17. package/hay/apps/server/tsconfig.json +9 -0
  18. package/hay/apps/web/index.html +12 -0
  19. package/hay/apps/web/package.json +32 -0
  20. package/hay/apps/web/scripts/run-e2e.mjs +130 -0
  21. package/hay/apps/web/src/App.tsx +1302 -0
  22. package/hay/apps/web/src/components/MobileKeyboard.tsx +701 -0
  23. package/hay/apps/web/src/main.tsx +13 -0
  24. package/hay/apps/web/src/setupTests.ts +1 -0
  25. package/hay/apps/web/src/styles.css +1198 -0
  26. package/hay/apps/web/src/utils/optimisticEcho.ts +115 -0
  27. package/hay/apps/web/src/utils/presence.ts +24 -0
  28. package/hay/apps/web/src/vite-env.d.ts +10 -0
  29. package/hay/apps/web/test/optimisticEcho.test.ts +39 -0
  30. package/hay/apps/web/test/presence.test.ts +18 -0
  31. package/hay/apps/web/tsconfig.json +8 -0
  32. package/hay/apps/web/vite.config.ts +13 -0
  33. package/hay/apps/web/vitest.config.ts +12 -0
  34. package/hay/package-lock.json +5988 -0
  35. package/hay/package.json +18 -0
  36. package/hay/packages/shared/package.json +27 -0
  37. package/hay/packages/shared/src/colors.ts +16 -0
  38. package/hay/packages/shared/src/index.ts +2 -0
  39. package/hay/packages/shared/src/protocol.ts +90 -0
  40. package/hay/packages/shared/test/protocol.test.ts +33 -0
  41. package/hay/packages/shared/tsconfig.json +7 -0
  42. package/hay/tsconfig.base.json +15 -0
  43. package/hay-web/assets/index-CTTzApRp.css +32 -0
  44. package/hay-web/assets/index-FDfdolCs.js +60 -0
  45. package/hay-web/assets/index-FDfdolCs.js.map +1 -0
  46. package/hay-web/index.html +13 -0
  47. package/hop +3717 -0
  48. package/package.json +52 -0
  49. package/sessions.html +243 -0
  50. package/tunnel-shell.js +254 -0
package/hay/README.md ADDED
@@ -0,0 +1,290 @@
1
+ # Termshare
2
+
3
+ > **Looking for a complete remote terminal solution?** Check out [hop](https://github.com/jzthree/hop) - secure terminal access from anywhere with authentication, Cloudflare tunneling, and session management built-in.
4
+
5
+ A terminal sharing library designed as a **building block** for applications that need shared terminal access. Multiple clients (same user on different devices, or different users) can connect to the same terminal session with real-time synchronization.
6
+
7
+ **This is not a complete solution** - it provides the core terminal sharing functionality without authentication, tunneling, or session persistence. These are intentionally left to the embedding application.
8
+
9
+ ## Features
10
+
11
+ **What it provides:**
12
+ - **Multi-client terminal** - Multiple clients share the same PTY session
13
+ - **Presence indicators** - See who's connected, who's typing, who's active
14
+ - **Control modes** - Collaborative (all can type) or locked (single controller)
15
+ - **Web and CLI clients** - Connect via browser or real terminal
16
+ - **Embeddable library** - `attachTermshare()` to add to any HTTP server
17
+ - **Auto-fit** - Terminal resizes to active client's screen
18
+ - **Mobile-ready** - Responsive web UI with slide-out drawer and haptic feedback
19
+
20
+ **What it doesn't provide (by design):**
21
+ - Authentication - bring your own (see hop for example)
22
+ - Tunneling/remote access - bring your own (Cloudflare, ngrok, etc.)
23
+ - User management - clients are identified by name parameter only
24
+
25
+ ## Comparison with ttyd
26
+
27
+ | Feature | Termshare | ttyd |
28
+ |---------|-----------|------|
29
+ | Web terminal | Yes | Yes |
30
+ | Multiple viewers | Yes | Yes |
31
+ | Real-time presence | Yes | No |
32
+ | Typing indicators | Yes | No |
33
+ | Control lock/collab modes | Yes | No |
34
+ | CLI client | Yes | No |
35
+ | Embeddable library | Yes | No |
36
+ | External dependencies | node-pty | libwebsockets |
37
+
38
+ ## Quick Start
39
+
40
+ ### Standalone
41
+
42
+ ```bash
43
+ # Install dependencies
44
+ npm install
45
+
46
+ # Start development server
47
+ npm run dev
48
+ ```
49
+
50
+ Open http://localhost:5173 and share the room link with collaborators.
51
+
52
+ ### CLI Client
53
+
54
+ ```bash
55
+ # Connect to a room from your terminal
56
+ npm -w @termshare/cli run dev -- -r my-room -n alice
57
+
58
+ # Or after building
59
+ npx termshare -r my-room -n alice
60
+ ```
61
+
62
+ #### Keyboard Shortcuts
63
+
64
+ The CLI client provides keyboard shortcuts for navigation and control:
65
+
66
+ | Key | Action |
67
+ |-----|--------|
68
+ | `←` `→` `↑` `↓` | Pan viewport |
69
+ | `0` | Center on cursor |
70
+ | `A` | Auto-fit viewport to content |
71
+ | `M` | Toggle mouse mode |
72
+ | `Ctrl+T` | Toggle hints bar |
73
+ | `Ctrl+G` | Detach from session |
74
+ | `Ctrl+Q` | Kill session |
75
+
76
+ #### Configuration
77
+
78
+ The CLI client reads configuration from these locations (first found wins):
79
+
80
+ 1. `.hay-cli.json` (local, legacy)
81
+ 2. `.hop.json` → `hay-cli` key (local)
82
+ 3. `~/.hay-cli.json` (global, legacy)
83
+ 4. `~/.hop.json` → `hay-cli` key (global)
84
+
85
+ **Example `.hop.json`:**
86
+ ```json
87
+ {
88
+ "hay-cli": {
89
+ "showHints": true,
90
+ "scrollOff": 3
91
+ }
92
+ }
93
+ ```
94
+
95
+ **Options:**
96
+
97
+ | Option | Default | Description |
98
+ |--------|---------|-------------|
99
+ | `showHints` | `true` | Show keyboard shortcut hints at bottom |
100
+ | `scrollOff` | `3` | Lines of context to keep above/below cursor when scrolling (vim-like) |
101
+
102
+ ### Web Client
103
+
104
+ The web client provides a browser-based terminal interface with:
105
+
106
+ - **Touch-friendly keyboard** - Virtual keyboard with common terminal keys
107
+ - **Haptic feedback** - Tactile feedback on iOS (via switch element trick) and Android (Vibration API)
108
+ - **Slide-out drawer** - Access presence indicators and controls on mobile
109
+ - **Responsive layout** - Adapts to screen size
110
+
111
+ ### Embedding in Your App
112
+
113
+ ```typescript
114
+ import http from "http";
115
+ import { attachTermshare } from "@termshare/server";
116
+
117
+ const server = http.createServer((req, res) => {
118
+ res.end("Hello");
119
+ });
120
+
121
+ const termshare = attachTermshare({
122
+ server,
123
+ path: "/ws", // WebSocket endpoint
124
+ onConnect: (clientId, roomId, name) => {
125
+ console.log(`${name} joined ${roomId}`);
126
+ },
127
+ onDisconnect: (clientId, roomId) => {
128
+ console.log(`${clientId} left ${roomId}`);
129
+ }
130
+ });
131
+
132
+ server.listen(4001);
133
+ ```
134
+
135
+ Connect clients to `ws://localhost:4001/ws?room=ROOM&name=NAME&cols=80&rows=24`
136
+
137
+ ## Architecture
138
+
139
+ ```
140
+ ┌─────────────────┐
141
+ │ Web Client │──┐
142
+ │ (xterm.js) │ │
143
+ └─────────────────┘ │ WebSocket ┌─────────────────┐
144
+ ├────────────────────▶│ Termshare │
145
+ ┌─────────────────┐ │ ?room=X&name=Y │ Server │──── node-pty ──── shell
146
+ │ CLI Client │──┘ │ (rooms.ts) │
147
+ │ (raw term) │ └─────────────────┘
148
+ └─────────────────┘ │
149
+ ▼
150
+ ┌─────────────┐
151
+ │ Room │
152
+ │ - clients │
153
+ │ - pty │
154
+ │ - collab │
155
+ └─────────────┘
156
+ ```
157
+
158
+ ### Protocol
159
+
160
+ Clients connect via WebSocket with query parameters:
161
+ - `room` - Room/session identifier
162
+ - `name` - Display name
163
+ - `cols` - Terminal columns
164
+ - `rows` - Terminal rows
165
+
166
+ #### Client → Server Messages
167
+
168
+ ```typescript
169
+ { type: "input", data: string } // Terminal input
170
+ { type: "resize", cols: number, rows: number } // Terminal resize
171
+ { type: "typing", active: boolean } // Typing indicator
172
+ { type: "toggle_collab", enabled: boolean } // Toggle collab mode
173
+ { type: "take_control" } // Request control (locked mode)
174
+ { type: "release_control" } // Release control
175
+ ```
176
+
177
+ #### Server → Client Messages
178
+
179
+ ```typescript
180
+ { type: "hello", clientId, roomId, color, collabMode, controllerId }
181
+ { type: "output", data: string } // Terminal output
182
+ { type: "snapshot", data: string } // Full terminal buffer
183
+ { type: "presence", clients: [...] } // Connected users
184
+ { type: "collab", enabled, controllerId } // Mode change
185
+ { type: "input_rejected", reason: string } // Input denied
186
+ ```
187
+
188
+ ## Project Structure
189
+
190
+ ```
191
+ termshare/
192
+ ├── apps/
193
+ │ ├── server/ # WebSocket + PTY server (library + standalone)
194
+ │ ├── web/ # React + xterm.js web client
195
+ │ └── cli/ # Terminal client
196
+ └── packages/
197
+ └── shared/ # Protocol types and utilities
198
+ ```
199
+
200
+ ## API Reference
201
+
202
+ ### `attachTermshare(options)`
203
+
204
+ Attach termshare to an existing HTTP server.
205
+
206
+ ```typescript
207
+ type TermshareServerOptions = {
208
+ server: http.Server; // HTTP server to attach to
209
+ path?: string; // WebSocket path (default: "/ws")
210
+ ptyFactory?: PtyFactory; // Custom PTY factory
211
+ onConnect?: (clientId, roomId, name) => void;
212
+ onDisconnect?: (clientId, roomId) => void;
213
+ };
214
+
215
+ const termshare = attachTermshare(options);
216
+
217
+ // Returns:
218
+ {
219
+ wss: WebSocketServer; // WebSocket server instance
220
+ rooms: RoomManager; // Room manager instance
221
+ close: () => void; // Cleanup function
222
+ }
223
+ ```
224
+
225
+ ### `RoomManager`
226
+
227
+ Manages terminal rooms/sessions.
228
+
229
+ ```typescript
230
+ const rooms = new RoomManager(ptyFactory);
231
+ const room = rooms.getRoom(roomId, { cols: 80, rows: 24 });
232
+ ```
233
+
234
+ ### `Room`
235
+
236
+ A single terminal session with connected clients.
237
+
238
+ ```typescript
239
+ room.attachClient(clientInfo, socketAdapter);
240
+ // Events: "empty" - emitted when last client leaves
241
+ ```
242
+
243
+ ### Custom PTY Factory
244
+
245
+ Provide your own PTY implementation:
246
+
247
+ ```typescript
248
+ const customPtyFactory = ({ cols, rows, cwd }) => {
249
+ // Return an object implementing IPty interface:
250
+ // - onData(handler): Subscribe to output
251
+ // - write(data): Send input
252
+ // - resize(cols, rows): Resize terminal
253
+ // - kill(): Terminate
254
+ };
255
+
256
+ attachTermshare({ server, ptyFactory: customPtyFactory });
257
+ ```
258
+
259
+ ## Environment Variables
260
+
261
+ | Variable | Default | Description |
262
+ |----------|---------|-------------|
263
+ | `PORT` | 4001 | Server port |
264
+ | `PTY_MODE` | native | `native`, `auto`, or `mock` |
265
+ | `SERVE_WEB` | false | Serve web client from server |
266
+ | `WEB_DIST_PATH` | - | Path to web client dist |
267
+
268
+ ## Production Build
269
+
270
+ ```bash
271
+ # Build all packages
272
+ npm run build
273
+
274
+ # Run standalone server with embedded web client
275
+ PORT=4001 SERVE_WEB=true WEB_DIST_PATH=./apps/web/dist node apps/server/dist/index.js
276
+ ```
277
+
278
+ ## Testing
279
+
280
+ ```bash
281
+ npm test # Run all tests
282
+ npm run test:unit # Unit tests only
283
+ npm run test:e2e # E2E tests (requires build)
284
+ ```
285
+
286
+ Set `PTY_MODE=mock` for CI environments that can't spawn PTYs.
287
+
288
+ ## License
289
+
290
+ MIT
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "hay-cli",
3
+ "version": "0.8.0",
4
+ "type": "module",
5
+ "private": true,
6
+ "bin": {
7
+ "hay": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "dev": "tsx src/index.ts",
11
+ "build": "tsup src/index.ts --format esm"
12
+ },
13
+ "dependencies": {
14
+ "hay-shared": "*",
15
+ "xterm-headless": "^5.3.0",
16
+ "ws": "^8.18.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^22.10.5",
20
+ "@types/ws": "^8.5.12",
21
+ "tsup": "^8.3.5",
22
+ "tsx": "^4.19.2",
23
+ "typescript": "^5.7.3"
24
+ }
25
+ }