/** * Validation Runner - Core validation orchestration with state caching * * This module provides the core validation engine that: * 1. Executes validation steps in parallel for speed * 2. Tracks state using git tree hashes for caching * 3. Provides fail-fast execution with proper cleanup * 4. Handles signals (SIGTERM/SIGINT) gracefully * * @packageDocumentation */ import { type ChildProcess } from 'node:child_process'; import type { ValidationPhase, ValidationStep, VibeValidateConfig } from '@vibe-validate/config'; import { readParentContext } from './parent-context.js'; import type { ValidationResult, StepResult, PhaseResult } from './result-schema.js'; /** * Resolve the per-step output directory and build the spawn environment with * VV_PARENT_CONTEXT injected for nested vibe-validate invocations. * * Used by both the sequential and parallel step execution paths. Returns the * resolved `outputDir` so the caller can pass it back to the file-creation * helpers, ensuring `ParentContext.outputDir` and the actual file location * are always identical. * * @param args - Step, base env, parent context, runId, treeHash, optional phase * @returns Step env (with VV_PARENT_CONTEXT) and the resolved outputDir * * @internal */ export declare function buildStepEnv(args: { step: ValidationStep; baseEnv: Record; parent: ReturnType; runId: string; treeHash: string; phaseName?: string; verbose: boolean; }): { env: Record; outputDir: string; }; /** * Determine if a step should be skipped based on its runScope and the current environment. * * - `runScope: 'ci'` — only runs in CI, skipped locally * - `runScope: 'local'` — only runs locally, skipped in CI * - No `runScope` (undefined) — runs everywhere (backwards compatible) * * @param runScope - The step's runScope setting * @param isCI - Whether the current environment is CI * @returns true if the step should be skipped * * @public */ export declare function shouldSkipByRunScope(runScope: 'ci' | 'local' | undefined, isCI: boolean): boolean; /** * Runtime validation configuration * * This extends the file-based configuration from @vibe-validate/config * with runtime-specific options (callbacks, logging, output format). * * Note: State management (caching, forceRun) is now handled at the CLI layer * via git notes. See packages/cli/src/commands/validate.ts and @vibe-validate/history. */ export interface ValidationConfig { /** Validation phases to execute */ phases: ValidationPhase[]; /** Path to log file (default: os.tmpdir()/validation-{timestamp}.log) */ logPath?: string; /** Enable fail-fast (stop on first failure) */ enableFailFast?: boolean; /** Show verbose output (stream command stdout/stderr in real-time) */ verbose?: boolean; /** Output YAML result to stdout (redirects subprocess output to stderr when true) */ yaml?: boolean; /** Developer feedback for continuous quality improvement (default: false) */ developerFeedback?: boolean; /** Debug mode: create output files for all steps (default: false) */ debug?: boolean; /** Environment variables to pass to all child processes */ env?: Record; /** Extractor plugin configuration (for loading local/external plugins) */ extractors?: Pick['extractors']; /** * Previous validation run for retry-failed functionality * * When provided, the runner can skip steps that passed in the previous run * and only re-execute failed steps. Used by --retry-failed flag. * * @see packages/history/src/schemas.ts - ValidationRunSchema */ previousRun?: { id: string; timestamp: string; duration: number; passed: boolean; branch: string; headCommit: string; uncommittedChanges: boolean; submoduleHashes?: Record; result: ValidationResult; }; /** Callback when phase starts */ onPhaseStart?: (_phase: ValidationPhase) => void; /** Callback when phase completes */ onPhaseComplete?: (_phase: ValidationPhase, _result: PhaseResult) => void; /** Callback when step starts */ onStepStart?: (_step: ValidationStep) => void; /** Callback when step completes */ onStepComplete?: (_step: ValidationStep, _result: StepResult) => void; } /** * Options for step execution (sequential or parallel) */ interface StepExecutionOptions { /** Enable fail-fast (stop on first failure) */ enableFailFast?: boolean; /** Additional environment variables */ env?: Record; /** Show verbose output */ verbose?: boolean; /** Output YAML result to stdout */ yaml?: boolean; /** Developer feedback mode */ developerFeedback?: boolean; /** Enable debug mode (create output files for all steps) */ debug?: boolean; /** Previous validation run for retry-failed functionality */ previousRun?: ValidationConfig['previousRun']; /** Pre-computed git tree hash for the current run (reused across all steps) */ treeHash?: string; /** Pre-computed run id for the current run (reused across all steps) */ runId?: string; } /** * Find step result from previous validation run by name * * Searches across all phases in the previous validation to find a step * with the matching name. This enables step caching for --retry-failed. * * @param previousRun - Previous validation run data from history * @param stepName - Name of step to find * @returns Step result if found, null otherwise * * @example * ```typescript * const previousStep = findPreviousStepResult(previousRun, 'TypeCheck'); * if (previousStep && previousStep.exitCode === 0) { * // Use cached result * } * ``` * * @public */ export declare function findPreviousStepResult(previousRun: ValidationConfig['previousRun'], stepName: string): StepResult | null; /** * Determine if we should use cached result for this step * * Returns true only when all conditions are met: * - Retry-failed mode is enabled * - Previous step exists * - Previous step passed (exitCode === 0) * * @param previousStep - Step result from previous run (or null if not found) * @param isRetryFailed - Whether retry-failed mode is enabled * @returns True if we should use cached result, false otherwise * * @example * ```typescript * const previousStep = findPreviousStepResult(previousRun, 'Build'); * if (shouldUseCachedResult(previousStep, true)) { * return createCachedStepResult(previousStep); * } * ``` * * @public */ export declare function shouldUseCachedResult(previousStep: StepResult | null, isRetryFailed: boolean): boolean; /** * Parse test output to extract specific failures * * Extracts failure details from validation step output using pattern matching. * Supports Vitest, TypeScript, and ESLint error formats. * * Note: This is a basic implementation - the extractors package provides * more sophisticated parsing with tool-specific extractors. * * @param output - Raw stdout/stderr output from validation step * @returns Array of extracted failure messages (max 10 per failure type) * * @example * ```typescript * const output = ` * ❌ should validate user input * src/user.ts(42,10): error TS2345: Argument type mismatch * `; * * const failures = parseFailures(output); * // ['❌ should validate user input', 'src/user.ts(42,10): error TS2345: ...'] * ``` * * @public * @deprecated Use autoDetectAndExtract() from @vibe-validate/extractors instead */ export declare function parseFailures(output: string): string[]; /** * Run validation steps sequentially (one at a time) * * Executes validation steps one at a time in order, stopping on first failure. * This mode is useful for bootstrap builds or when steps have dependencies. * * @param steps - Array of validation steps to execute sequentially * @param phaseName - Human-readable phase name for logging * @param options - Execution options (enableFailFast, env, verbose, yaml, debug, etc.) * @returns Promise resolving to execution results with outputs and step results * * @example * ```typescript * const result = await runStepsSequentially( * [ * { name: 'Build', command: 'pnpm build' }, * { name: 'TypeScript', command: 'pnpm typecheck' }, * { name: 'ESLint', command: 'pnpm lint' }, * ], * 'Pre-Qualification', * { enableFailFast: true, env: { NODE_ENV: 'test' } } * ); * * if (!result.success) { * console.error(`Step ${result.failedStep?.name} failed`); * } * ``` * * @public */ export declare function runStepsSequentially(steps: ValidationStep[], phaseName: string, options?: StepExecutionOptions): Promise<{ success: boolean; failedStep?: ValidationStep; outputs: Map; stepResults: StepResult[]; }>; /** * Run validation steps in parallel with smart fail-fast * * Executes multiple validation steps concurrently, capturing output and * providing fail-fast termination if enabled. Each step runs in its own * detached process group for clean termination. * * @param steps - Array of validation steps to execute in parallel * @param phaseName - Human-readable phase name for logging * @param options - Execution options (enableFailFast, env, verbose, yaml, debug, etc.) * @returns Promise resolving to execution results with outputs and step results * * @example * ```typescript * const result = await runStepsInParallel( * [ * { name: 'TypeScript', command: 'pnpm typecheck' }, * { name: 'ESLint', command: 'pnpm lint' }, * ], * 'Pre-Qualification', * { enableFailFast: true, env: { NODE_ENV: 'test' } } * ); * * if (!result.success) { * console.error(`Step ${result.failedStep?.name} failed`); * } * ``` * * @public */ export declare function runStepsInParallel(steps: ValidationStep[], phaseName: string, options?: StepExecutionOptions): Promise<{ success: boolean; failedStep?: ValidationStep; outputs: Map; stepResults: StepResult[]; }>; /** * Validation runner with state tracking and caching * * Main entry point for running validation with git tree hash-based caching. * Executes validation phases sequentially, with parallel step execution within * each phase. Supports fail-fast termination and comprehensive state tracking. * * Features: * - Git tree hash-based caching (skip if code unchanged) * - Parallel step execution within phases * - Fail-fast mode (stop on first failure) * - Comprehensive output logging * - State file persistence for cache validation * * @param config - Validation configuration with phases, steps, and options * @returns Promise resolving to validation result with pass/fail status * * @example * ```typescript * const result = await runValidation({ * phases: [ * { * name: 'Pre-Qualification', * parallel: true, * steps: [ * { name: 'TypeScript', command: 'pnpm typecheck' }, * { name: 'ESLint', command: 'pnpm lint' }, * ], * }, * ], * enableFailFast: false, * }); * * if (result.passed) { * console.log('✅ Validation passed'); * } else { * console.error(`❌ Failed at step: ${result.failedStep}`); * } * ``` * * @public */ export declare function runValidation(config: ValidationConfig): Promise; /** * Setup signal handlers for graceful cleanup * * Registers SIGTERM and SIGINT handlers to ensure all active child processes * are properly terminated when the validation runner is interrupted. * * @param activeProcesses - Set of active child processes to track for cleanup * * @example * ```typescript * const activeProcesses = new Set(); * setupSignalHandlers(activeProcesses); * * // When spawning new processes: * const proc = spawn('npm', ['test']); * activeProcesses.add(proc); * * // Cleanup is automatic on SIGTERM/SIGINT * ``` * * @public */ export declare function setupSignalHandlers(activeProcesses: Set): void; export {}; //# sourceMappingURL=runner.d.ts.map