Files
orca/src/preload/api/managed-orcad-api.ts
T
NeilandClaude Opus 5.5 8e9f86b119 feat(managed-server): Update and Update anyway for a managed SSH server, keeping its running terminals (#33397)
* feat(managed-server): offer Update and Update anyway on a managed SSH server's row

A managed SSH server only updated on connect, and every connect deferred while
a terminal ran there. Its row now offers Update when this desktop bundles a
newer build than the Orca that runs the host. When running terminals defer it,
Update anyway restarts the server past them; the terminal daemon carries them
across the restart.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(managed-server): Update anyway passes only counted live terminals and keeps Update's version admission

Update anyway now sends the incumbent build it confirmed over; under the host
fence it is refused if another desktop activated a build since, keeps the
newer-host downgrade refusal, and never passes an uncounted terminal census.
The offer also covers hosts activated before the Orca version was recorded,
for the build this desktop already deferred there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(managed-server): Update anyway also confirms a menu Update the row does not advertise

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(managed-server): the row shows one confirmation at a time

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* ci(e2e): route managed-server update sources to the Update anyway Docker spec

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 22:49:18 -07:00

90 lines
4.5 KiB
TypeScript

/** Managed orcad servers over SSH; desktop-only, so web clients leave it undefined. */
import { ipcRenderer } from 'electron'
import type {
OrcadDeltaMovePreview,
OrcadDeltaMoveResult,
OrcadManagedCancelStopResult,
OrcadManagedConversionResult,
OrcadManagedDeployResult,
OrcadManagedForgetResult,
OrcadManagedPastLiveTerminals,
OrcadManagedPendingMigrationRow,
OrcadManagedRecoveryResult,
OrcadManagedRestartResult,
OrcadManagedStaleLockReclaimRequest,
OrcadManagedStaleLockReclaimResult,
OrcadManagedRollbackResult,
OrcadManagedRuntimeStatus,
OrcadManagedStopResult
} from '../../shared/orcad-managed-runtime'
import type { PublicKnownRuntimeEnvironment } from '../../shared/runtime-environments'
import type {
RuntimeSshAccessLinkRequest,
RuntimeSshAccessUnlinkRequest
} from '../../shared/runtime-ssh-access'
export type ManagedOrcadPreloadApi = {
deploy: (args: {
name: string
sshTargetId: string
force?: boolean
}) => Promise<OrcadManagedDeployResult>
getStatus: (args: { selector: string }) => Promise<OrcadManagedRuntimeStatus>
update: (args: {
selector: string
force?: boolean
pastLiveTerminals?: OrcadManagedPastLiveTerminals
}) => Promise<OrcadManagedDeployResult>
rollback: (args: { selector: string }) => Promise<OrcadManagedRollbackResult>
recover: (args: {
selector: string
/** Restore the snapshot over state a rejected build changed; see ORCAD_RECOVERY_CHANGED_STATE_CODE. */
acceptChangedState?: boolean
}) => Promise<OrcadManagedRecoveryResult>
/** Restarts from this client's SSH session; refused while terminals run. */
restart: (args: { selector: string }) => Promise<OrcadManagedRestartResult>
/** Without `yes`, only reports whether the host's instance lock may be cleared. */
reclaimStaleLock: (
args: { selector: string } & OrcadManagedStaleLockReclaimRequest
) => Promise<OrcadManagedStaleLockReclaimResult>
stop: (args: { selector: string }) => Promise<OrcadManagedStopResult>
cancelStop: (args: { selector: string }) => Promise<OrcadManagedCancelStopResult>
forget: (args: { selector: string }) => Promise<OrcadManagedForgetResult>
linkSshAccess: (args: RuntimeSshAccessLinkRequest) => Promise<PublicKnownRuntimeEnvironment>
unlinkSshAccess: (args: RuntimeSshAccessUnlinkRequest) => Promise<PublicKnownRuntimeEnvironment>
convertSshHost: (args: {
sshTargetId: string
name: string
}) => Promise<OrcadManagedConversionResult>
listPendingMigrations: () => Promise<OrcadManagedPendingMigrationRow[]>
previewDeltaMove: (args: { sshTargetId: string }) => Promise<OrcadDeltaMovePreview>
moveDelta: (args: { sshTargetId: string }) => Promise<OrcadDeltaMoveResult>
keepServerVersion: (args: { sshTargetId: string }) => Promise<void>
/** "Move anyway": the next connect leaves what can't move on this desktop. */
allowMoveLeavingBehind: (args: { sshTargetId: string }) => Promise<void>
}
export const managedOrcadApi: ManagedOrcadPreloadApi = {
deploy: (args) => ipcRenderer.invoke('runtimeEnvironments:deployOrcad', args),
getStatus: (args) => ipcRenderer.invoke('runtimeEnvironments:getOrcadStatus', args),
update: (args) => ipcRenderer.invoke('runtimeEnvironments:updateOrcad', args),
rollback: (args) => ipcRenderer.invoke('runtimeEnvironments:rollbackOrcad', args),
recover: (args) => ipcRenderer.invoke('runtimeEnvironments:recoverOrcad', args),
restart: (args) => ipcRenderer.invoke('runtimeEnvironments:restartOrcad', args),
reclaimStaleLock: (args) => ipcRenderer.invoke('runtimeEnvironments:reclaimOrcadStaleLock', args),
stop: (args) => ipcRenderer.invoke('runtimeEnvironments:stopOrcad', args),
cancelStop: (args) => ipcRenderer.invoke('runtimeEnvironments:cancelOrcadStop', args),
forget: (args) => ipcRenderer.invoke('runtimeEnvironments:forgetOrcad', args),
linkSshAccess: (args) => ipcRenderer.invoke('runtimeEnvironments:linkSshAccess', args),
unlinkSshAccess: (args) => ipcRenderer.invoke('runtimeEnvironments:unlinkSshAccess', args),
convertSshHost: (args) =>
ipcRenderer.invoke('runtimeEnvironments:convertSshHostToManagedOrcad', args),
listPendingMigrations: () => ipcRenderer.invoke('runtimeEnvironments:listPendingOrcadMigrations'),
previewDeltaMove: (args) => ipcRenderer.invoke('runtimeEnvironments:previewOrcadDeltaMove', args),
moveDelta: (args) => ipcRenderer.invoke('runtimeEnvironments:moveOrcadDelta', args),
keepServerVersion: (args) =>
ipcRenderer.invoke('runtimeEnvironments:keepOrcadServerVersion', args),
allowMoveLeavingBehind: (args) =>
ipcRenderer.invoke('runtimeEnvironments:allowOrcadMoveLeavingBehind', args)
}