/**
 * Command / poll source evaluator.
 *
 * Runs a shell command; its stdout is the observation. `poll` re-runs the same
 * command on an interval — the evaluation is identical, so poll.ts delegates
 * here. No agent, no sandbox: a plain `/bin/sh -c` (or `cmd /c` on Windows).
 */
import { execFile } from 'child_process';
import { classifyPollFailure } from './failure.js';
const DEFAULT_TIMEOUT_MS = 60_000;
/** Run the source command and return its combined stdout as the observation. */
export function evaluate(source) {
    const command = source.command;
    if (!command)
        return Promise.resolve(null);
    const [bin, args] = process.platform === 'win32'
        ? ['cmd', ['/c', command]]
        : ['/bin/sh', ['-c', command]];
    return new Promise((resolve) => {
        execFile(bin, args, { encoding: 'utf-8', timeout: DEFAULT_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024 }, (err, stdout, stderr) => {
            const exitCode = err && typeof err.code === 'number'
                ? err.code
                : err
                    ? 1
                    : 0;
            // Surface stderr when stdout is empty.
            const raw = (stdout && stdout.length > 0 ? stdout : stderr ?? '').replace(/\s+$/, '');
            // A poll that failed to OBSERVE — non-zero exit, or a transport/auth/
            // rate-limit error shape in its output (which a piped `gh … | jq`
            // swallows the exit code of) — is not a new value. Flag it so the engine
            // skips it instead of reading empty→error→empty as two value changes and
            // dispatching an agent on a dead premise (PHNX-3510).
            const failureReason = classifyPollFailure({ exitCode, text: raw });
            resolve({
                raw,
                meta: { exitCode },
                ...(failureReason ? { failed: true, failureReason } : {}),
            });
        });
    });
}
