mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 08:02:31 +00:00
* fix(github): attribute GitHub API outages instead of blank/"failed" states When GitHub's API is unreachable (5xx outage, network, or rate limit), Orca showed no PR data with no explanation, so it read as an Orca bug rather than a GitHub-side problem. - Add a shared classifier (classifyGitHubUnavailable) reused by the main process and the renderer so every surface attributes an outage identically. A live outage returns HTTP 5xx, which the PR-refresh classifier previously had no branch for (fell through to the un-attributed "refresh failed"). - Right-sidebar Checks panel: show GitHub-attributed copy in the error empty-state, plus an inline banner over stale cached PR data so an outage doesn't look like a normal (silently out-of-date) panel. - Tasks/PR-list page: replace the vague "N of M projects failed to load" with a GitHub-attributed banner when the failure is a reachability problem. Copy names GitHub as the source and reassures it isn't an Orca problem, with no status-page link. Stays GitHub-scoped so GitLab/other providers aren't mislabeled. * fix(github): keep outage attribution accurate * fix(github): preserve outage attribution edge cases * fix(github): preserve Tasks outage attribution * fix(github): avoid false outage attribution * fix(runtime): tolerate absent browser certificate state * fix(ui): preserve exhaustive optional state handling * fix(github): preserve outage attribution for combined queries * fix(github): preserve runtime failure attribution * chore: restore unrelated UI files to main (out of scope) native-chat-session-option-labels.ts and skill-freshness-group.tsx switch tweaks were unrelated to GitHub API outage attribution — they fix pre-existing switch-exhaustiveness lint on main, which this PR's CI (oxlint) doesn't gate on. Restore them to origin/main so this PR's diff stays focused; the exhaustiveness cleanup belongs in its own change. (sync-runtime-graph.ts is already identical to main, so no diff there to revert.) * fix(github): drop Orca self-reference from outage copy * fix(github): drop em-dashes from outage copy
53 lines
2.7 KiB
TypeScript
53 lines
2.7 KiB
TypeScript
// Why: a GitHub outage, a dropped network, or a rate-limit all surface as
|
|
// unstructured gh/Octokit error text. Detecting them from one shared place lets
|
|
// both the main process (PR-refresh classification) and the renderer (Tasks
|
|
// work-item fan-out) attribute the failure to GitHub — not to Orca — using the
|
|
// exact same rules, so the two surfaces never disagree about whether GitHub is
|
|
// reachable. Returns null for anything that is NOT a reachability problem
|
|
// (auth, permission, 404): those are user-actionable, not "GitHub is down".
|
|
|
|
export type GitHubUnavailableKind = 'server_error' | 'network' | 'rate_limited'
|
|
|
|
// Rate-limit first: a primary rate-limit response also carries "HTTP 403", so
|
|
// it must win over any 4xx/permission interpretation downstream.
|
|
const RATE_LIMITED_PATTERN =
|
|
/rate limit|secondary rate limit|abuse detection|\bhttp[\s/]*429\b|\b429 too many requests\b/i
|
|
|
|
// Server-side outage. Anchor on "HTTP 5xx" or named 5xx statuses rather than a
|
|
// bare 3-digit match so unrelated numbers in stderr can't be misread as an
|
|
// outage.
|
|
const SERVER_ERROR_PATTERN =
|
|
/\bhttp[\s/]*5\d\d\b|\b5\d\d\s+(?:internal server error|bad gateway|service unavailable|gateway time-?out)\b|\binternal server error\b|\bbad gateway\b|\bservice unavailable\b|\bgateway time-?out\b|\bserver error\b|\btemporarily unavailable\b/i
|
|
|
|
// Transport-level failures — DNS, refused/reset connections, timeouts. Covers
|
|
// both Node (ENOTFOUND/ECONNRESET) and the gh Go client ("dial tcp", "i/o
|
|
// timeout", "no such host") shapes.
|
|
const NETWORK_PATTERN =
|
|
/timeout|\btimed out\b|\bno such host\b|could not resolve host|could not resolve to a host|\bnetwork(?:error| (?:error|unavailable|unreachable|request failed))\b|\bconnection (?:refused|reset)\b|\berror connecting to\b|\bfailed to connect to\b|\bdial tcp\b|\bi\/o timeout\b|\bfetch failed\b|\bsocket hang up\b|ENOTFOUND|ECONNRESET|ECONNREFUSED|ETIMEDOUT|EAI_AGAIN|ENETUNREACH/i
|
|
|
|
/**
|
|
* Classify a gh/Octokit error message as a GitHub-reachability problem, or
|
|
* null when it is not one (auth, permission, 404, validation, etc.).
|
|
*/
|
|
export function classifyGitHubUnavailable(message: string): GitHubUnavailableKind | null {
|
|
if (!message) {
|
|
return null
|
|
}
|
|
if (RATE_LIMITED_PATTERN.test(message)) {
|
|
return 'rate_limited'
|
|
}
|
|
if (SERVER_ERROR_PATTERN.test(message)) {
|
|
return 'server_error'
|
|
}
|
|
if (NETWORK_PATTERN.test(message)) {
|
|
return 'network'
|
|
}
|
|
return null
|
|
}
|
|
|
|
/** True when the message indicates GitHub itself is unreachable/unavailable. */
|
|
export function isGitHubUnavailableError(error: unknown): boolean {
|
|
const message = error instanceof Error ? error.message : String(error ?? '')
|
|
return classifyGitHubUnavailable(message) !== null
|
|
}
|