import { spawnSync } from "child_process"; import path from "path"; const CONTAINER_PATH = "/workspace"; // Maps container path prefixes to host paths. // Derived from docker-compose.yml volumes: // ./workspace -> /workspace // ./claude-home -> /home/claude // Override host paths via env vars when running outside the default layout. const VOLUME_MAP = { "/workspace": process.env.CONDUIT_HOST_WORKSPACE || CONTAINER_PATH, "/home/claude": process.env.CONDUIT_HOST_HOME || "/home/claude", }; // Translate a container-side path to its host-side equivalent using VOLUME_MAP. // Relative paths are resolved against CONTAINER_PATH first. // Throws if the path escapes all known volumes. export function resolve_path(user_path) { const abs = path.isAbsolute(user_path) ? user_path : path.join(CONTAINER_PATH, user_path); for (const [container_prefix, host_prefix] of Object.entries(VOLUME_MAP)) { if (abs === container_prefix || abs.startsWith(container_prefix + "/")) { const relative = abs.slice(container_prefix.length); return host_prefix + relative; } } throw new Error(`Path is outside all known volumes: ${user_path}`); } // Execute a binary with an argument list — no shell interpolation. export function exec(bin, args = []) { return new Promise((resolve, reject) => { const result = spawnSync(bin, args, { stdio: "inherit" }); if (result.error) { reject(result.error); } else { resolve(result.status); } }); }