120 lines
3.5 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|