/**
 * Shared foundation for feature-agent graph nodes.
 *
 * Provides consistent logging, spec file reading, executor invocation,
 * and error handling so every node follows the same patterns.
 */
import type { IAgentExecutor, AgentExecutionOptions, AgentExecutionResult } from '../../../../../application/ports/output/agents/agent-executor.interface.js';
import type { ApprovalGates, Evidence } from '../../../../../domain/generated/output.js';
import type { FeatureAgentState } from '../state.js';
/**
 * Create a scoped logger that prefixes messages with the node name.
 * Output goes to stdout which the worker redirects to the log file.
 * Also sets the current phase so executor logs inherit the node context.
 */
export declare function createNodeLogger(nodeName: string): {
    /** Activate this node's phase in the global log context. */
    activate(): void;
    info(message: string): void;
    error(message: string): void;
};
export type NodeLogger = ReturnType<typeof createNodeLogger>;
/**
 * Safely read a file from the spec directory. Returns empty string if file doesn't exist.
 */
export declare function readSpecFile(specDir: string, filename: string): string;
/**
 * Resolve the timeout for a specific stage.
 * Reads per-stage timeout from settings (workflow.stageTimeouts.<stage>Ms),
 * falling back to DEFAULT_STAGE_TIMEOUT_MS when not configured.
 */
export declare function getStageTimeoutMs(nodeName: string): number;
/**
 * Build executor options with cwd. Each node gets a clean agent context.
 * The timeout is resolved per-stage from settings (workflow.stageTimeouts)
 * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min).
 *
 * When no `nodeName` is provided, the current node from state is used.
 */
export declare function buildExecutorOptions(state: FeatureAgentState, overrides?: Partial<Pick<AgentExecutionOptions, 'timeout'>>, nodeName?: string): AgentExecutionOptions;
/**
 * Parse YAML with automatic sanitization of common AI-generated issues.
 * First attempts normal parsing; on failure, sanitizes unquoted braces
 * in list items and retries.
 */
export declare function safeYamlLoad(content: string): unknown;
/**
 * Serialize data to YAML with forced double-quoting for all string values.
 *
 * This helper ensures all YAML output uses consistent quoting to prevent
 * parse failures from unescaped quotes, colons, hashes, and other special
 * characters in AI-generated content.
 *
 * **When to use:**
 * - Use `safeYamlDump` for all YAML serialization in feature-agent nodes,
 *   use cases, and CLI output to ensure consistency and reliability.
 * - Do NOT use `yaml.dump` directly unless you have a specific need for
 *   unquoted strings (e.g., human-edited configuration files).
 *
 * **Options applied:**
 * - `indent: 2` — 2-space indentation (codebase standard)
 * - `lineWidth: -1` — Disable line wrapping to preserve formatting and reduce diff noise
 * - `quotingType: '"'` — Use double quotes for all quoted strings
 * - `forceQuotes: true` — Quote all string values, even those without special characters
 *
 * @param data - The data to serialize (objects, arrays, primitives)
 * @returns YAML string with all strings double-quoted
 *
 * @example
 * ```typescript
 * const yaml = safeYamlDump({ title: "it's working", description: "say \"hello\"" });
 * // Output:
 * // title: "it's working"
 * // description: "say \"hello\""
 * ```
 */
export declare function safeYamlDump(data: unknown): string;
/**
 * Determine whether the current node should trigger an interrupt
 * for human approval given the configured approval gates.
 *
 * Gates control which phases auto-approve:
 * - allowPrd: when true, skip interrupt after requirements phase
 * - allowPlan: when true, skip interrupt after plan phase
 * - allowMerge: when true, skip interrupt after merge phase
 *
 * Nodes not covered by a gate (analyze, research, implement) never interrupt.
 * Implementation always proceeds to merge; the merge node handles its own gate.
 *
 */
