mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
refactor(repo-host): one helper for the hosts registering a repo id (#31634)
Four twin checks (sort stamps, sidebar unread, sort-order notify, worktree-meta owner) each rebuilt new Set(repos.filter(id).map(getRepoExecutionHostId)). Name it once as getRepoRegistrationHostIds in shared/repo-host-identity.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { getRepoRegistrationHostIds } from '../../shared/repo-host-identity'
|
||||
import { getRepoExecutionHostId, type ExecutionHostId } from '../../shared/execution-host'
|
||||
import type { Repo } from '../../shared/repo-types'
|
||||
import type { WorktreeMeta } from '../../shared/worktree/meta-types'
|
||||
@@ -86,7 +87,7 @@ export function resolveWorktreeMetaOwner(
|
||||
const repoId = getRepoIdFromWorktreeId(worktreeId)
|
||||
const owners = store.getRepos().filter((repo) => repo.id === repoId)
|
||||
// Why: the raw-id row's stamp names whichever twin wrote first, not the twin the caller means.
|
||||
if (new Set(owners.map(getRepoExecutionHostId)).size > 1) {
|
||||
if (getRepoRegistrationHostIds(owners, repoId).size > 1) {
|
||||
return undefined
|
||||
}
|
||||
const stamped = store.getWorktreeMeta(worktreeId)?.hostId
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { getRepoRegistrationHostIds } from '../../shared/repo-host-identity'
|
||||
import type { GitPushTarget, Worktree } from '../../shared/worktree/types'
|
||||
import type { WorktreeMeta } from '../../shared/worktree/meta-types'
|
||||
import { worktreeWorkspaceKey } from '../../shared/workspace-scope'
|
||||
import { splitWorktreeId } from '../../shared/worktree/id'
|
||||
import { getRepoExecutionHostId } from '../../shared/execution-host'
|
||||
import type { WorktreeSortOrderUpdate } from '../../shared/worktree/sort-order-update'
|
||||
import { stripOrcaProvenanceMetaUpdates } from '../worktree-removal-safety'
|
||||
import { isRemovedFolderWorkspaceInstance } from '../folder-workspace-meta-presence'
|
||||
@@ -174,13 +174,8 @@ export function persistRuntimeManagedWorktreeSortOrder(args: {
|
||||
}
|
||||
}
|
||||
for (const [repoId, sortOrders] of updatesByRepo) {
|
||||
const hosts = new Set(
|
||||
args.store
|
||||
.getRepos()
|
||||
.filter((repo) => repo.id === repoId)
|
||||
.map(getRepoExecutionHostId)
|
||||
)
|
||||
args.notifyChanged(repoId, hosts.size > 1 ? undefined : sortOrders)
|
||||
const isTwin = getRepoRegistrationHostIds(args.store.getRepos(), repoId).size > 1
|
||||
args.notifyChanged(repoId, isTwin ? undefined : sortOrders)
|
||||
}
|
||||
return { updated: updates.length }
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getRepoRegistrationHostIds } from '../../../shared/repo-host-identity'
|
||||
import { isRemoteRuntimePtyId } from '../../../shared/remote-runtime-pty-id'
|
||||
import { OrcaRuntimeWithDetectedCheckoutsAndLiveContent } from './orca-runtime-detected-checkouts-live-content'
|
||||
import type { OrcaRuntimeWithAgentTransitions } from '../orca-runtime-agent-transitions'
|
||||
@@ -5,7 +6,6 @@ import { ORCA_SIDEBAR_INPUTS_IS_MAIN } from '../../../shared/sidebar-inputs-swit
|
||||
import { DEFAULT_HIDE_SLEEPING_WORKSPACES } from '../../../shared/constants'
|
||||
import {
|
||||
getConnectionExecutionHostId,
|
||||
getRepoExecutionHostId,
|
||||
isLocalExecutionHost,
|
||||
LOCAL_EXECUTION_HOST_ID,
|
||||
parseExecutionHostId,
|
||||
@@ -202,12 +202,7 @@ export abstract class OrcaRuntimeWithSidebarTemporal extends OrcaRuntimeWithDete
|
||||
return false
|
||||
}
|
||||
const repoId = getRepoIdFromWorktreeId(worktreeId)
|
||||
const hosts = new Set(
|
||||
(this.store?.getRepos() ?? [])
|
||||
.filter((repo) => repo.id === repoId)
|
||||
.map(getRepoExecutionHostId)
|
||||
)
|
||||
return hosts.size > 1
|
||||
return getRepoRegistrationHostIds(this.store?.getRepos() ?? [], repoId).size > 1
|
||||
}
|
||||
|
||||
private workspaceHostId(worktreeId: string): ExecutionHostId | null {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { getRepoRegistrationHostIds } from '../../../shared/repo-host-identity'
|
||||
import type { AgentPaneWorkspace } from '../../agent-hooks/agent-transition-detector'
|
||||
import {
|
||||
getRepoExecutionHostId,
|
||||
LOCAL_EXECUTION_HOST_ID,
|
||||
type ExecutionHostId
|
||||
} from '../../../shared/execution-host'
|
||||
import { LOCAL_EXECUTION_HOST_ID, type ExecutionHostId } from '../../../shared/execution-host'
|
||||
import { getRepoIdFromWorktreeId } from '../../../shared/worktree/id'
|
||||
import type {
|
||||
SmartStampFields,
|
||||
@@ -70,13 +67,7 @@ function localTwinHostId(
|
||||
store: Pick<WorkspaceRecordStore<unknown, never>, 'getRepos'>,
|
||||
worktreeId: string
|
||||
): ExecutionHostId | null {
|
||||
const repoId = getRepoIdFromWorktreeId(worktreeId)
|
||||
const hosts = new Set(
|
||||
store
|
||||
.getRepos()
|
||||
.filter((repo) => repo.id === repoId)
|
||||
.map(getRepoExecutionHostId)
|
||||
)
|
||||
const hosts = getRepoRegistrationHostIds(store.getRepos(), getRepoIdFromWorktreeId(worktreeId))
|
||||
return hosts.size > 1 && hosts.has(LOCAL_EXECUTION_HOST_ID) ? LOCAL_EXECUTION_HOST_ID : null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { describe, expect, expectTypeOf, it } from 'vitest'
|
||||
import { toRuntimeExecutionHostId, toSshExecutionHostId } from './execution-host'
|
||||
import { getRepoHostIdentityForParts, type HostScopedRepoKey } from './repo-host-identity'
|
||||
import {
|
||||
getRepoHostIdentityForParts,
|
||||
getRepoRegistrationHostIds,
|
||||
type HostScopedRepoKey
|
||||
} from './repo-host-identity'
|
||||
|
||||
// Why: these keys index persisted and cross-module repo state, so the bytes are frozen (D25).
|
||||
describe('repo host identity golden bytes', () => {
|
||||
@@ -29,3 +33,16 @@ describe('repo host identity golden bytes', () => {
|
||||
expect(raw).toBe(forged)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getRepoRegistrationHostIds', () => {
|
||||
it('collects each host registering the id once, across both SSH spellings', () => {
|
||||
const repos = [
|
||||
{ id: 'repo-1' },
|
||||
{ id: 'repo-1', connectionId: 'box' },
|
||||
{ id: 'repo-1', executionHostId: 'ssh:box' as const },
|
||||
{ id: 'repo-2', executionHostId: 'runtime:env' as const }
|
||||
]
|
||||
expect(getRepoRegistrationHostIds(repos, 'repo-1')).toEqual(new Set(['local', 'ssh:box']))
|
||||
expect(getRepoRegistrationHostIds(repos, 'missing').size).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getRepoExecutionHostId, type ExecutionHostId } from './execution-host'
|
||||
import type { Repo } from './repo-types'
|
||||
|
||||
declare const hostScopedRepoKeyBrand: unique symbol
|
||||
@@ -14,3 +15,11 @@ export function getRepoHostIdentityForParts(repoId: string, hostId: string): Hos
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: this is the only constructor of the brand; the bytes are the unbranded composite, frozen by golden tests (D25).
|
||||
return `${hostId}\0${repoId}` as HostScopedRepoKey
|
||||
}
|
||||
|
||||
/** The hosts registering `repoId`; two or more means same-id twins on different hosts. */
|
||||
export function getRepoRegistrationHostIds(
|
||||
repos: readonly RepoHostTarget[],
|
||||
repoId: string
|
||||
): Set<ExecutionHostId> {
|
||||
return new Set(repos.filter((repo) => repo.id === repoId).map(getRepoExecutionHostId))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user