dsh-pve-vm 0.1.0 → 0.2.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.
- package/CHANGELOG.md +66 -0
- package/README.md +34 -0
- package/client.js +535 -0
- package/index.js +9 -0
- package/lib/config.js +71 -3
- package/lib/png.js +19 -0
- package/lib/rfb.js +23 -4
- package/lib/routes.js +197 -0
- package/lib/session.js +37 -1
- package/lib/ssh.js +19 -2
- package/lib/view.js +145 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,72 @@
|
|
|
3
3
|
All notable changes to this plugin are documented here. The format follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versions follow [SemVer](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [0.2.0] — 2026-10-13
|
|
7
|
+
|
|
8
|
+
Watch the agent work: a live VM screen in the right sidebar of the web UI.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
* **The “VM screen” tab** — a right-sidebar panel that streams the frames the agent sees. The frames
|
|
13
|
+
come from the agent's own RFB session, so no second VNC session appears and the `qm vncproxy`
|
|
14
|
+
password is never reset; captures and tools share one session queue. Watch-only by design: the
|
|
15
|
+
panel injects nothing into the guest.
|
|
16
|
+
* **`viewAutoOpen`** (off by default) — reveal the tab by itself when the agent touches a console.
|
|
17
|
+
* **`viewFollowAgent`** (on by default) — the panel follows the VM the agent works with; a VM chip
|
|
18
|
+
pins it by hand. Watching never counts as agent work: frame requests suppress the activity mark
|
|
19
|
+
(`withConsole(..., { mark: false })`), so the panel cannot chase itself.
|
|
20
|
+
* **`viewFps`** (2) and **`viewScale`** (2) — frame pace and resolution divisor, both changeable on
|
|
21
|
+
the fly inside the panel.
|
|
22
|
+
* **Host routes** `/pve-vm/console/state`, `/frame` and `/release` on the harness web server,
|
|
23
|
+
registered only when the composition has a `webServer`. They carry a loopback-only fence: Host must
|
|
24
|
+
be loopback, a present Origin must match Host, `sec-fetch-site: cross-site` is refused and POST must
|
|
25
|
+
be `application/json`. A harness bound to a LAN therefore keeps the panel dark.
|
|
26
|
+
* `RfbClient.waitForUpdate({ idleOk: true })` — silence at a message boundary means "the screen did
|
|
27
|
+
not change" instead of an error, while a timeout inside a message stays fatal.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
* **`inputChannel` and `sendkeyDelayMs` never reached the tools.** Both keys were missing from
|
|
32
|
+
`CONFIG_KEYS`, so `snapshot()` dropped them and every run silently used the built-in `auto`/80 ms
|
|
33
|
+
defaults. The form accepted the values, the code ignored them.
|
|
34
|
+
|
|
35
|
+
## [0.1.1] — 2026-10-13
|
|
36
|
+
|
|
37
|
+
Linux guest support. Everything below was found by running the plugin against a real RedOS 8
|
|
38
|
+
guest with a MATE desktop, not by reading the code.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
* **Guest OS detection rejected almost every Linux distribution.** The guest agent reports `id`
|
|
43
|
+
from `/etc/os-release`, and only IDs containing `linux` were accepted — RedOS reports `redos`,
|
|
44
|
+
Debian `debian`, Ubuntu `ubuntu`. All of them landed in `other` and every `vm_*` tool answered
|
|
45
|
+
*running a shell command is not supported for guest OS «other»*, so the whole guest-agent half
|
|
46
|
+
was dead on Linux. Windows was unaffected (`mswindows`), which is why it went unnoticed.
|
|
47
|
+
Windows is now matched first, Linux by `id`/`name`/`pretty-name`, and a non-Windows guest that
|
|
48
|
+
answered `get-osinfo` with a non-empty `kernel-release` counts as Linux.
|
|
49
|
+
* **`vm_type_text` typed nothing on a GDM desktop.** The built-in typing script used
|
|
50
|
+
`$home/.Xauthority`, which does not exist when GDM owns the session — RedOS and RHEL keep the
|
|
51
|
+
file at `/run/user/<uid>/gdm/Xauthority`. `xdotool` then talked to the X server with no
|
|
52
|
+
authorization at all, failed with *No protocol specified*, and the text never appeared. The
|
|
53
|
+
script now tries `~/.Xauthority`, then the GDM path, then any `/run/user/<uid>/*/Xauthority`.
|
|
54
|
+
* **`vm_type_text` could not submit text.** `text=$(… | base64 -d)` — command substitution strips
|
|
55
|
+
trailing newlines, so text ending in `"\n"` was typed without pressing Enter and the shell
|
|
56
|
+
prompt never came back.
|
|
57
|
+
* **Console errors hid the actual cause.** When the node's `sshd` does not accept `AcceptEnv`,
|
|
58
|
+
`LC_PVE_TICKET` never arrives and `qm vncproxy` exits with a precise
|
|
59
|
+
*LC_PVE_TICKET not set, VNC proxy without password is forbidden* — but the RFB reader saw EOF
|
|
60
|
+
before ssh had finished exiting, so only *the VNC stream was closed by the node* surfaced. The
|
|
61
|
+
ssh stderr is now reported (after a short grace period), both during the handshake and when a
|
|
62
|
+
live session dies mid-way.
|
|
63
|
+
|
|
64
|
+
### Known limitations
|
|
65
|
+
|
|
66
|
+
* Proxmox applies a **default 5-second timeout to QMP commands** (`PVE/QMPClient.pm`), and
|
|
67
|
+
`guest-exec` waits for the guest agent to acknowledge. While a previous long command is still
|
|
68
|
+
running inside the guest that acknowledgement arrives too late and the call fails with
|
|
69
|
+
*qmp command 'guest-exec' failed - got timeout*. On an idle guest 10 out of 10 calls complete
|
|
70
|
+
in about a second. `vm_exec` is currently synchronous and does not retry.
|
|
71
|
+
|
|
6
72
|
## [0.1.0] — 2026-10-13
|
|
7
73
|
|
|
8
74
|
Initial public release.
|
package/README.md
CHANGED
|
@@ -30,6 +30,9 @@ agent ──► plugin ──► ssh ──► node: qm vncproxy ──► unix
|
|
|
30
30
|
* **Clipboard** — `console_paste` writes UTF-8 text into the guest clipboard over RFB and presses
|
|
31
31
|
Ctrl+V; `console_clipboard` reads the guest clipboard back, so text can leave the VM without OCR.
|
|
32
32
|
* **A settings card** in the web UI (English and Russian labels), backed by the profile patch layer.
|
|
33
|
+
* **A live screen panel** — the “VM screen” tab in the right sidebar shows the frames the agent
|
|
34
|
+
sees, taken from the very same VNC session, while the agent works. It follows the agent's VM
|
|
35
|
+
automatically or stays on the VM you pick by hand. Watching only: the panel never clicks or types.
|
|
33
36
|
* **Zero runtime dependencies** — RFB, DES authentication, keysym tables and PNG encoding are
|
|
34
37
|
implemented in this package on top of `node:crypto` and `node:zlib`. There is nothing to install
|
|
35
38
|
on the host, and nothing to install on the node either.
|
|
@@ -95,6 +98,10 @@ layer, and the same values can be edited there by hand:
|
|
|
95
98
|
sessionIdleMs: 300000
|
|
96
99
|
guestTimeoutMs: 60000
|
|
97
100
|
guestTypeCommand: '' # script for typing non-ASCII text into a Linux guest
|
|
101
|
+
viewAutoOpen: false # open the "VM screen" tab by itself when the agent touches a console
|
|
102
|
+
viewFollowAgent: true # the panel follows the VM the agent works with
|
|
103
|
+
viewFps: 2 # frame pace in the panel, 1–4
|
|
104
|
+
viewScale: 2 # frame resolution divisor: 1 native, 2 half, 4 quarter
|
|
98
105
|
```
|
|
99
106
|
|
|
100
107
|
**First run checklist**
|
|
@@ -137,6 +144,33 @@ Every action tool accepts a common tail: `observe` (return a frame after the act
|
|
|
137
144
|
| `vm_type_text` | `vmid`, `text`, `settleMs?`, `observe?` | Type text through the best available channel: ASCII → console, non-ASCII → the user session on Windows / `xdotool`–`wtype` on Linux. |
|
|
138
145
|
| `vm_status` | `vmid?` | Is the VM allowed, does the agent answer, which OS, are there open console sessions. |
|
|
139
146
|
|
|
147
|
+
## Watch the VM screen live
|
|
148
|
+
|
|
149
|
+
The **VM screen** tab in the right sidebar shows what the agent sees while it works. Add it from the
|
|
150
|
+
sidebar guide, or let `viewAutoOpen` reveal it the moment the agent touches a console.
|
|
151
|
+
|
|
152
|
+
* The frames are taken from the agent's own RFB session — **no second VNC session appears** and the
|
|
153
|
+
`qm vncproxy` password is never reset under the agent's feet. Captures and the agent's tools share
|
|
154
|
+
one session queue, so they never tear the stream for each other.
|
|
155
|
+
* `viewFollowAgent` keeps the panel on the VM the agent is working with; clicking a VM chip pins the
|
|
156
|
+
panel to that VM instead. `viewFps` (1–4) and `viewScale` (1 / 2 / 4) control the pace and the
|
|
157
|
+
resolution, and both can be changed on the fly inside the panel.
|
|
158
|
+
* The panel is **watch-only**: no clicks, no typing, nothing is injected into the guest. A blank
|
|
159
|
+
frame is called out explicitly — the guest blanked its display or is locked.
|
|
160
|
+
* Frames are served by the plugin's own routes (`/pve-vm/console/frame`, `/state`, `/release`) on the
|
|
161
|
+
harness web server, behind a loopback-only fence: a request is answered only when the `Host` is
|
|
162
|
+
loopback (`localhost`, `127.0.0.0/8`, `[::1]`), a present `Origin` matches `Host`, and
|
|
163
|
+
`sec-fetch-site: cross-site` is refused. If you bind the harness to your LAN, the panel stays dark
|
|
164
|
+
by design — the same fence the harness applies to `/api`.
|
|
165
|
+
* **The fence is loopback, not the harness token.** These routes live outside `/api`, so the
|
|
166
|
+
harness URL token does not cover them (the browser-skill overview works the same way). Any
|
|
167
|
+
process on the same machine can therefore pull frames or call `/release`; that is the accepted
|
|
168
|
+
price of loading frames without a token on a single-user box. Serve VMs you would not mind a
|
|
169
|
+
local user seeing, and harden with a harness-issued token if that is not acceptable.
|
|
170
|
+
* The console session stays open while the panel streams (the idle reaper does not take it); the
|
|
171
|
+
panel's “disconnect console” button closes it immediately. Streaming pauses by itself when the tab
|
|
172
|
+
is hidden.
|
|
173
|
+
|
|
140
174
|
## How it works
|
|
141
175
|
|
|
142
176
|
* **Transport.** A VM has no TCP VNC port: QEMU listens on the unix socket
|