auvezy-terminal-remote 0.4.4 → 0.4.5
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/README.md +261 -71
- package/dist/cli.js +11 -7
- package/frontend-dist/assets/{eruda-yHyqIqVX.js → eruda-JgMQJMlu.js} +1 -1
- package/frontend-dist/assets/index-CfHptVXT.js +340 -0
- package/frontend-dist/assets/index-DMTUuNcV.css +32 -0
- package/frontend-dist/index.html +2 -2
- package/frontend-dist/sw.js +1 -1
- package/package.json +1 -1
- package/frontend-dist/assets/index-CmEDzLbV.css +0 -32
- package/frontend-dist/assets/index-GlsB_6pe.js +0 -335
package/README.md
CHANGED
|
@@ -1,107 +1,297 @@
|
|
|
1
1
|
# auvezy-terminal-remote
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**English** | [简体中文](https://github.com/jjj201200/auvezy-terminal-remote/blob/main/README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
> Remote-control any terminal program on your PC (zsh / bash / claude / any CLI)
|
|
6
|
+
> from a phone or tablet browser over LAN.
|
|
4
7
|
>
|
|
5
|
-
>
|
|
8
|
+
> One command — `atr <program>` — and every instance shows up as a tab in your
|
|
9
|
+
> browser's top bar.
|
|
10
|
+
|
|
11
|
+
> **License: [PolyForm Noncommercial 1.0.0](./LICENSE)** —
|
|
12
|
+
> free for personal, educational, and nonprofit use, including modification and
|
|
13
|
+
> redistribution. Commercial use requires a separate license.
|
|
14
|
+
|
|
15
|
+
## What is this
|
|
6
16
|
|
|
7
|
-
|
|
17
|
+
You're on the couch with your phone. A long-running CLI on your PC
|
|
18
|
+
(Claude Code / a deploy script / a debug session…) is doing its thing and
|
|
19
|
+
you want to:
|
|
8
20
|
|
|
9
|
-
|
|
21
|
+
- See its live output (ANSI colors included)
|
|
22
|
+
- Type the next command, hit arrow keys
|
|
23
|
+
- Get a phone notification when Claude triggers an approval hook
|
|
24
|
+
- Not open any port to the public internet, not depend on a cloud service
|
|
10
25
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- 不开公网、不依赖云
|
|
26
|
+
That's exactly what this project does. PTY output is bridged over WebSocket
|
|
27
|
+
to a webapp; webapp input is bridged back to the PTY. Listens on LAN IPs only,
|
|
28
|
+
authed by token + local cookie.
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
把 webapp 输入桥回 PTY。仅绑 LAN IP,用 token + 本地 cookie 鉴权。
|
|
30
|
+
## Quick start
|
|
18
31
|
|
|
19
|
-
|
|
32
|
+
### Global install (npm users)
|
|
20
33
|
|
|
21
34
|
```bash
|
|
22
|
-
npm install -g auvezy-terminal-remote
|
|
35
|
+
npm install -g auvezy-terminal-remote # -g is required
|
|
23
36
|
```
|
|
24
37
|
|
|
25
|
-
|
|
38
|
+
> ⚠️ The default `npm i auvezy-terminal-remote` shown at the top right of the
|
|
39
|
+
> npm package page is **missing `-g`**. This is a CLI tool — without `-g` the
|
|
40
|
+
> `atr` binary won't be on your PATH. Use the command above.
|
|
41
|
+
|
|
42
|
+
Then in any terminal:
|
|
26
43
|
|
|
27
44
|
```bash
|
|
28
|
-
atr #
|
|
29
|
-
atr claude #
|
|
30
|
-
atr zsh #
|
|
31
|
-
atr claude --resume foo #
|
|
45
|
+
atr # runs your $SHELL (auto-detects zsh / bash)
|
|
46
|
+
atr claude # runs claude
|
|
47
|
+
atr zsh # runs zsh
|
|
48
|
+
atr claude --resume foo # passes any args through to the child process
|
|
32
49
|
```
|
|
33
50
|
|
|
34
|
-
|
|
51
|
+
After it starts, scan the QR code printed in the terminal — the webapp logs in
|
|
52
|
+
automatically (token lives in `~/.auvezy/terminal-remote/config.json`).
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
**Multiple instances**: Run `atr <prog>` in different terminals; each grabs the
|
|
55
|
+
next available port (3000, 3001, 3002…). Tabs for new instances appear in the
|
|
56
|
+
browser's top bar automatically — click to switch.
|
|
38
57
|
|
|
39
58
|
```bash
|
|
40
|
-
atr list #
|
|
41
|
-
atr stop #
|
|
42
|
-
atr attach <url> #
|
|
59
|
+
atr list # list all running instances on this machine
|
|
60
|
+
atr stop # stop all instances on this machine
|
|
61
|
+
atr attach <url> # take over a running instance from the command line
|
|
43
62
|
```
|
|
44
63
|
|
|
45
|
-
|
|
64
|
+
### From source (development or self-build)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# GitHub (primary)
|
|
68
|
+
git clone https://github.com/jjj201200/auvezy-terminal-remote.git
|
|
69
|
+
# or Gitee mirror (faster from mainland China)
|
|
70
|
+
git clone https://gitee.com/drowsyflesh/auvezy-terminal-remote.git
|
|
46
71
|
|
|
72
|
+
cd auvezy-terminal-remote
|
|
73
|
+
bash install.sh # checks Node 20+ / pnpm 9+ / build deps → installs → builds
|
|
74
|
+
node backend/dist/cli.js # equivalent to `atr`
|
|
47
75
|
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
## Feature matrix
|
|
79
|
+
|
|
80
|
+
| Feature | How it's implemented |
|
|
81
|
+
|---|---|
|
|
82
|
+
| PTY bridge | node-pty + xterm.js 5 |
|
|
83
|
+
| Auth | timingSafeEqual token + Session Cookie (port-bound) |
|
|
84
|
+
| Multi-instance | port-finder auto-increment + cookie-name suffix isolation |
|
|
85
|
+
| Reconnect / replay | OutputBuffer + history_sync (alt-screen filtered by default) |
|
|
86
|
+
| Approval push | Web Push (VAPID, 3 priorities) + iOS Safari LocalNotification fallback |
|
|
87
|
+
| IP drift detection | 30s polling + stability threshold + ip_changed broadcast |
|
|
88
|
+
| Config rewrite | Webapp Settings dialog → /api/config |
|
|
89
|
+
| `attach` subcommand | Master arbitration (webapp > attach > PC) |
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
On startup the backend reads `~/.auvezy/terminal-remote/config.json`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"token": "<64-char hex, auto-generated>",
|
|
98
|
+
"shortcuts": [
|
|
99
|
+
{ "label": "ESC", "data": "" },
|
|
100
|
+
{ "label": "↑", "data": "[A" }
|
|
101
|
+
],
|
|
102
|
+
"command": null,
|
|
103
|
+
"args": null,
|
|
104
|
+
"rateLimitPerMinute": 10,
|
|
105
|
+
"sessionTtlMs": 86400000
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
VAPID keys live in the same directory: `vapid.json` (mode 0o600, auto-generated
|
|
110
|
+
or read from env vars `VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY`).
|
|
111
|
+
|
|
112
|
+
Subscriptions are in `push-subscriptions.json`; the multi-instance registry is in
|
|
113
|
+
`instances/<port>.json`.
|
|
114
|
+
|
|
115
|
+
## Startup options
|
|
116
|
+
|
|
68
117
|
```
|
|
118
|
+
atr [subcommand] [options]
|
|
69
119
|
|
|
70
|
-
|
|
120
|
+
Subcommands:
|
|
121
|
+
start start the backend (default)
|
|
122
|
+
attach attach to a running instance from the command line
|
|
123
|
+
list list all running instances on this machine
|
|
124
|
+
stop stop all instances on this machine
|
|
71
125
|
|
|
72
|
-
|
|
126
|
+
Options:
|
|
127
|
+
-p, --port <n> port (default 3000, auto-increments unless -S)
|
|
128
|
+
-S, --strict-port strict port mode: fail if port is taken, no fallback
|
|
129
|
+
--spawn-timeout <s> PTY spawn fallback seconds (default 30; 0 = no timeout;
|
|
130
|
+
first browser connect / Enter / timeout — whichever first)
|
|
131
|
+
--wait-confirm require Enter to spawn (overrides browser/timeout triggers)
|
|
132
|
+
--name <s> instance name (shown in webapp)
|
|
133
|
+
--no-terminal don't print QR code (CI / daemon-friendly)
|
|
134
|
+
--command <cmd> PTY command (default: 'claude')
|
|
135
|
+
--args <json> command args (JSON array string)
|
|
136
|
+
-h, --help show help
|
|
137
|
+
-v, --version show version
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Environment variables:
|
|
141
|
+
|
|
142
|
+
| Variable | Purpose |
|
|
73
143
|
|---|---|
|
|
74
|
-
| `OCR_COMMAND` |
|
|
75
|
-
| `OCR_ARGS` |
|
|
76
|
-
| `OCR_CWD` |
|
|
77
|
-
| `OCR_ANSI_FILTER` |
|
|
78
|
-
| `OCR_ANSI_FILTER_TUI_NAMES` |
|
|
79
|
-
| `VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY` |
|
|
80
|
-
| `PORT` |
|
|
81
|
-
| `STRICT_PORT` |
|
|
82
|
-
| `OCR_SPAWN_TIMEOUT` |
|
|
83
|
-
| `AUTH_TOKEN` |
|
|
84
|
-
| `LOG_LEVEL` | pino
|
|
144
|
+
| `OCR_COMMAND` | Child command (default `$SHELL`, or `/bin/sh`; set to `claude` to run Claude) |
|
|
145
|
+
| `OCR_ARGS` | Command args (JSON array string, e.g. `'["-c","tail -f /dev/null"]'`) |
|
|
146
|
+
| `OCR_CWD` | Child process working directory (default: `process.cwd()`) |
|
|
147
|
+
| `OCR_ANSI_FILTER` | Filter alt-screen output (default `false`). Set `true` for cleaner reconnect replay after vim/htop exits; full-time alt-screen TUIs (claude/tmux/...) are still protected by built-in blocklist |
|
|
148
|
+
| `OCR_ANSI_FILTER_TUI_NAMES` | Append to your own alt-screen TUI blocklist (comma-separated), e.g. `"lazygit,k9s,gh-dash"` |
|
|
149
|
+
| `VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY` | Inject VAPID keys (highest priority, skips file) |
|
|
150
|
+
| `PORT` | Same as `--port` |
|
|
151
|
+
| `STRICT_PORT` | Same as `--strict-port` (set `true` to enable strict mode) |
|
|
152
|
+
| `OCR_SPAWN_TIMEOUT` | Same as `--spawn-timeout` (seconds; 0 = no timeout) |
|
|
153
|
+
| `AUTH_TOKEN` | Specify token (default: auto-generated) |
|
|
154
|
+
| `LOG_LEVEL` | pino level (default `info`) |
|
|
155
|
+
|
|
156
|
+
> Legacy names `CLAUDE_COMMAND` / `CLAUDE_ARGS` / `CLAUDE_CWD` still work
|
|
157
|
+
> (warned once at startup). Renamed to make it clear: this project is not tied
|
|
158
|
+
> to Claude — it can run any PTY program.
|
|
159
|
+
|
|
160
|
+
## Install as a PWA (recommended on mobile)
|
|
161
|
+
|
|
162
|
+
The webapp ships with a manifest. "Add to Home Screen" gives you a near-native
|
|
163
|
+
app experience:
|
|
164
|
+
|
|
165
|
+
- **Android Chrome**: top-right ⋮ → "Install app" (or the address bar shows an
|
|
166
|
+
"Install" prompt)
|
|
167
|
+
- **iOS Safari**: share button → "Add to Home Screen"
|
|
168
|
+
|
|
169
|
+
After install: no browser UI (no address bar, no bottom nav), independent task
|
|
170
|
+
card, status bar matches the app color.
|
|
171
|
+
|
|
172
|
+
> **Web Push limitations**: browsers require Push to be in a secure context
|
|
173
|
+
> (HTTPS / localhost). LAN HTTP (http://192.168.x.x) cannot subscribe to push.
|
|
174
|
+
> The settings panel will display "HTTPS required". Workarounds: use Tailscale /
|
|
175
|
+
> Cloudflare Tunnel to put HTTPS in front of the backend, or deploy with a
|
|
176
|
+
> self-signed certificate.
|
|
177
|
+
|
|
178
|
+
## Running in WSL, accessing from Windows browser
|
|
179
|
+
|
|
180
|
+
WSL2 has two network modes that behave differently:
|
|
181
|
+
|
|
182
|
+
- **Mirrored mode** (Win11 22H2+ default): WSL gets the Windows LAN IP directly
|
|
183
|
+
(e.g. `192.168.x.x`). Windows browsers can use the IP printed on the banner,
|
|
184
|
+
no extra config.
|
|
185
|
+
- **NAT mode** (default): WSL is on `172.x.x.x` private network — Windows
|
|
186
|
+
browsers can't connect directly. The backend detects this on startup and
|
|
187
|
+
prints PowerShell config commands at the end of the banner.
|
|
188
|
+
|
|
189
|
+
**One-shot auto config** (admin PowerShell):
|
|
190
|
+
|
|
191
|
+
```powershell
|
|
192
|
+
# Forward common port range (default 3000–3010)
|
|
193
|
+
.\scripts\wsl-port-forward.ps1
|
|
194
|
+
|
|
195
|
+
# Forward specific ports only
|
|
196
|
+
.\scripts\wsl-port-forward.ps1 -Ports 3000,3001
|
|
197
|
+
|
|
198
|
+
# Register to re-forward on login (no manual re-run when WSL IP changes)
|
|
199
|
+
.\scripts\wsl-port-forward.ps1 -Persist
|
|
200
|
+
|
|
201
|
+
# Cleanup
|
|
202
|
+
.\scripts\wsl-port-forward.ps1 -Reset
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Architecture / decisions
|
|
206
|
+
|
|
207
|
+
- Design doc: [`docs/plans/open-claude-remote-clone/design.md`](./docs/plans/open-claude-remote-clone/design.md)
|
|
208
|
+
- Module diagram and data flow: [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md)
|
|
209
|
+
- Architecture decision records (ADRs):
|
|
210
|
+
[`docs/plans/open-claude-remote-clone/adrs/`](./docs/plans/open-claude-remote-clone/adrs/)
|
|
211
|
+
|
|
212
|
+
## Development
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
pnpm install
|
|
216
|
+
pnpm dev # backend (tsx watch) + frontend (vite) in parallel
|
|
217
|
+
pnpm test # shared + backend + frontend unit tests
|
|
218
|
+
pnpm typecheck
|
|
219
|
+
pnpm build # full build artifacts (frontend copied into backend/frontend-dist)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
## Roadmap
|
|
224
|
+
|
|
225
|
+
### Tier 1 (must-have for mobile, low effort, big UX win)
|
|
226
|
+
|
|
227
|
+
1. **Local Echo** (Mosh / Blink / code-server)
|
|
228
|
+
Input lag killer on mobile 4G/weak networks. xterm prediction plugin shows
|
|
229
|
+
keystrokes immediately, PTY response replaces.
|
|
230
|
+
2. **Multi-line paste warning + bracketed paste** (VS Code, Tabby)
|
|
231
|
+
Mobile users paste 5-line commands from WeChat/email — currently goes
|
|
232
|
+
straight to PTY, dangerous. Detect multi-line → confirm dialog.
|
|
233
|
+
3. **Shell Integration subset (OSC 633/133)**
|
|
234
|
+
- Command decorations (green/red dot)
|
|
235
|
+
- Run Recent Command — fuzzy cross-session history quick pick
|
|
236
|
+
- Both extremely friendly on mobile (slow typing → cross-session history
|
|
237
|
+
search is core)
|
|
238
|
+
4. **Auto Reply** (VS Code)
|
|
239
|
+
Match prompt → auto-respond y/N. Mobile users hate typing `[y/N]`.
|
|
240
|
+
5. **Process Revive** (VS Code terminal revive)
|
|
241
|
+
You already have instances.json; serialize scrollback into it. After restart
|
|
242
|
+
webapp can see the previous content. The only hard part on the LAN-only
|
|
243
|
+
route is serialization size — bumping to 5MB is fine.
|
|
85
244
|
|
|
86
|
-
|
|
245
|
+
### Tier 2 (mobile UX bonus)
|
|
87
246
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
247
|
+
6. **SmartKeys long-press menu** (Blink)
|
|
248
|
+
On-screen keyboard expansion row: long-press Tab → Shift+Tab; long-press Esc
|
|
249
|
+
→ `^[`; long-press Ctrl → sticky until next key. We already have a Toolbar
|
|
250
|
+
shortcut panel, missing "long-press menu" + "modifier sticky".
|
|
251
|
+
7. **Thumb-drag cursor strip** (Termius: long-press space as trackpad)
|
|
252
|
+
Bottom 8px transparent strip on the terminal area; drag = arrow key
|
|
253
|
+
sequence. Best solution for precise cursor movement on mobile.
|
|
254
|
+
8. **OSC 8 hyperlinks + word-link / file-link** (VS Code)
|
|
255
|
+
xterm.js native LinkProvider — a few lines makes `src/foo.ts:42` clickable.
|
|
256
|
+
9. **Multi-chord shortcuts / modifier sticky** (Tabby, Blink)
|
|
257
|
+
Mobile virtual modifier + Cmd-K Cmd-S two-step combos save more screen than
|
|
258
|
+
a wall of buttons.
|
|
259
|
+
10. **Quick Fixes** (VS Code)
|
|
260
|
+
Scan output, suggest fixes. `fatal: ... --set-upstream` one-click apply.
|
|
261
|
+
High effort but very flashy.
|
|
91
262
|
|
|
92
|
-
|
|
263
|
+
### Tier 3 (write permission / security / collaboration)
|
|
93
264
|
|
|
94
|
-
|
|
265
|
+
11. **Writable / Read-only split** (ttyd -W, gotty -w)
|
|
266
|
+
When multiple devices connect to one instance, others can be set to
|
|
267
|
+
read-only. Very low effort (distinguish at WS handshake).
|
|
268
|
+
12. **Broadcast Input** (Termius: simultaneous input on multiple terminals)
|
|
269
|
+
When multiple webapps connect to one instance, broadcast the same input to
|
|
270
|
+
all PTYs. Easy to add to our multi-instance arch.
|
|
271
|
+
13. **TLS self-signed cert** (ttyd -S, gotty -t)
|
|
272
|
+
HTTPS on LAN lets Web Push API work in more browsers (currently restricted
|
|
273
|
+
on LAN HTTP).
|
|
274
|
+
14. **OAuth / client cert auth** (ttyd client cert)
|
|
275
|
+
On top of our token, add client cert for hardware auth. Low priority —
|
|
276
|
+
token is already enough.
|
|
95
277
|
|
|
96
|
-
|
|
97
|
-
Windows 浏览器可以直接用 banner 上的 IP 访问,无需任何额外配置
|
|
98
|
-
- **NAT 模式**(默认):WSL 在 `172.x.x.x` 私网,Windows 浏览器无法直连。
|
|
99
|
-
backend 启动时会自动检测并在 banner 末尾打印 PowerShell 配置命令
|
|
278
|
+
### Tier 4 (explicitly NOT copying)
|
|
100
279
|
|
|
101
|
-
|
|
280
|
+
- ❌ Plugin system (Tabby): unnecessary for a LAN-only single binary
|
|
281
|
+
- ❌ Cloud Settings Sync (VS Code): conflicts with the LAN-only red line
|
|
282
|
+
- ❌ Sixel/iTerm image protocols: low value on mobile, xterm.js doesn't
|
|
283
|
+
natively support them
|
|
284
|
+
- ❌ asciinema public sharing: conflicts with LAN-only; if anything we'd only
|
|
285
|
+
do local `.cast` export
|
|
286
|
+
- ❌ SFTP/SCP file management (Termius/Wetty): outside the "remote PTY control"
|
|
287
|
+
scope
|
|
288
|
+
- ❌ End-to-end encrypted Vault: home LAN users don't need this
|
|
102
289
|
|
|
103
|
-
|
|
290
|
+
---
|
|
104
291
|
|
|
105
|
-
##
|
|
292
|
+
## Pain points unique to us (others haven't done these)
|
|
106
293
|
|
|
107
|
-
|
|
294
|
+
- **Tailscale / VPN QR code labeling**: we already do dual LAN+Tailscale codes —
|
|
295
|
+
a thoughtful detail on the LAN-only route
|
|
296
|
+
- **Webapp toast notification + iOS LocalNotification fallback**: under iOS PWA
|
|
297
|
+
push restrictions, this fallback strategy isn't considered by anyone else
|
package/dist/cli.js
CHANGED
|
@@ -37,7 +37,7 @@ function isServerMessage(value) {
|
|
|
37
37
|
if (!value || typeof value !== "object")
|
|
38
38
|
return false;
|
|
39
39
|
const type = value.type;
|
|
40
|
-
return type === "terminal_output" || type === "status_update" || type === "history_sync" || type === "heartbeat" || type === "error" || type === "session_ended" || type === "terminal_resize" || type === "ip_changed";
|
|
40
|
+
return type === "terminal_output" || type === "status_update" || type === "history_sync" || type === "heartbeat" || type === "error" || type === "session_ended" || type === "terminal_resize" || type === "ip_changed" || type === "alt_screen_change";
|
|
41
41
|
}
|
|
42
42
|
var init_ws_protocol = __esm({
|
|
43
43
|
"shared/dist/ws-protocol.js"() {
|
|
@@ -1755,7 +1755,7 @@ var init_pty_manager = __esm({
|
|
|
1755
1755
|
*/
|
|
1756
1756
|
write(data) {
|
|
1757
1757
|
if (!this.process) {
|
|
1758
|
-
logger.
|
|
1758
|
+
logger.debug({ dataLength: data.length }, "\u5C1D\u8BD5\u5199\u5165 PTY \u4F46\u8FDB\u7A0B\u672A\u8FD0\u884C");
|
|
1759
1759
|
return;
|
|
1760
1760
|
}
|
|
1761
1761
|
this.process.write(data);
|
|
@@ -1864,6 +1864,7 @@ var init_pty_manager = __esm({
|
|
|
1864
1864
|
if (this._inAltScreen !== isEnter) {
|
|
1865
1865
|
this._inAltScreen = isEnter;
|
|
1866
1866
|
logger.debug({ inAltScreen: isEnter }, "PTY alt-screen \u72B6\u6001\u5207\u6362");
|
|
1867
|
+
this.emit("altScreenChange", isEnter);
|
|
1867
1868
|
}
|
|
1868
1869
|
}
|
|
1869
1870
|
}
|
|
@@ -1974,7 +1975,7 @@ var init_ws_server = __esm({
|
|
|
1974
1975
|
}
|
|
1975
1976
|
const clientType = this.opts.authenticate ? this.opts.authenticate(req) : "webapp";
|
|
1976
1977
|
if (clientType === null) {
|
|
1977
|
-
logger.
|
|
1978
|
+
logger.debug({ url: req.url }, "WS upgrade \u88AB\u9274\u6743\u62D2\u7EDD");
|
|
1978
1979
|
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
1979
1980
|
socket.destroy();
|
|
1980
1981
|
return;
|
|
@@ -2433,6 +2434,9 @@ var init_session_controller = __esm({
|
|
|
2433
2434
|
this.pty.on("resize", (cols, rows) => {
|
|
2434
2435
|
this.ws.broadcast({ type: "terminal_resize", cols, rows });
|
|
2435
2436
|
});
|
|
2437
|
+
this.pty.on("altScreenChange", (inAltScreen) => {
|
|
2438
|
+
this.ws.broadcast({ type: "alt_screen_change", inAltScreen });
|
|
2439
|
+
});
|
|
2436
2440
|
}
|
|
2437
2441
|
/**
|
|
2438
2442
|
* 入队一段 PTY 输出,按三阈值决定是否立即 flush
|
|
@@ -2931,7 +2935,7 @@ function createWsAuthenticate(authModule) {
|
|
|
2931
2935
|
logger.info({ remoteAddress: req.socket.remoteAddress }, "WS \u901A\u8FC7 URL token \u8BA4\u8BC1\uFF08attach\uFF09");
|
|
2932
2936
|
return "attach";
|
|
2933
2937
|
}
|
|
2934
|
-
logger.
|
|
2938
|
+
logger.debug({ remoteAddress: req.socket.remoteAddress }, "WS URL token \u65E0\u6548");
|
|
2935
2939
|
return null;
|
|
2936
2940
|
}
|
|
2937
2941
|
const cookieHeader = req.headers.cookie ?? "";
|
|
@@ -2939,7 +2943,7 @@ function createWsAuthenticate(authModule) {
|
|
|
2939
2943
|
if (sid && authModule.validateSession(sid)) {
|
|
2940
2944
|
return "webapp";
|
|
2941
2945
|
}
|
|
2942
|
-
logger.
|
|
2946
|
+
logger.debug({
|
|
2943
2947
|
remoteAddress: req.socket.remoteAddress,
|
|
2944
2948
|
cookieNames: cookieHeader.split(";").map((c) => c.trim().split("=")[0]).filter(Boolean),
|
|
2945
2949
|
expectedCookie: authModule.getCookieName()
|
|
@@ -4747,11 +4751,11 @@ var init_attach_client = __esm({
|
|
|
4747
4751
|
try {
|
|
4748
4752
|
parsed = JSON.parse(raw.toString());
|
|
4749
4753
|
} catch {
|
|
4750
|
-
logger.
|
|
4754
|
+
logger.debug("\u6536\u5230\u975E JSON WS \u6D88\u606F\uFF0C\u5FFD\u7565");
|
|
4751
4755
|
return;
|
|
4752
4756
|
}
|
|
4753
4757
|
if (!isServerMessage(parsed)) {
|
|
4754
|
-
logger.
|
|
4758
|
+
logger.debug("\u6536\u5230\u4E0D\u8BC6\u522B\u7684 server message\uFF0C\u5FFD\u7565");
|
|
4755
4759
|
return;
|
|
4756
4760
|
}
|
|
4757
4761
|
this.handleServerMessage(parsed);
|