Add GitHub integration for PRs, issues and AI PR description (#205)

* feat: integrate GitHub OAuth device flow across runtimes

Add GitHub OAuth device flow endpoints across runtimes
Introduce GitHubSettings UI panel and sidebar entry
Persist GitHub auth state in per-runtime storage

* feat: add GitHub PR status and PR description generation

Show PR status for the current branch in the Git view
Generate a pull request description from the diff between base and head
Expose prStatus, prCreate, and prMerge APIs in web and desktop clients

* feat: add GitHub PR ready for review

Add API to mark pull requests as ready for review
Show a Ready button for draft PRs and reflect status in UI
Handle token expiration and GraphQL errors when marking ready
This commit is contained in:
Bohdan Triapitsyn
2026-01-23 16:08:58 +02:00
committed by GitHub
parent 0e715be7d6
commit 463e9ec4e3
43 changed files with 4999 additions and 106 deletions
@@ -11,7 +11,6 @@ import {
} from '@/components/ui/collapsible';
import { Button } from '@/components/ui/button';
import { ButtonLarge } from '@/components/ui/button-large';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { CommitInput } from './CommitInput';
import { AIHighlightsBox } from './AIHighlightsBox';
@@ -97,32 +96,25 @@ export const CommitSection: React.FC<CommitSectionProps> = ({
)}
<div className="flex items-center gap-2">
<Tooltip delayDuration={1000}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={onGenerateMessage}
disabled={
isGeneratingMessage ||
commitAction !== null ||
selectedCount === 0 ||
isBusy
}
aria-label="Generate commit message"
>
{isGeneratingMessage ? (
<RiLoader4Line className="size-4 animate-spin" />
) : (
<RiAiGenerate2 className="size-4 text-primary" />
)}
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8}>
Generate commit message with AI
</TooltipContent>
</Tooltip>
<Button
variant="outline"
size="sm"
onClick={onGenerateMessage}
disabled={
isGeneratingMessage ||
commitAction !== null ||
selectedCount === 0 ||
isBusy
}
type="button"
>
{isGeneratingMessage ? (
<RiLoader4Line className="size-4 animate-spin" />
) : (
<RiAiGenerate2 className="size-4 text-primary" />
)}
Generate
</Button>
<div className="flex-1" />