feat(issues): make issues page writable with inline editing (#1017)

This commit is contained in:
Jinwoo Hong
2026-04-24 10:41:21 -07:00
committed by GitHub
parent 1772087db5
commit faed904aae
22 changed files with 2756 additions and 132 deletions
+30
View File
@@ -1,6 +1,7 @@
import { execFile } from 'child_process'
import { promisify } from 'util'
import { gitExecFileAsync, ghExecFileAsync } from '../git/runner'
import type { ClassifiedError } from '../../shared/types'
// Why: legacy generic execFile wrapper — only used by callers that don't need
// WSL-aware routing (e.g. non-repo-scoped gh commands). Repo-scoped callers
@@ -34,6 +35,35 @@ export function release(): void {
}
}
// ── Error classification ─────────────────────────────────────────────
// Why: gh CLI surfaces API errors as unstructured stderr. This helper maps
// known patterns to typed errors so callers can show user-friendly messages.
export function classifyGhError(stderr: string): ClassifiedError {
const s = stderr.toLowerCase()
if (s.includes('http 403') || s.includes('resource not accessible')) {
return {
type: 'permission_denied',
message: "You don't have permission to edit this issue. Check your GitHub token scopes."
}
}
if (s.includes('http 404') || s.includes('could not resolve')) {
return { type: 'not_found', message: 'Issue not found — it may have been deleted.' }
}
if (s.includes('http 422') || s.includes('validation failed')) {
return { type: 'validation_error', message: `Invalid update — ${stderr.trim()}` }
}
if (s.includes('rate limit')) {
return {
type: 'rate_limited',
message: 'GitHub rate limit hit. Try again in a few minutes.'
}
}
if (s.includes('timeout') || s.includes('no such host') || s.includes('network')) {
return { type: 'network_error', message: 'Network error — check your connection.' }
}
return { type: 'unknown', message: `Failed to update issue: ${stderr.trim()}` }
}
// ── Owner/repo resolution for gh api --cache ──────────────────────────
const ownerRepoCache = new Map<string, { owner: string; repo: string } | null>()