import { type Server } from 'node:net'; import { type AgentRelease, type StagedAgentRelease, type UpdateCommand, type UpdateCommandResult } from './agent-update'; import { type AgentRuntimeHandoff } from './agent-handover'; export declare const AGENT_UPDATE_GROUP = "forgezero-update"; export declare const AGENT_UPDATE_HELPER_UNIT_PATH = "/etc/systemd/system/forgezero-agent-update-helper.service"; /** Root-private crash transaction. Existing 0.1.31 hosts may contain its legacy success receipt here. */ export declare const AGENT_UPDATE_JOURNAL = "/var/lib/forgezero/agent-update.json"; /** Bounded, group-readable evidence consumed by the unprivileged Agent heartbeat. */ export declare const AGENT_UPDATE_RECEIPT = "/var/lib/forgezero/agent-update-receipt.json"; export type AgentUpdateRequest = { op: 'prepare'; target: 'compute' | 'metal'; attemptId?: string; currentVersion: string; expectedNodeKey: string; release: AgentRelease; } | { op: 'commit'; target: 'compute' | 'metal'; attemptId: string; currentVersion: string; targetVersion: string; handoff: AgentRuntimeHandoff; } | { op: 'abort'; target: 'compute' | 'metal'; attemptId: string; currentVersion: string; targetVersion: string; }; export type AgentUpdateResponse = { ok: true; status: 'prepared' | 'active' | 'aborted'; version: string; attemptId: string; } | { ok: false; error: { code: string; message: string; }; }; export type AgentUpdateOutcome = 'activating' | 'active' | 'rolled-back' | 'failed'; /** Bounded, non-secret update evidence included in the next signed heartbeat. */ export interface AgentUpdateReceipt { attemptId: string; fromVersion: string; targetVersion: string; outcome: AgentUpdateOutcome; startedAtTs: number; updatedAtTs: number; retryAfterTs?: number; rollbackHealthy?: boolean; reason?: { code: string; message: string; }; } /** Read only the bounded evidence safe to send to the control plane. */ export declare function readAgentUpdateReceipt(path?: string): AgentUpdateReceipt | undefined; /** Prove a newly started Agent process answers, not merely that PID 1 holds its socket. */ export declare function probeAgentSocket(socketPath?: string, timeoutMs?: number): Promise; export declare function activateAgentRelease(staged: StagedAgentRelease, options?: { target?: AgentUpdateRequest['target']; run?: (input: UpdateCommand) => Promise; probe?: () => Promise; receiptPath?: string; journalPath?: string; attemptId?: string; now?: () => number; candidatePrepared?: boolean; publicSocketPath?: string; }): Promise<{ ok: true; version: string; } | { ok: false; rolledBack: boolean; rollbackHealthy: boolean; reason: string; }>; /** Restore a transaction that lost power or the helper before its health verdict became durable. */ export declare function recoverInterruptedAgentUpdate(options?: { root?: string; receiptPath?: string; journalPath?: string; run?: (input: UpdateCommand) => Promise; probe?: () => Promise; now?: () => number; publicSocketPath?: string; }): Promise; export declare function startAgentUpdateHelper(options?: { socketPath?: string; root?: string; activate?: (staged: StagedAgentRelease, target: AgentUpdateRequest['target'], attemptId: string) => Promise; receiptPath?: string; journalPath?: string; recover?: () => Promise; now?: () => number; setTimer?: (callback: () => void, ms: number) => unknown; }): Server; export declare function requestAgentUpdate(request: AgentUpdateRequest, socketPath?: string, timeoutMs?: number): Promise;