import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { resolve } from 'node:path';
import { BaseExecutionContext } from './base.js';
export class LocalExecutionContext extends BaseExecutionContext {
    id;
    environment = 'local';
    cwd;
    fsAccess;
    envVars;
    capabilities;
    shell;
    constructor(options) {
        super();
        this.id = options.id;
        this.cwd = resolve(options.cwd);
        this.fsAccess = options.fsAccess ?? true;
        this.envVars = options.envVars ?? {};
        this.capabilities = options.capabilities ?? ['filesystem', 'process', 'shell'];
        this.shell = options.shell;
    }
    async doInitialize() {
        if (!existsSync(this.cwd)) {
            throw new Error(`Working directory does not exist: ${this.cwd}`);
        }
        this.log.info(`Local context initialized at ${this.cwd}`);
    }
    async doTeardown() { }
    getCwd() {
        return this.cwd;
    }
    setCwd(newCwd) {
        const resolved = resolve(newCwd);
        if (!existsSync(resolved)) {
            throw new Error(`Working directory does not exist: ${resolved}`);
        }
        this.cwd = resolved;
    }
    hasFsAccess() {
        return this.fsAccess;
    }
    resolvePath(relativePath) {
        return resolve(this.cwd, relativePath);
    }
    getEnvVar(key) {
        return this.envVars[key] ?? process.env[key];
    }
    getEnvVars() {
        return { ...this.envVars };
    }
    getCapabilities() {
        return [...this.capabilities];
    }
    hasCapability(cap) {
        return this.capabilities.includes(cap);
    }
    async executeCommand(command, args = [], options) {
        if (!this.hasCapability('process') && !this.hasCapability('shell')) {
            return {
                exitCode: 1,
                stdout: '',
                stderr: 'Command execution not available: context lacks process/shell capability',
                durationMs: 0,
            };
        }
        const cwd = options?.cwd ? resolve(this.cwd, options.cwd) : this.cwd;
        const env = { ...process.env, ...this.envVars, ...options?.env };
        const timeoutMs = options?.timeoutMs ?? 30_000;
        const shell = options?.shell ?? this.shell ?? true;
        return new Promise((resolvePromise) => {
            const start = performance.now();
            const proc = spawn(command, args, {
                cwd,
                env,
                shell,
                timeout: timeoutMs,
            });
            let stdout = '';
            let stderr = '';
            proc.stdout?.on('data', (data) => {
                stdout += data.toString();
            });
            proc.stderr?.on('data', (data) => {
                stderr += data.toString();
            });
            proc.on('close', (code) => {
                resolvePromise({
                    exitCode: code ?? 1,
                    stdout,
                    stderr,
                    durationMs: Math.round(performance.now() - start),
                });
            });
            proc.on('error', (err) => {
                resolvePromise({
                    exitCode: 1,
                    stdout,
                    stderr: err.message,
                    durationMs: Math.round(performance.now() - start),
                });
            });
        });
    }
    toConfig() {
        return {
            id: this.id,
            environment: 'local',
            cwd: this.cwd,
            fsAccess: this.fsAccess,
            envVars: this.envVars,
            capabilities: this.capabilities,
            shell: this.shell,
        };
    }
}
//# sourceMappingURL=local.js.map