/*
RFC-1035: thin kernel command handlers for isolation.* commands.
Each handler delegates to the IsolationManager and wraps the result
in KernelCommandResult. Records bordbuch isolation events on lifecycle transitions.
- Does not implement isolation logic — all logic lives in isolation-manager.ts.
- Does not register commands — registration lives in isolation.module.ts.
- RFC-1035: initial implementation — 6 isolation command handlers.
- RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt
*/
import type {
KernelCommandInput,
KernelCommandResult,
KernelRuntimeContext,
} from "@warpgogol/werkstatt-shared/kernel";
import type {
ComponentId,
IsolationTier,
CapabilityId,
} from "@warpgogol/werkstatt-shared/component";
import {
createIsolationManager,
type AdmittedProvider,
type SandboxLifecycleEvent,
} from "./isolation-manager.ts";
import type { IsolationManager, IsolationPolicy, SandboxHandle } from "./contracts.ts";
import { createFakeSandboxAdapter } from "./providers/fake-sandbox.ts";
import { appendBordbuchEntry } from "../bordbuch/bordbuch-io.ts";
import { failResult } from "@warpgogol/werkstatt-shared/checks/result-helpers";
let manager: IsolationManager | null = null;
function getManager(): IsolationManager {
if (!manager) {
const providers: AdmittedProvider[] = [
{ adapter: createFakeSandboxAdapter(), tier: 1 },
{ adapter: createFakeSandboxAdapter(), tier: 2 },
];
manager = createIsolationManager(providers, {
onSandboxEvent: (_event: SandboxLifecycleEvent) => {
// Bordbuch recording is handled in the command handlers where context is available
},
});
}
return manager;
}
function flagString(input: KernelCommandInput, name: string): string {
const v = input.flags[name];
return typeof v === "string" ? v : "";
}
function flagNumber(input: KernelCommandInput, name: string): number {
const v = input.flags[name];
return typeof v === "string" ? parseInt(v, 10) : 0;
}
function flagStringArray(input: KernelCommandInput, name: string): string[] {
const v = input.flags[name];
if (typeof v === "string") {
return v
.split(",")
.map((s) => s.trim())
.filter(Boolean);
}
return [];
}
function recordIsolationEvent(context: KernelRuntimeContext, event: SandboxLifecycleEvent): void {
const systemId = context.site?.name ?? "default";
appendBordbuchEntry(
context.workspaceRoot,
systemId,
"isolation",
`Sandbox ${event.sandboxId} ${event.type} for ${event.componentId}`,
"agent",
{
writerRole: "isolation",
metadata: {
sandboxId: event.sandboxId,
tier: event.tier,
componentId: event.componentId,
action: event.type,
reason: event.reason,
crashReason: event.crashReason,
},
},
)
.then(() => undefined)
.catch((err) => {
context.logger.warn(`[isolation] Bordbuch event failed: ${(err as Error).message}`);
});
}
function parsePolicy(input: KernelCommandInput): IsolationPolicy {
const tier = flagNumber(input, "tier") as IsolationTier;
return {
tier,
fsReadPaths: flagStringArray(input, "fs-read-paths"),
fsWritePaths: flagStringArray(input, "fs-write-paths"),
networkHosts: flagStringArray(input, "network-hosts"),
grantedCommands: flagStringArray(input, "granted-commands") as CapabilityId[],
timeoutMs: flagNumber(input, "timeout-ms") || 30_000,
memoryLimitBytes: flagNumber(input, "memory-limit-bytes") || 256 * 1024 * 1024,
cpuLimitPercent: flagNumber(input, "cpu-limit-percent") || 50,
};
}
export async function runTierInspect(
input: KernelCommandInput,
_context: KernelRuntimeContext,
): Promise {
const mgr = getManager();
const componentId = flagString(input, "component-id") as ComponentId;
if (componentId) {
const tier = mgr.getTier(componentId);
return {
data: { components: [{ componentId, tier }] },
exitCode: 0,
summary: `[isolation.commands] Component ${componentId} is at tier ${tier}`,
};
}
return {
data: { components: [] },
exitCode: 0,
summary: "[isolation.commands] No components registered",
};
}
export async function runTierAssign(
input: KernelCommandInput,
_context: KernelRuntimeContext,
): Promise {
const mgr = getManager();
const componentId = flagString(input, "component-id") as ComponentId;
const tier = flagNumber(input, "tier") as IsolationTier;
try {
mgr.assignTier(componentId, tier);
return {
data: { componentId, tier },
summary: `Assigned ${componentId} to tier ${tier}`,
};
} catch (err) {
return failResult("isolation.commands", [`Failed to assign tier: ${(err as Error).message}`]);
}
}
export async function runSandboxSpawn(
input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise {
const mgr = getManager();
const componentId = flagString(input, "component-id") as ComponentId;
const tier = flagNumber(input, "tier") as IsolationTier;
const policy = parsePolicy(input);
try {
const handle = await mgr.spawn(componentId, tier, policy);
recordIsolationEvent(context, {
type: "spawn",
sandboxId: handle.sandboxId,
componentId,
tier,
});
return {
data: { sandboxId: handle.sandboxId, state: "active", tier },
summary: `Spawned sandbox ${handle.sandboxId} at tier ${tier}`,
};
} catch (err) {
return failResult("isolation.commands", [`Spawn failed: ${(err as Error).message}`]);
}
}
export async function runSandboxInspect(
input: KernelCommandInput,
_context: KernelRuntimeContext,
): Promise {
const mgr = getManager();
const sandboxId = flagString(input, "sandbox-id");
const handle = mgr.inspect(sandboxId);
if (!handle) {
return failResult("isolation.commands", [`Sandbox ${sandboxId} not found`]);
}
return {
data: handle as SandboxHandle,
exitCode: 0,
summary: `[isolation.commands] Sandbox ${sandboxId}: state=${handle.state}, tier=${handle.tier}`,
};
}
export async function runSandboxTerminate(
input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise {
const mgr = getManager();
const sandboxId = flagString(input, "sandbox-id");
const reason = flagString(input, "reason") || "manual";
try {
const handle = mgr.inspect(sandboxId);
if (!handle) {
return failResult("isolation.commands", [`Sandbox ${sandboxId} not found`]);
}
await mgr.terminate(sandboxId, reason);
recordIsolationEvent(context, {
type: "terminate",
sandboxId,
componentId: handle.componentId,
tier: handle.tier,
reason,
});
return {
data: { sandboxId, state: "terminated", reason },
summary: `Terminated sandbox ${sandboxId}`,
};
} catch (err) {
return failResult("isolation.commands", [`Terminate failed: ${(err as Error).message}`]);
}
}
export async function runCapabilityBridge(
input: KernelCommandInput,
_context: KernelRuntimeContext,
): Promise {
const sandboxId = flagString(input, "sandbox-id");
const mgr = getManager();
const handle = mgr.inspect(sandboxId);
if (!handle) {
return failResult("isolation.commands", [`Sandbox ${sandboxId} not found`]);
}
return {
data: { sandboxId, bridgeId: `bridge-${sandboxId}` },
exitCode: 0,
summary: `[isolation.commands] Capability bridge created for ${sandboxId}`,
};
}