/**
 * AgentController-side sandbox manager.
 *
 * Composes:
 * - SettingsManager → SandboxConfig (via toPackageConfig)
 * - resolveSandboxConfig → SandboxState (pure, cached WSL probes)
 * - wrapCommand → WrappedCommand (pure)
 * - ProxyManager → proxy socket paths (long-lived, injected per command)
 *
 * Settings are re-read on every wrapCommand() call, so /sandbox menu
 * changes (paths, domains) take effect immediately — no restart needed.
 */
import { join } from 'path';
import { getAgentDir } from '../../config.js';
import { resolveSandboxConfig, toLinuxPath, wrapCommand } from './lib/index.js';
import { ProxyManager } from './lib/manager.js';
/** Map agent SandboxSettings to the package's SandboxConfig. */
function toPackageConfig(settingsManager) {
    const pipDir = toLinuxPath(join(getAgentDir(), 'pip-packages'));
    const settings = settingsManager.getSandboxSettings();
    return {
        readPaths: settings.readPaths ?? [],
        writePaths: settings.writePaths ?? [],
        networkMode: settingsManager.getSandboxNetworkMode(),
        env: {
            PYTHONUSERBASE: pipDir,
            PIP_USER: '1',
            PIP_BREAK_SYSTEM_PACKAGES: '1',
            PATH: `${pipDir}/bin:/usr/local/bin:/usr/bin:/bin`
        }
    };
}
/**
 * Orchestrates sandbox state, proxy lifecycle, and command wrapping.
 *
 * Re-reads settings on every wrapCommand() call so that /sandbox menu
 * changes take effect without restarting the session.
 */
export class SandboxManager {
    settingsManager;
    cwd;
    proxy = new ProxyManager();
    networkModeOverride = null;
    nextCommandNetworkModeOverride = null;
    domainCheckHandler = null;
    constructor(cwd, settingsManager) {
        this.cwd = cwd;
        this.settingsManager = settingsManager;
    }
    /** Read current settings → resolve into sandbox state. Fresh each call; WSL probes are cached. */
    resolve(consumeNextCommandOverride = false) {
        const config = toPackageConfig(this.settingsManager); // read live settings
        const state = resolveSandboxConfig(config, this.cwd); // Windows→Linux paths, deny mounts, WSL probes
        if (this.networkModeOverride) {
            state.networkMode = this.networkModeOverride; // preserve runtime override (e.g. proxy failure)
        }
        if (consumeNextCommandOverride && this.nextCommandNetworkModeOverride) {
            state.networkMode = this.nextCommandNetworkModeOverride;
            this.nextCommandNetworkModeOverride = null;
        }
        return state;
    }
    getState() {
        return this.resolve();
    }
    /** Override the network mode at runtime (e.g., fallback to 'none' on proxy failure). */
    setNetworkMode(mode) {
        this.networkModeOverride = mode;
    }
    /** Register the callback invoked when the proxy encounters an unknown domain. */
    setDomainCheckHandler(handler) {
        this.domainCheckHandler = handler;
    }
    /** Start/restart the proxy if in proxy mode, or stop it otherwise. Must be awaited before the first command. */
    async ensureReady() {
        const state = this.resolve();
        if (state.networkMode !== 'proxy') {
            this.proxy.stop();
            return;
        }
        try {
            const allowedDomains = this.settingsManager.getSandboxAllowedDomains();
            await this.proxy.start(state.distro, allowedDomains, {
                onDomainCheck: async (domain) => {
                    const choice = await this.domainCheckHandler?.onDomainCheck(domain);
                    if (choice === 'save') {
                        this.settingsManager.addSandboxAllowedDomain(domain);
                        return 'always';
                    }
                    if (choice === 'once')
                        return 'once';
                    return false;
                }
            });
            return this.proxy.ensureReady();
        }
        catch {
            // Degrade the failed command to no-network without leaving sticky state.
            this.nextCommandNetworkModeOverride = 'none';
            this.proxy.stop();
        }
    }
    /** Resolve current settings and wrap a shell command for sandboxed execution. */
    wrapCommand(command, cwd) {
        const state = this.resolve(true);
        return wrapCommand(command, state, {
            cwd,
            httpSocketPath: this.proxy.httpSocketPath,
            socksSocketPath: this.proxy.socksSocketPath
        });
    }
    stopProxy() {
        this.proxy.stop();
    }
}
//# sourceMappingURL=sandbox-manager.js.map