mirror of
https://github.com/stablyai/orca.git
synced 2026-10-09 08:02:35 +00:00
* feat: improve worktree import handling * chore: remove PR docs assets * rm html
254 lines
7.2 KiB
TypeScript
254 lines
7.2 KiB
TypeScript
import {
|
|
getRuntimePathBasename,
|
|
isWindowsAbsolutePathLike,
|
|
normalizeRuntimePathForComparison,
|
|
normalizeRuntimePathSeparators,
|
|
relativePathInsideRoot
|
|
} from './cross-platform-path'
|
|
import { parseWslUncPath } from './wsl-paths'
|
|
import type {
|
|
DetectedWorktree,
|
|
ExternalWorktreeVisibility,
|
|
GlobalSettings,
|
|
OrcaWorkspaceLayout,
|
|
Repo,
|
|
Worktree,
|
|
WorktreeMeta,
|
|
WorktreeOwnership
|
|
} from './types'
|
|
|
|
export const EXTERNAL_WORKTREE_VISIBILITY_ROLLOUT_AT = Date.UTC(2026, 4, 23)
|
|
|
|
export function isLegacyRepoForExternalWorktreeVisibility(repo: Repo): boolean {
|
|
if (typeof repo.externalWorktreeVisibilityLegacy === 'boolean') {
|
|
return repo.externalWorktreeVisibilityLegacy
|
|
}
|
|
if (repo.externalWorktreeVisibility === undefined) {
|
|
return true
|
|
}
|
|
if (!Number.isFinite(repo.addedAt)) {
|
|
return true
|
|
}
|
|
return repo.addedAt < EXTERNAL_WORKTREE_VISIBILITY_ROLLOUT_AT
|
|
}
|
|
|
|
export function effectiveExternalWorktreeVisibility(
|
|
repo: Pick<Repo, 'externalWorktreeVisibility'>,
|
|
isLegacyRepoForVisibility: boolean
|
|
): ExternalWorktreeVisibility {
|
|
if (repo.externalWorktreeVisibility) {
|
|
return repo.externalWorktreeVisibility
|
|
}
|
|
return isLegacyRepoForVisibility ? 'show' : 'hide'
|
|
}
|
|
|
|
export function buildKnownOrcaWorkspaceLayouts(
|
|
settings: Pick<GlobalSettings, 'workspaceDir' | 'nestWorkspaces' | 'workspaceDirHistory'>,
|
|
repo?: Pick<Repo, 'path' | 'connectionId'>
|
|
): OrcaWorkspaceLayout[] {
|
|
const layouts: OrcaWorkspaceLayout[] = []
|
|
if (!repo?.connectionId && settings.workspaceDir) {
|
|
layouts.push({ path: settings.workspaceDir, nestWorkspaces: settings.nestWorkspaces })
|
|
layouts.push(...(settings.workspaceDirHistory ?? []))
|
|
}
|
|
|
|
const wslLayouts = repo ? buildWslWorkspaceLayouts(repo.path, settings) : []
|
|
layouts.push(...wslLayouts)
|
|
|
|
const seen = new Set<string>()
|
|
return layouts.filter((layout) => {
|
|
const key = `${normalizeRuntimePathForComparison(layout.path)}:${layout.nestWorkspaces}`
|
|
if (seen.has(key)) {
|
|
return false
|
|
}
|
|
seen.add(key)
|
|
return Boolean(layout.path)
|
|
})
|
|
}
|
|
|
|
function buildWslWorkspaceLayouts(
|
|
repoPath: string,
|
|
settings: Pick<GlobalSettings, 'nestWorkspaces' | 'workspaceDirHistory'>
|
|
): OrcaWorkspaceLayout[] {
|
|
const parsed = parseWslUncPath(repoPath)
|
|
if (!parsed) {
|
|
return []
|
|
}
|
|
const homeMatch = parsed.linuxPath.match(/^\/home\/[^/]+(?:\/|$)/)
|
|
const linuxHome = homeMatch?.[0].replace(/\/$/, '')
|
|
if (!linuxHome) {
|
|
return []
|
|
}
|
|
const root = `//wsl.localhost/${parsed.distro}${linuxHome}/orca/workspaces`
|
|
const historicalModes = (settings.workspaceDirHistory ?? []).map(
|
|
(layout) => layout.nestWorkspaces
|
|
)
|
|
const modes = [settings.nestWorkspaces, ...historicalModes]
|
|
return [...new Set(modes)].map((nestWorkspaces) => ({ path: root, nestWorkspaces }))
|
|
}
|
|
|
|
export function classifyWorktreeOwnership(args: {
|
|
repo: Repo
|
|
worktree: Pick<Worktree, 'path' | 'isMainWorktree'>
|
|
meta?: WorktreeMeta
|
|
settings: Pick<GlobalSettings, 'workspaceDir' | 'nestWorkspaces' | 'workspaceDirHistory'>
|
|
knownOrcaLayouts: OrcaWorkspaceLayout[]
|
|
}): WorktreeOwnership {
|
|
if (hasStrongOrcaMetadata(args.meta)) {
|
|
return 'orca-managed'
|
|
}
|
|
|
|
if (matchesStrongOrcaCreatePath(args.worktree.path, args.knownOrcaLayouts, args.repo)) {
|
|
return 'orca-managed'
|
|
}
|
|
|
|
if (isUnderFlatOrUntrustedOrcaRoot(args.worktree.path, args.knownOrcaLayouts)) {
|
|
return 'unknown-legacy'
|
|
}
|
|
|
|
if (canClassifyAsExternal(args.worktree.path, args.knownOrcaLayouts)) {
|
|
return 'external'
|
|
}
|
|
|
|
return 'unknown-legacy'
|
|
}
|
|
|
|
export function toDetectedWorktree(args: {
|
|
repo: Repo
|
|
worktree: Worktree
|
|
meta?: WorktreeMeta
|
|
settings: Pick<GlobalSettings, 'workspaceDir' | 'nestWorkspaces' | 'workspaceDirHistory'>
|
|
knownOrcaLayouts: OrcaWorkspaceLayout[]
|
|
isLegacyRepoForVisibility?: boolean
|
|
}): DetectedWorktree {
|
|
const ownership = classifyWorktreeOwnership(args)
|
|
const selectedCheckout = areRuntimePathsEqual(args.worktree.path, args.repo.path)
|
|
const isLegacyRepoForVisibility =
|
|
args.isLegacyRepoForVisibility ?? isLegacyRepoForExternalWorktreeVisibility(args.repo)
|
|
const visible = shouldShowWorktree({
|
|
worktree: args.worktree,
|
|
ownership,
|
|
repo: args.repo,
|
|
isLegacyRepoForVisibility,
|
|
isSelectedCheckout: selectedCheckout
|
|
})
|
|
|
|
return {
|
|
...args.worktree,
|
|
ownership,
|
|
selectedCheckout,
|
|
visible
|
|
}
|
|
}
|
|
|
|
export function shouldShowWorktree(args: {
|
|
worktree: Pick<Worktree, 'path'>
|
|
ownership: WorktreeOwnership
|
|
repo: Repo
|
|
isLegacyRepoForVisibility: boolean
|
|
isSelectedCheckout: boolean
|
|
}): boolean {
|
|
if (args.isSelectedCheckout) {
|
|
return true
|
|
}
|
|
if (args.ownership === 'orca-managed') {
|
|
return true
|
|
}
|
|
if (args.ownership === 'unknown-legacy' && args.isLegacyRepoForVisibility) {
|
|
return true
|
|
}
|
|
return effectiveExternalWorktreeVisibility(args.repo, args.isLegacyRepoForVisibility) === 'show'
|
|
}
|
|
|
|
export function areRuntimePathsEqual(leftPath: string, rightPath: string): boolean {
|
|
return (
|
|
normalizeRuntimePathForComparison(leftPath) === normalizeRuntimePathForComparison(rightPath)
|
|
)
|
|
}
|
|
|
|
function hasStrongOrcaMetadata(meta: WorktreeMeta | undefined): boolean {
|
|
return Boolean(
|
|
meta?.orcaCreatedAt ||
|
|
meta?.createdAt ||
|
|
meta?.createdWithAgent ||
|
|
meta?.pushTarget ||
|
|
meta?.sparseBaseRef ||
|
|
meta?.sparsePresetId ||
|
|
meta?.preserveBranchOnDelete
|
|
)
|
|
}
|
|
|
|
function matchesStrongOrcaCreatePath(
|
|
worktreePath: string,
|
|
knownOrcaLayouts: OrcaWorkspaceLayout[],
|
|
repo: Pick<Repo, 'path'>
|
|
): boolean {
|
|
const repoName = getRuntimePathBasename(repo.path).replace(/\.git$/i, '')
|
|
if (!repoName) {
|
|
return false
|
|
}
|
|
for (const layout of knownOrcaLayouts) {
|
|
if (!layout.nestWorkspaces) {
|
|
continue
|
|
}
|
|
const relative = relativePathInsideRoot(layout.path, worktreePath)
|
|
if (relative === null) {
|
|
continue
|
|
}
|
|
const segments = splitNormalizedPath(relative)
|
|
const caseInsensitive =
|
|
isWindowsAbsolutePathLike(layout.path) || isWindowsAbsolutePathLike(worktreePath)
|
|
if (
|
|
segments.length === 2 &&
|
|
normalizePathSegment(segments[0], caseInsensitive) ===
|
|
normalizePathSegment(repoName, caseInsensitive) &&
|
|
segments[1].length > 0
|
|
) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
function isUnderFlatOrUntrustedOrcaRoot(
|
|
worktreePath: string,
|
|
knownOrcaLayouts: OrcaWorkspaceLayout[]
|
|
): boolean {
|
|
for (const layout of knownOrcaLayouts) {
|
|
const relative = relativePathInsideRoot(layout.path, worktreePath)
|
|
if (relative === null) {
|
|
continue
|
|
}
|
|
if (!layout.nestWorkspaces) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
function canClassifyAsExternal(
|
|
worktreePath: string,
|
|
knownOrcaLayouts: OrcaWorkspaceLayout[]
|
|
): boolean {
|
|
if (knownOrcaLayouts.length === 0) {
|
|
return false
|
|
}
|
|
for (const layout of knownOrcaLayouts) {
|
|
const relative = relativePathInsideRoot(layout.path, worktreePath)
|
|
if (relative === null) {
|
|
continue
|
|
}
|
|
return layout.nestWorkspaces
|
|
}
|
|
return true
|
|
}
|
|
|
|
function splitNormalizedPath(value: string): string[] {
|
|
return normalizeRuntimePathSeparators(value).split('/').filter(Boolean)
|
|
}
|
|
|
|
function normalizePathSegment(value: string, caseInsensitive: boolean): string {
|
|
const normalized = normalizeRuntimePathSeparators(value)
|
|
return caseInsensitive ? normalized.toLowerCase() : normalized
|
|
}
|