mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
refactor(runtime): declare the host-status entry once instead of per consumer (#20262)
This commit is contained in:
@@ -30,7 +30,7 @@ import type { SshConnectionState } from '../../../../shared/ssh-types'
|
||||
import type { ProjectHostSetup } from '../../../../shared/project-types'
|
||||
import type { Repo } from '../../../../shared/repo-types'
|
||||
import type { Worktree } from '../../../../shared/worktree/types'
|
||||
import type { RuntimeStatus } from '../../../../shared/runtime-types'
|
||||
import type { RuntimeEnvironmentStatus } from '../../../../shared/runtime-host-status'
|
||||
import type { TaskSourceHostAvailability } from '../task-source-context-summary'
|
||||
import type { AutomationRowAction } from './automation-captured-owner'
|
||||
import type { AutomationHostTarget } from './automation-host-client'
|
||||
@@ -70,10 +70,7 @@ export type AutomationListLocalRowProps = {
|
||||
worktreeForRow?: (row: AutomationListRow, repo: Repo | undefined) => Worktree | undefined
|
||||
projectHostSetups: readonly ProjectHostSetup[]
|
||||
sshConnectionStates: ReadonlyMap<string, Pick<SshConnectionState, 'status'>>
|
||||
runtimeStatusByEnvironmentId: ReadonlyMap<
|
||||
string,
|
||||
{ status: RuntimeStatus | null; checkedAt: number }
|
||||
>
|
||||
runtimeStatusByEnvironmentId: ReadonlyMap<string, RuntimeEnvironmentStatus>
|
||||
hostTargetFor: (row: AutomationListRow) => AutomationHostTarget | null
|
||||
automationSourceHostAvailabilityByRowKey: ReadonlyMap<string, TaskSourceHostAvailability[]>
|
||||
hostLabelById?: ReadonlyMap<string, string>
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { SshConnectionState } from '../../../../shared/ssh-types'
|
||||
import type { ProjectHostSetup } from '../../../../shared/project-types'
|
||||
import type { Repo } from '../../../../shared/repo-types'
|
||||
import type { Worktree } from '../../../../shared/worktree/types'
|
||||
import type { RuntimeStatus } from '../../../../shared/runtime-types'
|
||||
import type { RuntimeEnvironmentStatus } from '../../../../shared/runtime-host-status'
|
||||
import type { TaskSourceHostAvailability } from '../task-source-context-summary'
|
||||
import type { AutomationRowAction } from './automation-captured-owner'
|
||||
import type { AutomationHostTarget } from './automation-host-client'
|
||||
@@ -53,7 +53,7 @@ import { AutomationListToolbar } from './AutomationListToolbar'
|
||||
const TEMPLATE_EMPTY_STATES: ReadonlySet<string> = new Set(['host-empty', 'all-hosts-empty'])
|
||||
const EMPTY_AUTOMATION_RUNS: ReadonlyMap<string, AutomationRun> = new Map()
|
||||
|
||||
type AutomationsListPanelProps = {
|
||||
export type AutomationsListPanelProps = {
|
||||
hasListItems: boolean
|
||||
hasFilteredListItems: boolean
|
||||
listSearchQuery: string
|
||||
@@ -83,10 +83,7 @@ type AutomationsListPanelProps = {
|
||||
worktreeForRow?: (row: AutomationListRow, repo: Repo | undefined) => Worktree | undefined
|
||||
projectHostSetups: readonly ProjectHostSetup[]
|
||||
sshConnectionStates: ReadonlyMap<string, Pick<SshConnectionState, 'status'>>
|
||||
runtimeStatusByEnvironmentId: ReadonlyMap<
|
||||
string,
|
||||
{ status: RuntimeStatus | null; checkedAt: number }
|
||||
>
|
||||
runtimeStatusByEnvironmentId: ReadonlyMap<string, RuntimeEnvironmentStatus>
|
||||
hostTargetFor: (row: AutomationListRow) => AutomationHostTarget | null
|
||||
automationSourceHostAvailabilityByRowKey: ReadonlyMap<string, TaskSourceHostAvailability[]>
|
||||
hostLabelById?: ReadonlyMap<string, string>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY } from '../../../../shared/protocol-version'
|
||||
import { parseExecutionHostId } from '../../../../shared/execution-host'
|
||||
import type { Automation } from '../../../../shared/automations-types'
|
||||
import type { RuntimeStatus } from '../../../../shared/runtime-types'
|
||||
import type { RuntimeEnvironmentStatus } from '../../../../shared/runtime-host-status'
|
||||
import type { TaskSourceContext } from '../../../../shared/task-source-context'
|
||||
import type { TaskSourceHostAvailability } from '../task-source-context-summary'
|
||||
|
||||
@@ -20,10 +20,7 @@ export function getRepoBackedAutomationSourceContext(
|
||||
|
||||
export function getRuntimeSourceHostAvailability(
|
||||
context: TaskSourceContext,
|
||||
runtimeStatusByEnvironmentId: ReadonlyMap<
|
||||
string,
|
||||
{ status: RuntimeStatus | null; checkedAt: number }
|
||||
>
|
||||
runtimeStatusByEnvironmentId: ReadonlyMap<string, RuntimeEnvironmentStatus>
|
||||
): TaskSourceHostAvailability | null {
|
||||
const parsed = parseExecutionHostId(context.hostId)
|
||||
if (parsed?.kind !== 'runtime') {
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
import type { AutomationHostTarget } from './automation-host-client'
|
||||
import type { SshConnectionState } from '../../../../shared/ssh-types'
|
||||
import type { TaskSourceContext } from '../../../../shared/task-source-context'
|
||||
import type { RuntimeStatus } from '../../../../shared/runtime-types'
|
||||
import type { ProjectHostSetup } from '../../../../shared/project-types'
|
||||
import type { Repo } from '../../../../shared/repo-types'
|
||||
import type { RuntimeEnvironmentStatus } from '../../../../shared/runtime-host-status'
|
||||
import type { Worktree } from '../../../../shared/worktree/types'
|
||||
import type { TaskSourceHostAvailability } from '../task-source-context-summary'
|
||||
|
||||
@@ -51,10 +51,7 @@ type AutomationTargetAvailabilityArgs = {
|
||||
workspace: Worktree | null | undefined
|
||||
projectHostSetups: readonly ProjectHostSetup[]
|
||||
sshConnectionStates: ReadonlyMap<string, Pick<SshConnectionState, 'status'>>
|
||||
runtimeStatusByEnvironmentId?: ReadonlyMap<
|
||||
string,
|
||||
{ status: RuntimeStatus | null; checkedAt: number }
|
||||
>
|
||||
runtimeStatusByEnvironmentId?: ReadonlyMap<string, RuntimeEnvironmentStatus>
|
||||
automationHostTarget?: AutomationHostTarget | null
|
||||
sourceHostAvailability?: readonly TaskSourceHostAvailability[]
|
||||
}
|
||||
@@ -267,9 +264,7 @@ function getAutomationSourceProviderLabel(provider: TaskSourceContext['provider'
|
||||
|
||||
export function getRuntimeAutomationAvailability(
|
||||
environmentId: string,
|
||||
runtimeStatusByEnvironmentId:
|
||||
| ReadonlyMap<string, { status: RuntimeStatus | null; checkedAt: number }>
|
||||
| undefined
|
||||
runtimeStatusByEnvironmentId: ReadonlyMap<string, RuntimeEnvironmentStatus> | undefined
|
||||
): AutomationTargetAvailability {
|
||||
const entry = runtimeStatusByEnvironmentId?.get(environmentId)
|
||||
if (!entry) {
|
||||
|
||||
@@ -88,6 +88,7 @@ describe('getPaletteHostBadge', () => {
|
||||
[
|
||||
'env-1',
|
||||
{
|
||||
checkedAt: 0,
|
||||
status: {
|
||||
runtimeId: 'rt',
|
||||
rendererGraphEpoch: 0,
|
||||
|
||||
@@ -115,6 +115,7 @@ describe('sidebar host options', () => {
|
||||
[
|
||||
'runtime-1',
|
||||
{
|
||||
checkedAt: 0,
|
||||
status: {
|
||||
runtimeId: 'rt',
|
||||
rendererGraphEpoch: 0,
|
||||
@@ -147,6 +148,7 @@ describe('sidebar host options', () => {
|
||||
[
|
||||
'runtime-1',
|
||||
{
|
||||
checkedAt: 0,
|
||||
status: {
|
||||
runtimeId: 'rt',
|
||||
rendererGraphEpoch: 0,
|
||||
|
||||
@@ -12,8 +12,8 @@ import {
|
||||
} from '../../../../shared/execution-host-registry'
|
||||
import type { RuntimeCompatVerdict } from '../../../../shared/protocol-compat'
|
||||
import type { SshConnectionState, SshConnectionStatus } from '../../../../shared/ssh-types'
|
||||
import type { RuntimeStatus } from '../../../../shared/runtime-types'
|
||||
import type { PublicKnownRuntimeEnvironment } from '../../../../shared/runtime-environments'
|
||||
import type { RuntimeEnvironmentStatus } from '../../../../shared/runtime-host-status'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
|
||||
export type SidebarHostOption = {
|
||||
@@ -43,10 +43,7 @@ export function buildSidebarHostOptions(args: {
|
||||
settings: Pick<GlobalSettings, 'activeRuntimeEnvironmentId'> | null | undefined
|
||||
// Why: live per-environment runtime status lets the registry surface compat
|
||||
// verdicts and blocked health in the sidebar without re-probing servers.
|
||||
runtimeStatusByEnvironmentId?: ReadonlyMap<
|
||||
string,
|
||||
{ status?: RuntimeStatus | null; appVersion?: string | null }
|
||||
>
|
||||
runtimeStatusByEnvironmentId?: ReadonlyMap<string, RuntimeEnvironmentStatus>
|
||||
runtimeEnvironments?: readonly Pick<PublicKnownRuntimeEnvironment, 'id' | 'name'>[]
|
||||
// Why: per-host display-label overrides rename hosts everywhere the sidebar
|
||||
// options feed (host headers, scope picker, focus menu).
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// The store's host-status entry is one shape, and every reader of the map has to accept exactly
|
||||
// it. A narrower local copy still typechecks against the store — the fields it is missing are all
|
||||
// optional — so it freezes at the vintage it was written at and never fails. #17710 added
|
||||
// `remoteControl` and #20003 added `snapshot`; the copies these assertions cover were not updated
|
||||
// either time. Like the other typed-contract tests, they fail at typecheck, not at runtime.
|
||||
import { describe, expectTypeOf, it } from 'vitest'
|
||||
import type { buildExecutionHostRegistry } from '../../../../shared/execution-host-registry'
|
||||
import type { buildSidebarHostOptions } from '@/components/sidebar/sidebar-host-options'
|
||||
import type { getRuntimeAutomationAvailability } from '@/components/automations/automation-target-availability'
|
||||
import type { getRuntimeSourceHostAvailability } from '@/components/automations/automation-source-context'
|
||||
import type { AutomationListLocalRowProps } from '@/components/automations/AutomationListLocalRow'
|
||||
import type { AutomationsListPanelProps } from '@/components/automations/AutomationsListPanel'
|
||||
import type { RuntimeEnvironmentStatus } from './runtime-status-types'
|
||||
|
||||
// Compare the entry each reader accepts rather than the surrounding map, so a mismatch names the
|
||||
// field that drifted instead of every ReadonlyMap method signature.
|
||||
type AcceptedEntry<T> = NonNullable<T> extends ReadonlyMap<string, infer TEntry> ? TEntry : never
|
||||
|
||||
type RegistryEntry = AcceptedEntry<
|
||||
Parameters<typeof buildExecutionHostRegistry>[0]['runtimeStatusByEnvironmentId']
|
||||
>
|
||||
type SidebarEntry = AcceptedEntry<
|
||||
Parameters<typeof buildSidebarHostOptions>[0]['runtimeStatusByEnvironmentId']
|
||||
>
|
||||
type AutomationEntry = AcceptedEntry<Parameters<typeof getRuntimeAutomationAvailability>[1]>
|
||||
type SourceContextEntry = AcceptedEntry<Parameters<typeof getRuntimeSourceHostAvailability>[1]>
|
||||
type LocalRowEntry = AcceptedEntry<AutomationListLocalRowProps['runtimeStatusByEnvironmentId']>
|
||||
type ListPanelEntry = AcceptedEntry<AutomationsListPanelProps['runtimeStatusByEnvironmentId']>
|
||||
|
||||
describe('every reader of the runtime host status map accepts the store entry', () => {
|
||||
it('holds for the execution-host registry', () => {
|
||||
expectTypeOf<RegistryEntry>().toEqualTypeOf<RuntimeEnvironmentStatus>()
|
||||
})
|
||||
|
||||
it('holds for the sidebar host options', () => {
|
||||
expectTypeOf<SidebarEntry>().toEqualTypeOf<RuntimeEnvironmentStatus>()
|
||||
})
|
||||
|
||||
it('holds for runtime automation availability', () => {
|
||||
expectTypeOf<AutomationEntry>().toEqualTypeOf<RuntimeEnvironmentStatus>()
|
||||
})
|
||||
|
||||
// These three only forward the map, which is exactly how a stale copy survives: nothing they
|
||||
// do with it can fail, so the drift surfaces in whatever they hand it to.
|
||||
it('holds for the automation source-context reader', () => {
|
||||
expectTypeOf<SourceContextEntry>().toEqualTypeOf<RuntimeEnvironmentStatus>()
|
||||
})
|
||||
|
||||
it('holds for the automation list row', () => {
|
||||
expectTypeOf<LocalRowEntry>().toEqualTypeOf<RuntimeEnvironmentStatus>()
|
||||
})
|
||||
|
||||
it('holds for the automations list panel', () => {
|
||||
expectTypeOf<ListPanelEntry>().toEqualTypeOf<RuntimeEnvironmentStatus>()
|
||||
})
|
||||
})
|
||||
@@ -1,15 +1,10 @@
|
||||
import type { RuntimeHostStatusSnapshot } from '../../../../shared/runtime-host-status'
|
||||
import type {
|
||||
RuntimeEnvironmentStatus,
|
||||
RuntimeHostStatusSnapshot
|
||||
} from '../../../../shared/runtime-host-status'
|
||||
import type { PublicKnownRuntimeEnvironment } from '../../../../shared/runtime-environments'
|
||||
import type { RuntimeStatus } from '../../../../shared/runtime-types'
|
||||
|
||||
export type RuntimeEnvironmentStatus = {
|
||||
snapshot?: RuntimeHostStatusSnapshot
|
||||
status: RuntimeStatus | null
|
||||
remoteControl?: RuntimeStatus['remoteControl'] | null
|
||||
appVersion?: string | null
|
||||
checkedAt: number
|
||||
connectionGeneration?: number
|
||||
}
|
||||
export type { RuntimeEnvironmentStatus }
|
||||
|
||||
export type RuntimeStatusSlice = {
|
||||
readRuntimeHostStatusSnapshots: () => Promise<void>
|
||||
|
||||
@@ -121,6 +121,7 @@ describe('execution host registry', () => {
|
||||
[
|
||||
'builder',
|
||||
{
|
||||
checkedAt: 0,
|
||||
appVersion: '1.8.0',
|
||||
status: {
|
||||
runtimeId: 'runtime-builder',
|
||||
@@ -139,6 +140,7 @@ describe('execution host registry', () => {
|
||||
[
|
||||
'old-server',
|
||||
{
|
||||
checkedAt: 0,
|
||||
appVersion: '1.6.0',
|
||||
status: {
|
||||
runtimeId: 'runtime-old',
|
||||
@@ -187,6 +189,7 @@ describe('execution host registry', () => {
|
||||
[
|
||||
'dev-box',
|
||||
{
|
||||
checkedAt: 0,
|
||||
status: {
|
||||
runtimeId: 'runtime-dev',
|
||||
rendererGraphEpoch: 1,
|
||||
@@ -229,6 +232,7 @@ describe('execution host registry', () => {
|
||||
[
|
||||
'dev-box',
|
||||
{
|
||||
checkedAt: 0,
|
||||
status: null,
|
||||
remoteControl: {
|
||||
state: 'ready',
|
||||
@@ -264,6 +268,7 @@ describe('execution host registry', () => {
|
||||
[
|
||||
'vm-runtime',
|
||||
{
|
||||
checkedAt: 0,
|
||||
status: {
|
||||
runtimeId: 'runtime-vm',
|
||||
rendererGraphEpoch: 1,
|
||||
@@ -340,6 +345,7 @@ describe('execution host registry', () => {
|
||||
[
|
||||
'gpu',
|
||||
{
|
||||
checkedAt: 0,
|
||||
appVersion: '1.8.0',
|
||||
status: {
|
||||
runtimeId: 'runtime-gpu',
|
||||
@@ -381,6 +387,7 @@ it('keeps an initial unknown-transport verification connecting', () => {
|
||||
[
|
||||
'host',
|
||||
{
|
||||
checkedAt: 0,
|
||||
status: null,
|
||||
snapshot: {
|
||||
environmentId: 'host',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { RuntimeHostStatusSnapshot } from './runtime-host-status'
|
||||
import type { RuntimeEnvironmentStatus } from './runtime-host-status'
|
||||
import {
|
||||
LOCAL_EXECUTION_HOST_ID,
|
||||
getLocalExecutionHostLabel,
|
||||
@@ -49,14 +49,7 @@ type RuntimeEnvironmentSummary = {
|
||||
source?: RuntimeEnvironmentSource
|
||||
}
|
||||
|
||||
type RuntimeHostStatus = {
|
||||
snapshot?: RuntimeHostStatusSnapshot
|
||||
status?: RuntimeStatus | null
|
||||
remoteControl?: RuntimeStatus['remoteControl'] | null
|
||||
appVersion?: string | null
|
||||
}
|
||||
|
||||
type RuntimeStatusByEnvironmentId = ReadonlyMap<string, RuntimeHostStatus>
|
||||
type RuntimeStatusByEnvironmentId = ReadonlyMap<string, RuntimeEnvironmentStatus>
|
||||
|
||||
export type ExecutionHostSource = 'configured-only' | 'include-references'
|
||||
|
||||
|
||||
@@ -17,6 +17,21 @@ export type RuntimeHostStatusSnapshot = {
|
||||
retired?: true
|
||||
}
|
||||
|
||||
/**
|
||||
* One client-side record of a host's last status probe: the projected `status`, and the
|
||||
* `snapshot` evidence for what that projection is worth. Declared once rather than duck-typed
|
||||
* per consumer — every field added here has been optional, so a local structural copy keeps
|
||||
* typechecking against the store while silently missing whatever landed after it was written.
|
||||
*/
|
||||
export type RuntimeEnvironmentStatus = {
|
||||
snapshot?: RuntimeHostStatusSnapshot
|
||||
status: RuntimeStatus | null
|
||||
remoteControl?: RuntimeStatus['remoteControl'] | null
|
||||
appVersion?: string | null
|
||||
checkedAt: number
|
||||
connectionGeneration?: number
|
||||
}
|
||||
|
||||
export type RuntimeHostStatusResponse = RuntimeRpcResponse<RuntimeStatus>
|
||||
|
||||
export function runtimeHostStatusFailure(code: string, message: string): RuntimeRpcFailure {
|
||||
|
||||
Reference in New Issue
Block a user