package com.correx.core.tools.process

import java.io.File

/**
 * Single construction point for child processes spawned on behalf of a run — both model-authored
 * shell (ShellTool) and operator-trusted gate commands (static-analysis runner) go through here.
 *
 * Every child is configured for *unattended* execution, closing the two ways a subprocess hangs a
 * headless run:
 *  1. **stdin from /dev/null** — a tool that still prompts reads EOF and fails fast instead of
 *     blocking on a dangling pipe until the caller's timeout kills it.
 *  2. **non-interactive env overlay** — package managers / scaffolders (`npm create`, `npm init`,
 *     …) honour `CI`, `npm_config_yes`, etc. and take defaults rather than prompting at all.
 *
 * Output redirection is deliberately NOT set here: callers differ (ShellTool drains stdout/stderr
 * separately; the gate runner merges them via `redirectErrorStream`). They also keep their own
 * timeout backstop — this only builds the [ProcessBuilder].
 */
object ChildProcess {
    private val DEV_NULL = File("/dev/null")

    // Overlaid on the inherited environment. Forces the common Node toolchain into non-interactive
    // mode so `npm create`/`npm init` and friends never block on a stdin prompt.
    private val NON_INTERACTIVE_ENV = mapOf(
        "CI" to "true",
        "npm_config_yes" to "true",
        "NPM_CONFIG_YES" to "true",
        "ADBLOCK" to "1",
        "DISABLE_OPENCOLLECTIVE" to "1",
    )

    /**
     * A [ProcessBuilder] for [command] in [workingDir] (JVM cwd when null), with the non-interactive
     * env overlay and stdin redirected from /dev/null. The caller sets any output redirection and
     * owns the timeout.
     */
    fun builder(command: List<String>, workingDir: File? = null): ProcessBuilder =
        ProcessBuilder(command).apply {
            workingDir?.let { directory(it) }
            environment().putAll(NON_INTERACTIVE_ENV)
            redirectInput(ProcessBuilder.Redirect.from(DEV_NULL))
        }
}
