import type { SpawnError } from "@uncaged/nerve-workflow-utils"; export function formatSpawnFailure(error: SpawnError): string { if (error.kind === "spawn_failed") { return `spawn_failed: ${error.message}`; } if (error.kind === "timeout") { return `timeout: stdout=${error.stdout.slice(0, 200)} stderr=${error.stderr.slice(0, 200)}`; } return `non_zero_exit(${error.exitCode}): stderr=${error.stderr.slice(0, 400)}`; } export function errorText(error: SpawnError): string { if (error.kind === "spawn_failed") { return error.message.toLowerCase(); } if (error.kind === "timeout") { return `${error.stdout} ${error.stderr}`.toLowerCase(); } return `${error.stdout} ${error.stderr}`.toLowerCase(); } export function classifyIssueReaderFailure(error: SpawnError): { transientError: boolean; failureKind: "transient" | "permanent"; } { if (error.kind === "timeout" || error.kind === "spawn_failed") { return { transientError: true, failureKind: "transient" }; } const text = errorText(error); if ( text.includes("network") || text.includes("timed out") || text.includes("timeout") || text.includes("connection reset") || text.includes("connection refused") || text.includes("429") || text.includes("500") || text.includes("502") || text.includes("503") || text.includes("504") ) { return { transientError: true, failureKind: "transient" }; } return { transientError: false, failureKind: "permanent" }; } export function classifyPublisherFailure(error: SpawnError): "auth_or_network" | "permanent" { if (error.kind === "timeout" || error.kind === "spawn_failed") { return "auth_or_network"; } const text = errorText(error); if ( text.includes("401") || text.includes("403") || text.includes("auth") || text.includes("token") || text.includes("permission") || text.includes("network") || text.includes("connection") || text.includes("timeout") ) { return "auth_or_network"; } return "permanent"; }