Peter Steinberger c379191f80 chore: migrate to oxlint and oxfmt
Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
2026-01-14 15:02:19 +00:00

120 lines
3.5 KiB
TypeScript

import { stopBrowserBridgeServer } from "../../browser/bridge-server.js";
import { loadConfig } from "../../config/config.js";
import { BROWSER_BRIDGES } from "./browser-bridges.js";
import { resolveSandboxConfigForAgent } from "./config.js";
import { dockerContainerState, execDocker } from "./docker.js";
import {
readBrowserRegistry,
readRegistry,
removeBrowserRegistryEntry,
removeRegistryEntry,
type SandboxBrowserRegistryEntry,
type SandboxRegistryEntry,
} from "./registry.js";
import { resolveSandboxAgentId } from "./shared.js";
export type SandboxContainerInfo = SandboxRegistryEntry & {
running: boolean;
imageMatch: boolean;
};
export type SandboxBrowserInfo = SandboxBrowserRegistryEntry & {
running: boolean;
imageMatch: boolean;
};
export async function listSandboxContainers(): Promise<SandboxContainerInfo[]> {
const config = loadConfig();
const registry = await readRegistry();
const results: SandboxContainerInfo[] = [];
for (const entry of registry.entries) {
const state = await dockerContainerState(entry.containerName);
// Get actual image from container
let actualImage = entry.image;
if (state.exists) {
try {
const result = await execDocker(
["inspect", "-f", "{{.Config.Image}}", entry.containerName],
{ allowFailure: true },
);
if (result.code === 0) {
actualImage = result.stdout.trim();
}
} catch {
// ignore
}
}
const agentId = resolveSandboxAgentId(entry.sessionKey);
const configuredImage = resolveSandboxConfigForAgent(config, agentId).docker.image;
results.push({
...entry,
image: actualImage,
running: state.running,
imageMatch: actualImage === configuredImage,
});
}
return results;
}
export async function listSandboxBrowsers(): Promise<SandboxBrowserInfo[]> {
const config = loadConfig();
const registry = await readBrowserRegistry();
const results: SandboxBrowserInfo[] = [];
for (const entry of registry.entries) {
const state = await dockerContainerState(entry.containerName);
let actualImage = entry.image;
if (state.exists) {
try {
const result = await execDocker(
["inspect", "-f", "{{.Config.Image}}", entry.containerName],
{ allowFailure: true },
);
if (result.code === 0) {
actualImage = result.stdout.trim();
}
} catch {
// ignore
}
}
const agentId = resolveSandboxAgentId(entry.sessionKey);
const configuredImage = resolveSandboxConfigForAgent(config, agentId).browser.image;
results.push({
...entry,
image: actualImage,
running: state.running,
imageMatch: actualImage === configuredImage,
});
}
return results;
}
export async function removeSandboxContainer(containerName: string): Promise<void> {
try {
await execDocker(["rm", "-f", containerName], { allowFailure: true });
} catch {
// ignore removal failures
}
await removeRegistryEntry(containerName);
}
export async function removeSandboxBrowserContainer(containerName: string): Promise<void> {
try {
await execDocker(["rm", "-f", containerName], { allowFailure: true });
} catch {
// ignore removal failures
}
await removeBrowserRegistryEntry(containerName);
// Stop browser bridge if active
for (const [sessionKey, bridge] of BROWSER_BRIDGES.entries()) {
if (bridge.containerName === containerName) {
await stopBrowserBridgeServer(bridge.bridge.server).catch(() => undefined);
BROWSER_BRIDGES.delete(sessionKey);
}
}
}