/**
 * Forcefully terminate a process AND its descendant tree.
 *
 * Windows: `taskkill /F /T /PID` — the only reliable way to take down the whole
 * tree (a bare TerminateProcess leaves children orphaned, which is exactly the
 * "stop reported success but the tree is still alive" bug). POSIX: SIGKILL to the
 * pid (matching the existing hard-kill behavior; callers that own a process group
 * can pass the negative pid). Best-effort — never throws; an already-exited
 * process counts as success.
 */
export declare function killTree(pid: number): void;
/**
 * Spawn options for a long-lived background child (daemon, detached worker,
 * sidecar server, fire-and-forget job).
 *
 * POSIX: `detached: true` — the child leads its own process group, so it
 * survives the parent and group kills (`kill(-pid)`) still reach it.
 *
 * Windows: the child must not share the launcher's console (a console-close
 * event when the launcher exits would tear it down, #556) and must not flash
 * a window. How to get there depends on the child's stdio:
 *
 * - All stdio non-inherited ('ignore'/'pipe'): `windowsHide: true`, NOT
 *   detached. CREATE_NO_WINDOW gives the child its own hidden console that
 *   every console-subsystem descendant (powershell, git, a .cmd shim's cmd.exe
 *   wrapper) inherits — no window anywhere down the tree. `detached` would
 *   defeat it: DETACHED_PROCESS makes CreateProcess ignore CREATE_NO_WINDOW.
 *
 * - Any stdio slot redirected to an fd (log files — `fdStdio: true`): libuv
 *   skips CREATE_NO_WINDOW whenever a stdio fd is inherited, so windowsHide
 *   cannot engage and a non-detached child would share the launcher's console
 *   and die with it. Keep DETACHED_PROCESS: the child runs console-less and
 *   windowless; its console-tool spawns stay invisible because the leaf call
 *   sites pass their own `windowsHide` with piped stdio.
 */
export declare function backgroundSpawnOptions(opts?: {
    cwd?: string;
    fdStdio?: boolean;
    platform?: NodeJS.Platform;
}): {
    cwd: string;
    detached: boolean;
    windowsHide: boolean;
};
/**
 * Whether `pid` has stopped serving — dead, or a ZOMBIE awaiting reap.
 *
 * `isAlive` is a bare `kill(pid, 0)`, which succeeds for a zombie. That matters
 * here because {@link waitForExit} blocks the event loop, so a daemon that is
 * this process's own child can never be reaped while we wait: it would read as
 * alive for the entire timeout and then be hard-killed after it had already
 * exited. A zombie holds no socket and serves no request, so for stop purposes
 * it has exited.
 */
export declare function hasExited(pid: number): boolean;
/**
 * Block until `pid` stops serving or `timeoutMs` elapses. Synchronous on purpose:
 * the callers are short-lived CLI/postinstall processes that exit before any
 * async timer would fire, which is exactly how a SIGTERMed daemon used to outlive
 * the `stopDaemon()` that was supposed to have reaped it. Returns true if it is
 * gone.
 */
export declare function waitForExit(pid: number, timeoutMs: number): boolean;
export declare function isAlive(pid: number): boolean;
/**
 * A stable identifier for the process at `pid` as of when it started, or null if
 * unknowable. Used to defeat PID reuse: acting on a pid is only safe when the
 * process still occupies the slot we observed earlier. The value is only ever
 * compared for equality against an earlier capture of the SAME pid, so the format
 * need only be stable, not parseable.
 *
 * Linux:   field 22 of /proc/<pid>/stat (starttime in clock ticks since boot).
 * macOS:   `ps -o lstart= -p <pid>`.
 * Windows: CreationDate from Win32_Process, as a culture-independent FILETIME.
 *
 * This is the single source of truth. `pty-server.ts` and `teams/agents.ts` each
 * carried their own copy; the Windows branch was missing from both, so every
 * caller there silently ran with NO pid-reuse protection — including
 * `agents teams stop`, which is how it could SIGKILL an unrelated process group.
 */
export declare function captureProcessStartTime(pid: number): string | null;
