feat(agent): ship a Node 12 executable for Windows Server 2008 R2
Build and Deploy Remote Control Support / Test (push) Successful in 10s
Build and Deploy Remote Control Support / Build Image (push) Successful in 37s
Build and Deploy Remote Control Support / Deploy to Portainer (push) Successful in 6s

Machines that cannot install Node 22 had no way to run the agent at all, which
left them stuck on direct mode — and direct mode only works when the hub can
route to the VNC port, which it often cannot.

agent.js now resolves the two Node 22 globals it uses through fallbacks: `ws`
for the control and tunnel sockets, and http/https for the single enrolment
POST. Node 22 loads neither, since `globalThis.WebSocket || require('ws')`
short-circuits. The require and the http/https references are static so the
bundler can follow them.

A new Docker stage bundles that file with a Node 12 runtime — the last line
supporting Windows 7 and Server 2008 R2 — into one self-contained .exe, served
from /download/agent.exe and linked from the enrolment page. The route answers
503 rather than 404 in a dev checkout, where the build has not run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 00:55:57 -07:00
co-authored by Claude Opus 5
parent 88be2bf867
commit cecaf74a0a
8 changed files with 141 additions and 12 deletions
+19
View File
@@ -59,6 +59,22 @@
</li>
</ol>
<div class="notice" style="margin-top:14px">
<strong>On Windows 7 or Server 2008 R2?</strong>
<div class="faint" style="margin-top:6px">
Node.js will not install on those — the last version that supported them is long
out of date. Use the standalone build instead: one file, nothing to install.
</div>
<div class="row wrap" style="margin-top:10px">
<a class="small" href="/download/agent.exe" download="rcs-agent.exe">Download rcs-agent.exe</a>
</div>
<div class="faint" style="margin-top:10px">Then in a Command Prompt, in the folder you saved it to:</div>
<pre class="code" id="exe-oneliner"></pre>
<div class="row wrap" style="margin-top:10px">
<button class="small" id="copy-exe">Copy</button>
</div>
</div>
<p class="login-foot">
Link expires <span id="expiry"></span> · once enrolled, this machine appears in the operator console
</p>
@@ -75,6 +91,7 @@
const unix = `curl -fsSL ${origin}/download/agent.js -o rcs-agent.js \\\n && node rcs-agent.js enroll ${link} \\\n && node rcs-agent.js run`;
const win = `iwr ${origin}/download/agent.js -OutFile rcs-agent.js; `
+ `node rcs-agent.js enroll ${link}; node rcs-agent.js run`;
const exe = `rcs-agent.exe enroll ${link}\r\nrcs-agent.exe run`;
function copy(text, button) {
navigator.clipboard.writeText(text).then(() => {
@@ -87,6 +104,8 @@
document.getElementById('oneliner').textContent = unix;
document.getElementById('copy-unix').onclick = (e) => copy(unix, e.currentTarget);
document.getElementById('copy-win').onclick = (e) => copy(win, e.currentTarget);
document.getElementById('exe-oneliner').textContent = exe;
document.getElementById('copy-exe').onclick = (e) => copy(exe, e.currentTarget);
fetch(`/api/public/invite/${encodeURIComponent(token)}`)
.then((r) => r.json().then((body) => ({ ok: r.ok, body })))