feat: wire remote-desktop plugin into core and rename i18n keys

Repoints core consumers (dispatcher, collab, session-sharing, tab
utils) at the plugin, adds isTabTypeAvailable gating for rdp/vnc/
telnet, widens hostCapability to accept an array, and renames the
guacamole i18n namespace to remoteDesktop.
This commit is contained in:
LukeGus committed 2026-09-21 20:26:09 -05:00
1 parent c6bcfdb80d
commit 76b2e5739a
41 files changed
+361 -686

No files matched your search

+7
View File
@@ -62,6 +62,12 @@
* do, verifies host keys via SSHHostKeyVerifier, and streams its discovery
* progress as server-sent events. Neither the worker's 13-field read-only
* ctx.hosts nor its single-postMessage-reply ctx.http.route can support that.
*
* remote-desktop is here for the same reason ssh-terminal is: it owns a
* WebSocket server (guacamole-lite, port 30008) and its
* /connect-host/:hostId route does multi-step credential/tunnel resolution
* (SSH jump-host tunnels, a macOS VNC compatibility proxy) using raw
* net.Socket plumbing that cannot cross a structured-clone boundary.
*/
export const FIRST_PARTY_PLUGIN_IDS: ReadonlySet<string> = new Set([
"ssh-terminal",
@@ -69,6 +75,7 @@ export const FIRST_PARTY_PLUGIN_IDS: ReadonlySet<string> = new Set([
"host-metrics",
"ai",
"proxmox",
"remote-desktop",
]);
export const TRANSPORT_OWNER_CAPABILITY = "process:transport-owner";
+33 -9
View File
@@ -128,7 +128,7 @@ export interface PluginManifest {
icon: string;
openFrom: string[];
}>;
hostCapability?: { key: string; labelKey: string; editorTab: string };
hostCapability?: HostCapabilityContribution | HostCapabilityContribution[];
permissionGroup?: {
group: string;
permissions: string[];
@@ -161,6 +161,19 @@ export interface PluginManifest {
sidecars: Array<{ id: string; binary: string }>;
}
/**
* A host-level checkbox this plugin contributes to the host editor (e.g.
* "Enable RDP"), backed by an existing boolean column on the host record.
* Most plugins declare one; a plugin covering several independent protocols
* on the same host (rdp/vnc/telnet) declares several -- see
* contributes.hostCapability, which accepts either shape.
*/
export interface HostCapabilityContribution {
key: string;
labelKey: string;
editorTab: string;
}
export interface PluginServiceProvide {
service: string;
version: string;
@@ -540,15 +553,26 @@ function validateContributes(contributes: Record<string, unknown>): string[] {
}
if ("hostCapability" in contributes) {
const hostCapability = (contributes.hostCapability ?? {}) as Record<
string,
unknown
>;
for (const field of ["key", "labelKey", "editorTab"]) {
if (!(field in hostCapability)) {
errors.push(`contributes.hostCapability.${field} is required`);
const raw = contributes.hostCapability;
const entries = Array.isArray(raw) ? raw : [raw];
const seenKeys = new Set<string>();
entries.forEach((entry, index) => {
const hc = (entry ?? {}) as Record<string, unknown>;
const prefix = Array.isArray(raw)
? `contributes.hostCapability[${index}]`
: "contributes.hostCapability";
for (const field of ["key", "labelKey", "editorTab"]) {
if (!(field in hc)) {
errors.push(`${prefix}.${field} is required`);
}
}
}
if (typeof hc.key === "string") {
if (seenKeys.has(hc.key)) {
errors.push(`${prefix}.key is a duplicate: "${hc.key}"`);
}
seenKeys.add(hc.key);
}
});
}
if ("permissionGroup" in contributes) {