refactor: remove bridge protocol

This commit is contained in:
Peter Steinberger
2026-01-19 04:50:07 +00:00
parent b347d5d9cc
commit 2f8206862a
118 changed files with 1560 additions and 8087 deletions

View File

@@ -20,7 +20,7 @@ import { ensureClawdbotCliOnPath } from "../infra/path-env.js";
import {
primeRemoteSkillsCache,
refreshRemoteBinsForConnectedNodes,
setSkillsRemoteBridge,
setSkillsRemoteRegistry,
} from "../infra/skills-remote.js";
import { scheduleGatewayUpdateCheck } from "../infra/update-startup.js";
import { setGatewaySigusr1RestartPolicy } from "../infra/restart.js";
@@ -36,7 +36,7 @@ import {
incrementPresenceVersion,
refreshGatewayHealthSnapshot,
} from "./server/health-state.js";
import { startGatewayBridgeRuntime } from "./server-bridge-runtime.js";
import { startGatewayDiscovery } from "./server-discovery-runtime.js";
import { ExecApprovalManager } from "./exec-approval-manager.js";
import { createExecApprovalHandlers } from "./server-methods/exec-approval.js";
import type { startBrowserControlServerIfEnabled } from "./server-browser.js";
@@ -48,12 +48,15 @@ import { applyGatewayLaneConcurrency } from "./server-lanes.js";
import { startGatewayMaintenanceTimers } from "./server-maintenance.js";
import { coreGatewayHandlers } from "./server-methods.js";
import { GATEWAY_EVENTS, listGatewayMethods } from "./server-methods-list.js";
import { hasConnectedMobileNode as hasConnectedMobileNodeFromBridge } from "./server-mobile-nodes.js";
import { loadGatewayModelCatalog } from "./server-model-catalog.js";
import { NodeRegistry } from "./node-registry.js";
import { createNodeSubscriptionManager } from "./server-node-subscriptions.js";
import { safeParseJson } from "./server-methods/nodes.helpers.js";
import { loadGatewayPlugins } from "./server-plugins.js";
import { createGatewayReloadHandlers } from "./server-reload-handlers.js";
import { resolveGatewayRuntimeConfig } from "./server-runtime-config.js";
import { createGatewayRuntimeState } from "./server-runtime-state.js";
import { hasConnectedMobileNode } from "./server-mobile-nodes.js";
import { resolveSessionKeyForRun } from "./server-session-key.js";
import { startGatewaySidecars } from "./server-startup.js";
import { logGatewayStartup } from "./server-startup-log.js";
@@ -68,7 +71,6 @@ ensureClawdbotCliOnPath();
const log = createSubsystemLogger("gateway");
const logCanvas = log.child("canvas");
const logBridge = log.child("bridge");
const logDiscovery = log.child("discovery");
const logTailscale = log.child("tailscale");
const logChannels = log.child("channels");
@@ -93,7 +95,7 @@ export type GatewayServerOptions = {
* - tailnet: bind only to the Tailscale IPv4 address (100.64.0.0/10)
* - auto: prefer tailnet, else LAN
*/
bind?: import("../config/config.js").BridgeBindMode;
bind?: import("../config/config.js").GatewayBindMode;
/**
* Advanced override for the bind host, bypassing bind resolution.
* Prefer `bind` unless you really need a specific address.
@@ -135,7 +137,7 @@ export async function startGatewayServer(
port = 18789,
opts: GatewayServerOptions = {},
): Promise<GatewayServer> {
// Ensure all default port derivations (browser/bridge/canvas) see the actual runtime port.
// Ensure all default port derivations (browser/canvas) see the actual runtime port.
process.env.CLAWDBOT_GATEWAY_PORT = String(port);
let configSnapshot = await readConfigFileSnapshot();
@@ -261,9 +263,24 @@ export async function startGatewayServer(
logPlugins,
});
let bonjourStop: (() => Promise<void>) | null = null;
let bridge: import("../infra/bridge/server.js").NodeBridgeServer | null = null;
const hasConnectedMobileNode = () => hasConnectedMobileNodeFromBridge(bridge);
const nodeRegistry = new NodeRegistry();
const nodePresenceTimers = new Map<string, ReturnType<typeof setInterval>>();
const nodeSubscriptions = createNodeSubscriptionManager();
const nodeSendEvent = (opts: { nodeId: string; event: string; payloadJSON?: string | null }) => {
const payload = safeParseJson(opts.payloadJSON ?? null);
nodeRegistry.sendEvent(opts.nodeId, opts.event, payload);
};
const nodeSendToSession = (sessionKey: string, event: string, payload: unknown) =>
nodeSubscriptions.sendToSession(sessionKey, event, payload, nodeSendEvent);
const nodeSendToAllSubscribed = (event: string, payload: unknown) =>
nodeSubscriptions.sendToAllSubscribed(event, payload, nodeSendEvent);
const nodeSubscribe = nodeSubscriptions.subscribe;
const nodeUnsubscribe = nodeSubscriptions.unsubscribe;
const nodeUnsubscribeAll = nodeSubscriptions.unsubscribeAll;
const broadcastVoiceWakeChanged = (triggers: string[]) => {
broadcast("voicewake.changed", { triggers }, { dropIfSlow: true });
};
const hasMobileNodeConnected = () => hasConnectedMobileNode(nodeRegistry);
applyGatewayLaneConcurrency(cfgAtStart);
let cronState = buildGatewayCronService({
@@ -282,44 +299,18 @@ export async function startGatewayServer(
channelManager;
const machineDisplayName = await getMachineDisplayName();
const bridgeRuntime = await startGatewayBridgeRuntime({
cfg: cfgAtStart,
const discovery = await startGatewayDiscovery({
machineDisplayName,
port,
gatewayTls: gatewayTls.enabled
? { enabled: true, fingerprintSha256: gatewayTls.fingerprintSha256 }
: undefined,
canvasHostEnabled,
canvasHost,
canvasRuntime,
allowCanvasHostInTests: opts.allowCanvasHostInTests,
machineDisplayName,
deps,
broadcast,
dedupe,
agentRunSeq,
chatRunState,
chatRunBuffers,
chatDeltaSentAt,
addChatRun,
removeChatRun,
chatAbortControllers,
getHealthCache,
refreshGatewayHealthSnapshot,
loadGatewayModelCatalog,
logBridge,
logCanvas,
wideAreaDiscoveryEnabled: cfgAtStart.discovery?.wideArea?.enabled === true,
logDiscovery,
});
bridge = bridgeRuntime.bridge;
const bridgeHost = bridgeRuntime.bridgeHost;
canvasHostServer = bridgeRuntime.canvasHostServer;
const nodePresenceTimers = bridgeRuntime.nodePresenceTimers;
bonjourStop = bridgeRuntime.bonjourStop;
const bridgeSendToSession = bridgeRuntime.bridgeSendToSession;
const bridgeSendToAllSubscribed = bridgeRuntime.bridgeSendToAllSubscribed;
const broadcastVoiceWakeChanged = bridgeRuntime.broadcastVoiceWakeChanged;
bonjourStop = discovery.bonjourStop;
setSkillsRemoteBridge(bridge);
setSkillsRemoteRegistry(nodeRegistry);
void primeRemoteSkillsCache();
registerSkillsChangeListener(() => {
const latest = loadConfig();
@@ -328,7 +319,7 @@ export async function startGatewayServer(
const { tickInterval, healthInterval, dedupeCleanup } = startGatewayMaintenanceTimers({
broadcast,
bridgeSendToAllSubscribed,
nodeSendToAllSubscribed,
getPresenceVersion,
getHealthVersion,
refreshGatewayHealthSnapshot,
@@ -340,13 +331,13 @@ export async function startGatewayServer(
chatDeltaSentAt,
removeChatRun,
agentRunSeq,
bridgeSendToSession,
nodeSendToSession,
});
const agentUnsub = onAgentEvent(
createAgentEventHandler({
broadcast,
bridgeSendToSession,
nodeSendToSession,
agentRunSeq,
chatRunState,
resolveSessionKeyForRun,
@@ -369,7 +360,7 @@ export async function startGatewayServer(
wss,
clients,
port,
bridgeHost: bridgeHost ?? undefined,
gatewayHost: bindHost ?? undefined,
canvasHostEnabled: Boolean(canvasHost),
canvasHostServerPort: canvasHostServer?.port ?? undefined,
resolvedAuth,
@@ -395,9 +386,13 @@ export async function startGatewayServer(
incrementPresenceVersion,
getHealthVersion,
broadcast,
bridge,
bridgeSendToSession,
hasConnectedMobileNode,
nodeSendToSession,
nodeSendToAllSubscribed,
nodeSubscribe,
nodeUnsubscribe,
nodeUnsubscribeAll,
hasConnectedMobileNode: hasMobileNodeConnected,
nodeRegistry,
agentRunSeq,
chatAbortControllers,
chatAbortedRuns: chatRunState.abortedRuns,
@@ -491,7 +486,6 @@ export async function startGatewayServer(
tailscaleCleanup,
canvasHost,
canvasHostServer,
bridge,
stopChannel,
pluginServices,
cron,