export type ClineErrorType = | "not_subscribed" | "auth_expired" | "rate_limited" | "unknown"; function matchesAny(text: string, patterns: string[]): boolean { return patterns.some((p) => text.includes(p)); } export const CLINE_ERROR_MESSAGES: Record = { not_subscribed: "This model requires a ClinePass subscription — visit app.cline.bot to subscribe. " + "Free-tier models (z-ai/*) work without one.", auth_expired: "Cline authentication expired. Run `pi /login` and select Cline, or run `cline auth` first.", rate_limited: "Cline rate limit reached. Wait a moment and try again.", unknown: "Cline request failed. Run `cline auth` or `pi /login` to refresh credentials.", }; export function classifyClineError(errorMessage: string): { type: ClineErrorType; message: string; } { const lower = errorMessage.toLowerCase(); if ( matchesAny(lower, [ "entitlement", "not subscribed", "required model plan", ]) ) { return { type: "not_subscribed", message: CLINE_ERROR_MESSAGES.not_subscribed }; } if (matchesAny(lower, ["401", "unauthorized", "invalid api key", "invalid_api_key"])) { return { type: "auth_expired", message: CLINE_ERROR_MESSAGES.auth_expired }; } if (matchesAny(lower, ["429", "rate limit", "too many requests", "rate_limit"])) { return { type: "rate_limited", message: CLINE_ERROR_MESSAGES.rate_limited }; } return { type: "unknown", message: CLINE_ERROR_MESSAGES.unknown }; }