67 lines
2.0 KiB
TypeScript

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";
}