import { type ChildProcess, type SpawnOptions } from "node:child_process"; import { diffStatsFromNumstat } from "./runtime-support.js"; import type { VerifierExecutionBinding } from "../core/index.js"; export type SpawnLike = (command: string, args?: readonly string[], options?: SpawnOptions) => ChildProcess; export interface SubprocessResult { exitCode: number; stdout: string; stderr: string; timedOut: boolean; completed: boolean; crashed: boolean; /** * True when the subprocess was terminated early because its combined * stdout+stderr exceeded `maxOutputBytes` — a circuit breaker against * runaway agent sessions that would otherwise burn far more cost/tokens * than the loop budget allows before MartinLoop can observe the final * (post-hoc) usage report. See `claude-cli.ts` execute() for how this * cap is derived from the remaining loop budget. */ outputCapped: boolean; /** * Set to the inspector's reason string when an `onStdoutChunk` callback * requested early termination (e.g. a streaming usage/cost circuit breaker * that detected the agent is on track to blow through its budget). Distinct * from `outputCapped`, which fires on raw byte volume rather than parsed * semantic content. */ terminationReason?: string; launched: boolean; } export interface VerificationOutcome { passed: boolean; summary: string; steps: VerificationStepOutcome[]; warnings?: string[]; binding: VerifierExecutionBinding; } export interface VerificationStepOutcome { command: string; launched: boolean; completed: boolean; crashed: boolean; exitCode?: number; timedOut: boolean; fastFail: boolean; detail?: string; } export declare function runSubprocess(command: string, args: string[], options: { cwd: string; timeoutMs: number; spawnImpl?: SpawnLike; stdinData?: string; /** * Optional circuit breaker: terminate the subprocess once combined * stdout+stderr bytes exceed this threshold, instead of waiting for * natural completion. Used to bound runaway agent-CLI cost/token spend * that can't otherwise be observed until the process exits. */ maxOutputBytes?: number; /** * Optional semantic inspector invoked with each raw stdout chunk. Used to * parse streaming structured output (e.g. Claude's `stream-json` usage * events) and request early termination via the supplied `terminate` * callback once a semantic threshold (such as cumulative cost) is * crossed — well before the subprocess would exit naturally and report * a runaway final usage figure. */ onStdoutChunk?: (chunk: Buffer, terminate: (reason: string) => void) => void; /** Optional abort signal — kills the subprocess when aborted. */ signal?: AbortSignal; }): Promise; export declare function runVerification(commands: string[], cwd: string, timeoutMs: number, verificationStack?: Array<{ command: string; type: string; fastFail?: boolean; }>, spawnImpl?: SpawnLike, binding?: Omit): Promise; export declare function readGitExecutionArtifacts(repoRoot: string, timeoutMs: number, spawnImpl?: SpawnLike): Promise<{ changedFiles?: string[]; diffStats?: ReturnType; }>; export declare function readGitChangedFiles(repoRoot: string, timeoutMs: number, spawnImpl?: SpawnLike): Promise; /** * Detects whether a meaningful workspace delta has occurred by checking * git status for changed files that aren't MartinLoop metadata, lockfiles, * or cache artifacts. Returns the first meaningful changed file if found. */ export declare function detectFirstDelta(repoRoot: string, timeoutMs: number, spawnImpl?: SpawnLike): Promise<{ detected: boolean; filePath?: string; changeType?: "create" | "modify" | "delete"; }>; export declare function resolveGitRepositoryRoot(workingDirectory: string): string | undefined; export interface SpawnPlan { command: string; args: string[]; } export declare function createSpawnPlan(command: string, args: string[], cwd: string, preserveRawForInjectedSpawn: boolean): SpawnPlan; /** * npm generates Windows shims (.cmd/.ps1, occasionally .bat) that ultimately just exec * `node .js ` relative to the shim's own directory. Parse the shim text to * find that real script path and return it if it resolves to a file that actually exists on disk; * otherwise return undefined so callers fall back to the existing wrapper-shell behavior unchanged. */ export declare function resolveNpmShimScript(shimPath: string): string | undefined; /** * Returns true if the command string contains shell operators that cannot be * passed as literal arguments to spawn(). These must be routed through a * platform shell (cmd.exe /c or sh -c) so the operator is interpreted. */ export declare function containsShellOperator(command: string): boolean; export declare function splitCommand(command: string): string[];