mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
Adds GitHub stacked pull request creation: a contextual "Stack this PR above #N" option that appears only when the selected base branch has an open PR, plus the main-process stack preflight and registration. Also reworks the create-review composer for cohesion: shadcn Checkbox and Label primitives, base label above a full-width searchable combobox with attached results, keyboard navigation, and a unified field skin, spacing and typography scale. Verified end to end against real GitHub: extending an existing stack and creating a new one.
208 lines
5.7 KiB
TypeScript
208 lines
5.7 KiB
TypeScript
import type {
|
|
CheckStatus,
|
|
GitHubRepositoryIdentity,
|
|
PRConflictSummary,
|
|
PRMergeableState,
|
|
PRReviewDecision
|
|
} from './types'
|
|
|
|
export type HostedReviewProvider =
|
|
| 'github'
|
|
| 'gitlab'
|
|
| 'bitbucket'
|
|
| 'azure-devops'
|
|
| 'gitea'
|
|
| 'unsupported'
|
|
|
|
export type HostedReviewState = 'open' | 'closed' | 'merged' | 'draft'
|
|
|
|
// Why: Bitbucket Cloud's API has no draft pull requests, so offering the toggle
|
|
// there would either publish a live PR or fail at submit.
|
|
export function hostedReviewProviderSupportsDraft(provider: HostedReviewProvider): boolean {
|
|
return provider !== 'bitbucket'
|
|
}
|
|
|
|
/** A linked review is identified by a positive integer PR/MR number. */
|
|
export function isPositiveHostedReviewNumber(value: unknown): value is number {
|
|
return typeof value === 'number' && Number.isInteger(value) && value > 0
|
|
}
|
|
|
|
export type HostedReviewInfo = {
|
|
provider: HostedReviewProvider
|
|
number: number
|
|
title: string
|
|
state: HostedReviewState
|
|
url: string
|
|
status: CheckStatus
|
|
updatedAt: string
|
|
mergeable: PRMergeableState
|
|
reviewDecision?: PRReviewDecision | null
|
|
autoMergeEnabled?: boolean
|
|
autoMergeAllowed?: boolean | null
|
|
mergeQueueRequired?: boolean | null
|
|
mergeStateStatus?: string | null
|
|
headSha?: string
|
|
/** GitHub repository that owns the PR; absent on older runtimes and other providers. */
|
|
githubRepository?: GitHubRepositoryIdentity
|
|
// Why: mirrors PRInfo.confirmedContainedHeadOid so merged-review staleness
|
|
// checks accept a worktree head confirmed to be part of the merged PR.
|
|
confirmedContainedHeadOid?: string
|
|
/** Target branch name for review-created worktree compare-base repair. */
|
|
baseRefName?: string
|
|
conflictSummary?: PRConflictSummary
|
|
}
|
|
|
|
export type HostedReviewForBranchArgs = {
|
|
repoPath: string
|
|
repoId?: string
|
|
branch: string
|
|
linkedGitHubPR?: number | null
|
|
fallbackGitHubPR?: number | null
|
|
linkedGitLabMR?: number | null
|
|
linkedBitbucketPR?: number | null
|
|
linkedAzureDevOpsPR?: number | null
|
|
linkedGiteaPR?: number | null
|
|
// The worktree's checked-out HEAD oid (GitHub merged-at-head visibility).
|
|
currentHeadOid?: string | null
|
|
/**
|
|
* Set only by surfaces scoped to the selected worktree. That tier is O(1), so
|
|
* the host re-checks it per minute; the worktree list is O(N) and is paced far
|
|
* more slowly to stay inside the shared API budget (#11532).
|
|
*/
|
|
active?: boolean
|
|
}
|
|
|
|
export type HostedReviewSummary = {
|
|
number?: number
|
|
url: string
|
|
}
|
|
|
|
export type CreateHostedReviewInput = {
|
|
provider: HostedReviewProvider
|
|
base: string
|
|
head?: string
|
|
title: string
|
|
body?: string
|
|
draft?: boolean
|
|
worktreePath?: string
|
|
useTemplate?: boolean
|
|
}
|
|
|
|
export type CreateHostedReviewArgs = CreateHostedReviewInput & {
|
|
repoPath: string
|
|
repoId?: string
|
|
connectionId?: string | null
|
|
}
|
|
|
|
export type CreateStackedHostedReviewInput = CreateHostedReviewInput
|
|
|
|
export type CreateStackedHostedReviewArgs = CreateStackedHostedReviewInput & {
|
|
repoPath: string
|
|
repoId?: string
|
|
connectionId?: string | null
|
|
}
|
|
|
|
export type CreateHostedReviewErrorCode =
|
|
| 'auth_required'
|
|
| 'unsupported_provider'
|
|
| 'already_exists'
|
|
| 'validation'
|
|
| 'timeout'
|
|
| 'unknown_completion'
|
|
| 'push_failed'
|
|
| 'unknown'
|
|
|
|
export type CreateHostedReviewResult =
|
|
| { ok: true; number: number; url: string }
|
|
| {
|
|
ok: false
|
|
code: CreateHostedReviewErrorCode
|
|
error: string
|
|
existingReview?: HostedReviewSummary
|
|
}
|
|
|
|
export type CreateStackedHostedReviewResult =
|
|
| {
|
|
ok: true
|
|
number: number
|
|
url: string
|
|
stackNumber: number
|
|
parentReview: HostedReviewSummary
|
|
}
|
|
| {
|
|
ok: false
|
|
code: CreateHostedReviewErrorCode
|
|
error: string
|
|
createdReview?: HostedReviewSummary
|
|
}
|
|
|
|
export type HostedReviewCreationBlockedReason =
|
|
| 'dirty'
|
|
| 'detached_head'
|
|
| 'default_branch'
|
|
| 'no_upstream'
|
|
| 'needs_push'
|
|
| 'needs_sync'
|
|
| 'auth_required'
|
|
| 'fork_head_unsupported'
|
|
| 'unsupported_provider'
|
|
| 'existing_review'
|
|
// Why: a stacked worktree's local-only parent base is unresolvable on the
|
|
// remote; blocked at create-time so the submit fails with actionable copy
|
|
// instead of the provider's opaque error.
|
|
| 'base_not_on_remote'
|
|
| null
|
|
|
|
export type HostedReviewCreationNextAction =
|
|
| 'commit'
|
|
| 'publish'
|
|
| 'push'
|
|
| 'sync'
|
|
| 'authenticate'
|
|
| 'open_existing_review'
|
|
| null
|
|
|
|
/**
|
|
* Records whether the eligibility result observed an authoritative existing-review
|
|
* lookup. `found` / `not_found` come only from an accepted provider lookup;
|
|
* `unavailable` marks a local-blocker fallback returned after a swallowed or
|
|
* skipped lookup, so it can never masquerade as authoritative no-review evidence.
|
|
*/
|
|
export type HostedReviewLookupOutcome = 'found' | 'not_found' | 'unavailable'
|
|
|
|
export type HostedReviewCreationEligibility = {
|
|
provider: HostedReviewProvider
|
|
review: HostedReviewSummary | null
|
|
canCreate: boolean
|
|
blockedReason: HostedReviewCreationBlockedReason
|
|
nextAction: HostedReviewCreationNextAction
|
|
reviewLookupOutcome: HostedReviewLookupOutcome
|
|
defaultBaseRef?: string | null
|
|
head?: string | null
|
|
title?: string | null
|
|
body?: string | null
|
|
/** Present only when the executing host supports GitHub stack creation. */
|
|
stackedCreationSupported?: boolean
|
|
}
|
|
|
|
export type HostedReviewCreationEligibilityArgs = {
|
|
repoPath: string
|
|
repoId?: string
|
|
worktreePath?: string
|
|
connectionId?: string | null
|
|
branch: string
|
|
base?: string | null
|
|
hasUncommittedChanges?: boolean
|
|
hasUpstream?: boolean
|
|
ahead?: number
|
|
behind?: number
|
|
linkedGitHubPR?: number | null
|
|
fallbackGitHubPR?: number | null
|
|
linkedGitLabMR?: number | null
|
|
linkedBitbucketPR?: number | null
|
|
linkedAzureDevOpsPR?: number | null
|
|
linkedGiteaPR?: number | null
|
|
}
|
|
|
|
export type HostedReviewDecision = 'approved' | 'changes_requested' | 'review_required' | null
|