openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
123 lines (122 loc) • 5.63 kB
JavaScript
import { c as normalizeOptionalLowercaseString } from "./string-coerce-CIXf7egm.js";
import { t as loadActivatedBundledPluginPublicSurfaceModule } from "./facade-runtime-BjmVS_9G.js";
import { A as createDockerSandboxBackend, M as dockerSandboxBackendManager, N as podmanSandboxBackendManager, i as sshSandboxBackendManager, j as createPodmanSandboxBackend, n as createSshSandboxBackend, r as resolveSshRuntimePaths } from "./ssh-backend-Bi2dY2r6.js";
//#region src/agents/sandbox/backend.ts
/**
* Sandbox backend registry.
*
* Stores process-wide backend factories so core and plugins can register local container, SSH, or custom sandbox providers.
*/
const SANDBOX_BACKEND_FACTORIES_STATE_KEY = Symbol.for("openclaw.sandboxBackendFactories");
function getSandboxBackendFactories() {
const globalStore = globalThis;
globalStore[SANDBOX_BACKEND_FACTORIES_STATE_KEY] ??= /* @__PURE__ */ new Map();
return globalStore[SANDBOX_BACKEND_FACTORIES_STATE_KEY];
}
function normalizeSandboxBackendId(id) {
const normalized = normalizeOptionalLowercaseString(id);
if (!normalized) throw new Error("Sandbox backend id must not be empty.");
return normalized;
}
/** Register or replace a sandbox backend and return a restore callback. */
function registerSandboxBackend(id, registration) {
const normalizedId = normalizeSandboxBackendId(id);
const resolved = typeof registration === "function" ? { factory: registration } : registration;
const factories = getSandboxBackendFactories();
const generation = {
registration: resolved,
previous: factories.get(normalizedId),
retired: false
};
factories.set(normalizedId, generation);
return () => {
if (generation.retired) return;
generation.retired = true;
if (factories.get(normalizedId) !== generation) return;
let previous = generation.previous;
while (previous?.retired) previous = previous.previous;
if (previous) {
factories.set(normalizedId, previous);
return;
}
factories.delete(normalizedId);
};
}
/** Look up a sandbox backend factory by normalized backend id. */
function getSandboxBackendFactory(id) {
return resolveSandboxBackendRegistration(id)?.factory ?? null;
}
/** Look up optional lifecycle management hooks for a registered backend. */
function getSandboxBackendManager(id) {
return resolveSandboxBackendRegistration(id)?.manager ?? null;
}
/** Look up optional backend workdir resolution that does not start the runtime. */
function getSandboxBackendWorkdirResolver(id) {
return resolveSandboxBackendRegistration(id)?.resolveWorkdir ?? null;
}
/** Resolve a backend factory or throw the user-facing configuration error. */
function requireSandboxBackendFactory(id) {
const factory = getSandboxBackendFactory(id);
if (factory) return factory;
throw new Error([`Sandbox backend "${id}" is not registered.`, "Load the plugin that provides it, or set agents.defaults.sandbox.backend=docker."].join("\n"));
}
const builtinSandboxBackends = /* @__PURE__ */ new Map();
builtinSandboxBackends.set("docker", {
factory: createDockerSandboxBackend,
manager: dockerSandboxBackendManager,
resolveWorkdir: ({ cfg }) => cfg.docker.workdir
});
builtinSandboxBackends.set("podman", {
factory: createPodmanSandboxBackend,
manager: podmanSandboxBackendManager,
resolveWorkdir: ({ cfg }) => cfg.docker.workdir
});
builtinSandboxBackends.set("ssh", {
factory: createSshSandboxBackend,
manager: sshSandboxBackendManager,
resolveWorkdir: ({ cfg, scopeKey }) => resolveSshRuntimePaths(cfg.ssh.workspaceRoot, scopeKey).remoteWorkspaceDir
});
function resolveSandboxBackendRegistration(id) {
const normalizedId = normalizeSandboxBackendId(id);
return getSandboxBackendFactories().get(normalizedId)?.registration ?? builtinSandboxBackends.get(normalizedId);
}
//#endregion
//#region src/plugin-sdk/browser-bridge.ts
function loadFacadeModule() {
return loadActivatedBundledPluginPublicSurfaceModule({
dirName: "browser",
artifactBasename: "bridge-api.js"
});
}
/** Starts the browser bridge runtime from the activated browser plugin facade. */
async function startBrowserBridgeServer(params) {
return await (await loadFacadeModule()).startBrowserBridgeServer(params);
}
/** Stops a browser bridge server previously returned by startBrowserBridgeServer. */
async function stopBrowserBridgeServer(server) {
await (await loadFacadeModule()).stopBrowserBridgeServer(server);
}
//#endregion
//#region src/agents/sandbox/browser-bridges.ts
/**
* In-process browser bridge registry keyed by sandbox session.
*
* The prune path uses this table to stop bridge servers when backing containers expire.
*/
const BROWSER_BRIDGES = /* @__PURE__ */ new Map();
/** Stop and remove only the cached bridge instance the caller inspected. */
async function stopCachedBrowserBridge(sessionKey, expected) {
if (BROWSER_BRIDGES.get(sessionKey) !== expected) return;
await stopBrowserBridgeServer(expected.bridge.server);
if (BROWSER_BRIDGES.get(sessionKey) === expected) BROWSER_BRIDGES.delete(sessionKey);
}
/** Drain every cached bridge that still owns one sandbox container. */
async function stopCachedBrowserBridgesForContainer(containerName) {
for (;;) {
const match = [...BROWSER_BRIDGES].find(([, cached]) => cached.containerName === containerName);
if (!match) return;
await stopCachedBrowserBridge(match[0], match[1]);
}
}
//#endregion
export { getSandboxBackendFactory as a, registerSandboxBackend as c, startBrowserBridgeServer as i, requireSandboxBackendFactory as l, stopCachedBrowserBridge as n, getSandboxBackendManager as o, stopCachedBrowserBridgesForContainer as r, getSandboxBackendWorkdirResolver as s, BROWSER_BRIDGES as t };