export declare function shouldInterrupt(nodeName: string, gates: ApprovalGates | undefined): boolean;
export type ErrorCategory = 'retryable-api' | 'retryable-network' | 'non-retryable' | 'unknown';
/**
 * Classify an error message into a retry category.
 *
 * - **retryable-api**: Transient API errors (rate-limit, overload, bad request)
 * - **retryable-network**: Network-level failures (DNS, timeouts, connection refused)
 * - **non-retryable**: Logic / filesystem / syntax errors that won't resolve on retry
 * - **unknown**: Anything unrecognised (callers may choose to retry cautiously)
 */
export declare function classifyError(errorMessage: string): ErrorCategory;
export interface RetryOptions {
    /** Maximum number of execution attempts (default 3). */
    maxAttempts?: number;
    /** Base delay in ms before the first retry (default 2000). Doubles each retry. */
    baseDelayMs?: number;
    /** Optional logger for retry messages. */
    logger?: NodeLogger;
}
/**
 * Execute a prompt via the given executor with automatic retry and
 * exponential back-off for transient errors.
 *
 * Non-retryable errors are thrown immediately. Unknown errors are
 * retried (conservative stance: could be transient).
 */
export declare function retryExecute(executor: IAgentExecutor, prompt: string, options: AgentExecutionOptions, retryOpts?: RetryOptions): Promise<AgentExecutionResult>;
/**
 * Read completed phases from feature.yaml.
 */
export declare function getCompletedPhases(specDir: string): string[];
/**
 * Remove a phase from completedPhases in feature.yaml.
 * Used when a phase is rejected and needs to re-execute.
 */
export declare function clearCompletedPhase(specDir: string, phaseId: string, log?: NodeLogger): void;
/**
 * Type guard to detect rejection payloads from interrupt() return value.
 */
export declare function isRejectionPayload(value: unknown): value is {
    rejected: true;
    feedback: string;
};
/**
 * Mark a phase as complete in feature.yaml by adding its ID to completedPhases.
 */
export declare function markPhaseComplete(specDir: string, phaseId: string, log?: NodeLogger): void;
/**
 * Write a spec file atomically using temp-file-then-rename pattern.
 * Prevents corruption on crash mid-write.
 */
export declare function writeSpecFileAtomic(specDir: string, filename: string, content: string): void;
/**
 * Build a commit + optional push instruction block for prompt suffixes.
 *
 * Used by phase prompts to instruct the agent to commit spec/code changes
 * at the end of each step, and optionally push when the --push flag is set.
 */
export declare function buildCommitPushBlock(opts: {
    push: boolean;
    files: string[];
    commitHint: string;
    /** Skip build/test/lint verification (for spec-only phases that don't modify source code) */
    skipVerification?: boolean;
}): string;
/**
 * Build a resume context prefix for the agent prompt.
 *
 * When a run is resumed after being stopped/failed/crashed, this provides
 * context so the agent knows to check existing work before proceeding.
 */
export declare function buildResumeContext(resumeReason: string | undefined): string;
/**
 * Safety net: remove spec-file commits the agent made despite being told not to.
 *
 * When commitSpecs=false and the agent ignored the "do NOT commit" instruction,
 * this function finds the most recent commit that touches the spec directory and
 * soft-resets it so the files remain on disk (for local use) but are not committed.
 */
export declare function removeSpecCommitsIfNeeded(state: FeatureAgentState, nodeName: string, log: NodeLogger): void;
/**
 * Execute a node with consistent logging and error handling.
 *
 * Wraps the node's core logic with:
 * - Entry/exit logging with timing
 * - Error catching that returns error state instead of throwing
 * - Consistent state shape for success and failure
 */
export declare function executeNode(nodeName: string, executor: IAgentExecutor, buildPrompt: (state: FeatureAgentState, log: NodeLogger) => string): (state: FeatureAgentState) => Promise<Partial<FeatureAgentState>>;
/**
 * Save evidence manifest to the shep home evidence folder so the
 * merge review UI can read it without accessing graph state.
 */
export declare function saveEvidenceManifest(state: FeatureAgentState, evidence: Evidence[], log: ReturnType<typeof createNodeLogger>): void;
//# sourceMappingURL=node-helpers.d.ts.map