mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 18:47:40 +00:00
* [comment audit] Shorten daemon, hook, and emulator comments [skip ci] * [comment audit] Shorten VM, conversation, SQLite, and theme-import comments [skip ci] * [comment audit] Tighten Git execution and source-control comment contracts [skip ci] * [comment audit] Clarify repository probes and maintenance comments [skip ci] * [comment audit] Shorten status, diff-cache, and checkout comments [skip ci] * [comment audit] Clarify worktree lifecycle and WSL routing comments [skip ci] * [comment audit] Shorten forge identity and review-refresh comments [skip ci] * [comment audit] Tighten hosted-review client comment contracts [skip ci] * [comment audit] Clarify GitLab compatibility and review comments [skip ci] * [comment audit] Tighten hook ownership and watchdog rationale [skip ci] * [comment audit] Condense host and integration compatibility comments [skip ci] * [comment audit] Clarify IPC authority and remote-routing rationale [skip ci] * [comment audit] Finalize file-import and containment comment cleanup * [comment audit] Fix stale Jira type imports blocking full CI --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
241 lines
7.1 KiB
TypeScript
241 lines
7.1 KiB
TypeScript
import type { GitHubOwnerRepo } from '../../shared/github/pull-request-types'
|
|
import type { IssueSourcePreference } from '../../shared/repo-types'
|
|
import {
|
|
githubRepoIdentityKey,
|
|
isDefaultGitHubHost
|
|
} from '../../shared/github/repository-identity-key'
|
|
import { shouldProbeGitRemote } from '../git/remote-name-listing'
|
|
import { ghRepoExecOptions, githubRepoContext, type LocalGitExecOptions } from './gh-utils'
|
|
import { isGitHubHostAuthenticated } from './github-enterprise-repository'
|
|
import { githubHostExecOptions } from './github-repository-host'
|
|
import {
|
|
isValidGitHubApiRepository,
|
|
type GitHubApiRepositoryResolution
|
|
} from './github-api-repository-validation'
|
|
import {
|
|
_resetOriginGitHubApiRepositoryCache,
|
|
getGitHubApiRepositoryForRemote,
|
|
getOriginGitHubApiRepository
|
|
} from './github-api-repository-remote-probe'
|
|
|
|
export {
|
|
githubHostExecOptions,
|
|
githubRepositorySlugArg,
|
|
githubRepositoryWebHost
|
|
} from './github-repository-host'
|
|
export type GitHubApiRepository = GitHubOwnerRepo
|
|
export type GitHubRepoExecOptions = ReturnType<typeof ghRepoExecOptions> & {
|
|
host?: string
|
|
env?: NodeJS.ProcessEnv
|
|
}
|
|
export type GitHubRepoExecution = {
|
|
ownerRepo: GitHubApiRepository | null
|
|
ghOptions: GitHubRepoExecOptions
|
|
}
|
|
export {
|
|
_resetOriginGitHubApiRepositoryCache,
|
|
getGitHubApiRepositoryForRemote,
|
|
getOriginGitHubApiRepository
|
|
}
|
|
|
|
/** Hosted mirror of getIssueOwnerRepo: issues prefer `upstream` over `origin`. */
|
|
export async function getIssueGitHubApiRepository(
|
|
repoPath: string,
|
|
connectionId?: string | null,
|
|
localGitOptions: LocalGitExecOptions = {}
|
|
): Promise<GitHubApiRepository | null> {
|
|
const originPromise = getGitHubApiRepositoryForRemote(
|
|
repoPath,
|
|
'origin',
|
|
connectionId,
|
|
localGitOptions
|
|
).then(
|
|
(value) => ({ status: 'fulfilled' as const, value }),
|
|
(reason: unknown) => ({ status: 'rejected' as const, reason })
|
|
)
|
|
const upstream = (await shouldProbeGitRemote(repoPath, 'upstream', connectionId, localGitOptions))
|
|
? await getGitHubApiRepositoryForRemote(repoPath, 'upstream', connectionId, localGitOptions)
|
|
: null
|
|
if (upstream) {
|
|
return upstream
|
|
}
|
|
const origin = await originPromise
|
|
if (origin.status === 'rejected') {
|
|
throw origin.reason
|
|
}
|
|
return origin.value
|
|
}
|
|
|
|
export type GitHubApiRepositoryCandidates = {
|
|
candidates: GitHubApiRepository[]
|
|
headRepo: GitHubApiRepository | null
|
|
}
|
|
|
|
/** Hosted mirror of resolvePRRepositoryCandidates: upstream first, then origin. */
|
|
export async function resolveGitHubApiRepositoryCandidates(
|
|
repoPath: string,
|
|
connectionId?: string | null,
|
|
localGitOptions: LocalGitExecOptions = {}
|
|
): Promise<GitHubApiRepositoryCandidates> {
|
|
const originPromise = getGitHubApiRepositoryForRemote(
|
|
repoPath,
|
|
'origin',
|
|
connectionId,
|
|
localGitOptions,
|
|
{
|
|
requireVerifiedSshProbe: true
|
|
}
|
|
).then(
|
|
(value) => ({ status: 'fulfilled' as const, value }),
|
|
(reason: unknown) => ({ status: 'rejected' as const, reason })
|
|
)
|
|
const probeUpstream = await shouldProbeGitRemote(
|
|
repoPath,
|
|
'upstream',
|
|
connectionId,
|
|
localGitOptions
|
|
)
|
|
const [upstream, originResult] = await Promise.all([
|
|
probeUpstream
|
|
? getGitHubApiRepositoryForRemote(repoPath, 'upstream', connectionId, localGitOptions, {
|
|
requireVerifiedSshProbe: true
|
|
})
|
|
: null,
|
|
originPromise
|
|
])
|
|
if (originResult.status === 'rejected') {
|
|
throw originResult.reason
|
|
}
|
|
const origin = originResult.value
|
|
const seen = new Set<string>()
|
|
const candidates: GitHubApiRepository[] = []
|
|
for (const candidate of [upstream, origin]) {
|
|
if (!candidate) {
|
|
continue
|
|
}
|
|
const key = githubRepoIdentityKey(candidate)
|
|
if (seen.has(key)) {
|
|
continue
|
|
}
|
|
seen.add(key)
|
|
candidates.push(candidate)
|
|
}
|
|
return { candidates, headRepo: origin }
|
|
}
|
|
|
|
export type ResolvedGitHubApiRepositorySource = {
|
|
source: GitHubApiRepository | null
|
|
/** True when explicit upstream is gone and resolver fell back to origin. */
|
|
fellBack: boolean
|
|
}
|
|
|
|
export async function resolveIssueGitHubApiRepositorySource(
|
|
repoPath: string,
|
|
preference: IssueSourcePreference | undefined,
|
|
connectionId?: string | null,
|
|
localGitOptions: LocalGitExecOptions = {}
|
|
): Promise<ResolvedGitHubApiRepositorySource> {
|
|
if (preference === 'upstream') {
|
|
const upstream = await getGitHubApiRepositoryForRemote(
|
|
repoPath,
|
|
'upstream',
|
|
connectionId,
|
|
localGitOptions
|
|
)
|
|
if (upstream) {
|
|
return { source: upstream, fellBack: false }
|
|
}
|
|
const origin = await getGitHubApiRepositoryForRemote(
|
|
repoPath,
|
|
'origin',
|
|
connectionId,
|
|
localGitOptions
|
|
)
|
|
return { source: origin, fellBack: origin !== null }
|
|
}
|
|
if (preference === 'origin') {
|
|
return {
|
|
source: await getGitHubApiRepositoryForRemote(
|
|
repoPath,
|
|
'origin',
|
|
connectionId,
|
|
localGitOptions
|
|
),
|
|
fellBack: false
|
|
}
|
|
}
|
|
return {
|
|
source: await getIssueGitHubApiRepository(repoPath, connectionId, localGitOptions),
|
|
fellBack: false
|
|
}
|
|
}
|
|
|
|
export async function resolveGitHubApiRepository(
|
|
repoPath: string,
|
|
repository?: GitHubApiRepository | null,
|
|
connectionId?: string | null,
|
|
localGitOptions: LocalGitExecOptions = {}
|
|
): Promise<GitHubApiRepository | null> {
|
|
if (repository && !isValidGitHubApiRepository(repository)) {
|
|
return null
|
|
}
|
|
if (repository?.host) {
|
|
const host = repository.host.trim().toLowerCase()
|
|
if (!host) {
|
|
return null
|
|
}
|
|
if (isDefaultGitHubHost(host)) {
|
|
return { ...repository, host }
|
|
}
|
|
// Verify supplied hosts against local auth inventory before giving them ambient Enterprise credentials.
|
|
const authenticated = await isGitHubHostAuthenticated(
|
|
host,
|
|
repoPath,
|
|
connectionId,
|
|
localGitOptions
|
|
)
|
|
return authenticated ? { ...repository, host } : null
|
|
}
|
|
const originRepository = await getOriginGitHubApiRepository(
|
|
repoPath,
|
|
connectionId,
|
|
localGitOptions
|
|
)
|
|
if (!repository) {
|
|
return originRepository
|
|
}
|
|
// Older clients omit host; resolved origin supplies it for fork-base slugs on the same server.
|
|
if (originRepository?.host) {
|
|
return { ...repository, host: originRepository.host }
|
|
}
|
|
// Host-less calls could follow ambient GH_HOST; only resolved origin can supply the legacy host.
|
|
return null
|
|
}
|
|
|
|
export async function resolveGitHubRepoExecution(
|
|
repoPath: string,
|
|
repository?: GitHubApiRepositoryResolution,
|
|
connectionId?: string | null,
|
|
localGitOptions: LocalGitExecOptions = {}
|
|
): Promise<GitHubRepoExecution> {
|
|
// Retain upstream-first issue resolution with the same host-pinned execution options.
|
|
const requestedRepository = typeof repository === 'function' ? await repository() : repository
|
|
// Preserve authoritative nulls instead of replacing them with origin.
|
|
const ownerRepo =
|
|
typeof repository === 'function' && !requestedRepository
|
|
? null
|
|
: await resolveGitHubApiRepository(
|
|
repoPath,
|
|
requestedRepository,
|
|
connectionId,
|
|
localGitOptions
|
|
)
|
|
return {
|
|
ownerRepo,
|
|
ghOptions: {
|
|
...ghRepoExecOptions(githubRepoContext(repoPath, connectionId, localGitOptions)),
|
|
...githubHostExecOptions(ownerRepo)
|
|
}
|
|
}
|
|
}
|