import { z } from 'zod'; declare const AwsResourcesSchema: z.ZodObject<{ instance_id: z.ZodString; security_group_id: z.ZodString; key_pair_name: z.ZodString; eip_allocation_id: z.ZodString; region: z.ZodString; }, "strip", z.ZodTypeAny, { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }, { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }>; declare const GcpResourcesSchema: z.ZodObject<{ instance_name: z.ZodString; static_ip_name: z.ZodString; firewall_rule_names: z.ZodArray; project_id: z.ZodString; zone: z.ZodString; }, "strip", z.ZodTypeAny, { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }, { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }>; declare const DeploymentSchema: z.ZodDiscriminatedUnion<"cloud", [z.ZodObject<{ project_path: z.ZodString; region: z.ZodString; created_at: z.ZodString; last_deployed_at: z.ZodString; last_config_hash: z.ZodString; /** * Hash of the nix-relevant files only (config_file, secrets_file, * nix_extra, documents) — excludes hermes.toml so that changes to * network-only fields do NOT trigger a nixos-rebuild. Populated after * every successful nixos-rebuild; defaults to "sha256:unknown" on * migration (forces a rebuild on the first update after upgrade, which * is safe). */ last_nix_hash: z.ZodDefault; ssh_key_path: z.ZodString; age_key_path: z.ZodString; health: z.ZodEnum<["healthy", "unhealthy", "unknown"]>; instance_ip: z.ZodString; hermes_agent_rev: z.ZodDefault; hermes_agent_tag: z.ZodDefault; domain_name: z.ZodOptional; dns_record_id: z.ZodOptional; profile_hashes: z.ZodOptional>; } & { cloud: z.ZodLiteral<"aws">; cloud_resources: z.ZodObject<{ instance_id: z.ZodString; security_group_id: z.ZodString; key_pair_name: z.ZodString; eip_allocation_id: z.ZodString; region: z.ZodString; }, "strip", z.ZodTypeAny, { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }, { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }>; }, "strip", z.ZodTypeAny, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; last_nix_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; hermes_agent_rev: string; hermes_agent_tag: string; cloud: "aws"; cloud_resources: { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; cloud: "aws"; cloud_resources: { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }; last_nix_hash?: string | undefined; hermes_agent_rev?: string | undefined; hermes_agent_tag?: string | undefined; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }>, z.ZodObject<{ project_path: z.ZodString; region: z.ZodString; created_at: z.ZodString; last_deployed_at: z.ZodString; last_config_hash: z.ZodString; /** * Hash of the nix-relevant files only (config_file, secrets_file, * nix_extra, documents) — excludes hermes.toml so that changes to * network-only fields do NOT trigger a nixos-rebuild. Populated after * every successful nixos-rebuild; defaults to "sha256:unknown" on * migration (forces a rebuild on the first update after upgrade, which * is safe). */ last_nix_hash: z.ZodDefault; ssh_key_path: z.ZodString; age_key_path: z.ZodString; health: z.ZodEnum<["healthy", "unhealthy", "unknown"]>; instance_ip: z.ZodString; hermes_agent_rev: z.ZodDefault; hermes_agent_tag: z.ZodDefault; domain_name: z.ZodOptional; dns_record_id: z.ZodOptional; profile_hashes: z.ZodOptional>; } & { cloud: z.ZodLiteral<"gcp">; cloud_resources: z.ZodObject<{ instance_name: z.ZodString; static_ip_name: z.ZodString; firewall_rule_names: z.ZodArray; project_id: z.ZodString; zone: z.ZodString; }, "strip", z.ZodTypeAny, { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }, { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }>; }, "strip", z.ZodTypeAny, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; last_nix_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; hermes_agent_rev: string; hermes_agent_tag: string; cloud: "gcp"; cloud_resources: { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; cloud: "gcp"; cloud_resources: { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }; last_nix_hash?: string | undefined; hermes_agent_rev?: string | undefined; hermes_agent_tag?: string | undefined; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }>]>; declare const StateTomlSchema: z.ZodObject<{ schema_version: z.ZodLiteral<4>; deployments: z.ZodRecord; ssh_key_path: z.ZodString; age_key_path: z.ZodString; health: z.ZodEnum<["healthy", "unhealthy", "unknown"]>; instance_ip: z.ZodString; hermes_agent_rev: z.ZodDefault; hermes_agent_tag: z.ZodDefault; domain_name: z.ZodOptional; dns_record_id: z.ZodOptional; profile_hashes: z.ZodOptional>; } & { cloud: z.ZodLiteral<"aws">; cloud_resources: z.ZodObject<{ instance_id: z.ZodString; security_group_id: z.ZodString; key_pair_name: z.ZodString; eip_allocation_id: z.ZodString; region: z.ZodString; }, "strip", z.ZodTypeAny, { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }, { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }>; }, "strip", z.ZodTypeAny, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; last_nix_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; hermes_agent_rev: string; hermes_agent_tag: string; cloud: "aws"; cloud_resources: { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; cloud: "aws"; cloud_resources: { instance_id: string; security_group_id: string; key_pair_name: string; eip_allocation_id: string; region: string; }; last_nix_hash?: string | undefined; hermes_agent_rev?: string | undefined; hermes_agent_tag?: string | undefined; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }>, z.ZodObject<{ project_path: z.ZodString; region: z.ZodString; created_at: z.ZodString; last_deployed_at: z.ZodString; last_config_hash: z.ZodString; /** * Hash of the nix-relevant files only (config_file, secrets_file, * nix_extra, documents) — excludes hermes.toml so that changes to * network-only fields do NOT trigger a nixos-rebuild. Populated after * every successful nixos-rebuild; defaults to "sha256:unknown" on * migration (forces a rebuild on the first update after upgrade, which * is safe). */ last_nix_hash: z.ZodDefault; ssh_key_path: z.ZodString; age_key_path: z.ZodString; health: z.ZodEnum<["healthy", "unhealthy", "unknown"]>; instance_ip: z.ZodString; hermes_agent_rev: z.ZodDefault; hermes_agent_tag: z.ZodDefault; domain_name: z.ZodOptional; dns_record_id: z.ZodOptional; profile_hashes: z.ZodOptional>; } & { cloud: z.ZodLiteral<"gcp">; cloud_resources: z.ZodObject<{ instance_name: z.ZodString; static_ip_name: z.ZodString; firewall_rule_names: z.ZodArray; project_id: z.ZodString; zone: z.ZodString; }, "strip", z.ZodTypeAny, { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }, { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }>; }, "strip", z.ZodTypeAny, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; last_nix_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; hermes_agent_rev: string; hermes_agent_tag: string; cloud: "gcp"; cloud_resources: { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }, { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; cloud: "gcp"; cloud_resources: { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }; last_nix_hash?: string | undefined; hermes_agent_rev?: string | undefined; hermes_agent_tag?: string | undefined; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }>]>>; }, "strip", z.ZodTypeAny, { schema_version: 4; deployments: Record | undefined; } | { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; last_nix_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; hermes_agent_rev: string; hermes_agent_tag: string; cloud: "gcp"; cloud_resources: { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }>; }, { schema_version: 4; deployments: Record | undefined; } | { region: string; project_path: string; created_at: string; last_deployed_at: string; last_config_hash: string; ssh_key_path: string; age_key_path: string; health: "healthy" | "unhealthy" | "unknown"; instance_ip: string; cloud: "gcp"; cloud_resources: { instance_name: string; static_ip_name: string; firewall_rule_names: string[]; project_id: string; zone: string; }; last_nix_hash?: string | undefined; hermes_agent_rev?: string | undefined; hermes_agent_tag?: string | undefined; domain_name?: string | undefined; dns_record_id?: string | undefined; profile_hashes?: Record | undefined; }>; }>; type StateToml = z.infer; type Deployment = z.infer; type AwsResources = z.infer; type GcpResources = z.infer; type Size = 'small' | 'medium' | 'large'; interface Location { region: string; zone?: string; } interface ImageRef { id: string; description: string; } interface NetworkRules { sshAllowedFrom: string; inboundPorts: number[]; /** When true, ports 80 and 443 are automatically added for nginx/ACME. */ hasDomain?: boolean; } interface ProvisionSpec { deploymentName: string; location: Location; size: Size; diskGb: number; image: ImageRef; publicSshKey: string; networkRules: NetworkRules; } interface Instance { publicIp: string; sshUser: string; } type ResourceLedger = { kind: 'aws'; resources: Partial; } | { kind: 'gcp'; resources: Partial; }; interface InstanceStatus { state: 'pending' | 'running' | 'shutting-down' | 'stopping' | 'stopped' | 'terminated' | 'unknown'; publicIp: string | null; } /** * Result of a successful adoption: the reconstructed ResourceLedger * (ready to persist into state.toml) plus the currently-reachable public * IP (if any), which the orchestrator needs to write `instance_ip` into * state alongside the ledger. */ interface AdoptResult$1 { ledger: ResourceLedger; publicIp: string | null; } interface DnsRecord { zoneId: string; fqdn: string; } interface CloudProvider { readonly name: 'aws' | 'gcp'; resolveNixosImage(loc: Location): Promise; provision(spec: ProvisionSpec, ledger: ResourceLedger): Promise; /** * Apply network rule changes in place, without recreating the instance. * Adds rules that aren't currently on the SG/firewall, removes rules that * are no longer required. Idempotent — safe to call when the rules * already match. */ reconcileNetwork(ledger: ResourceLedger, rules: NetworkRules): Promise; destroy(ledger: ResourceLedger): Promise; status(ledger: ResourceLedger): Promise; /** * Reconstruct a ResourceLedger for a deployment whose state entry was * lost (e.g. the user moved to a new machine, or ~/.config/hermes-deploy * was wiped). Looks up cloud resources by their provision-time tag * markers (`managed-by=hermes-deploy` + `hermes-deploy/deployment=` * on AWS; equivalent labels on GCP). Returns the rebuilt ledger and the * current public IP. * * Throws if no resources carrying the expected markers are found — the * caller should present a clear "no deployment named X found in this * cloud/region" error. The tag check is the safety rail: this method * must NEVER adopt resources that don't carry the hermes-deploy * provenance markers. */ adopt(deploymentName: string): Promise; /** * Create or update a DNS A record pointing fqdn → ip. * Returns an identifier that can be used for deletion. */ upsertDnsRecord?(fqdn: string, ip: string): Promise; /** * Delete a DNS A record previously created by upsertDnsRecord. */ deleteDnsRecord?(record: DnsRecord, ip: string): Promise; } declare const SIZE_MAP_AWS: Record; declare const SIZE_MAP_GCP: Record; interface CreateProviderOptions { provider: 'aws' | 'gcp'; region: string; zone?: string; profile?: string; imageCacheFile: string; } declare function createCloudProvider(opts: CreateProviderOptions): CloudProvider; interface AwsProviderOptions { region: string; profile?: string; imageCacheFile: string; } declare class AwsProvider implements CloudProvider { private readonly opts; readonly name: "aws"; private readonly ec2; private readonly r53; constructor(opts: AwsProviderOptions); resolveNixosImage(_loc: Location): Promise; provision(spec: ProvisionSpec, ledger: ResourceLedger): Promise; reconcileNetwork(ledger: ResourceLedger, rules: NetworkRules): Promise; destroy(ledger: ResourceLedger): Promise; status(ledger: ResourceLedger): Promise; adopt(deploymentName: string): Promise; upsertDnsRecord(fqdn: string, ip: string): Promise; deleteDnsRecord(record: DnsRecord, ip: string): Promise; } interface GcpProviderOptions { zone: string; project?: string; imageCacheFile: string; } declare class GcpProvider implements CloudProvider { private readonly opts; readonly name: "gcp"; private resolvedProject; constructor(opts: GcpProviderOptions); private getProject; resolveNixosImage(_loc: Location): Promise; provision(spec: ProvisionSpec, ledger: ResourceLedger): Promise; reconcileNetwork(ledger: ResourceLedger, rules: NetworkRules): Promise; destroy(ledger: ResourceLedger): Promise; status(ledger: ResourceLedger): Promise; adopt(deploymentName: string): Promise; upsertDnsRecord(fqdn: string, ip: string): Promise; deleteDnsRecord(record: DnsRecord, _ip: string): Promise; } declare const HermesTomlSchema: z.ZodObject<{ name: z.ZodString; cloud: z.ZodEffects; profile: z.ZodString; region: z.ZodString; zone: z.ZodOptional; size: z.ZodEnum<["small", "medium", "large"]>; disk_gb: z.ZodDefault; image: z.ZodOptional; }, "strip", z.ZodTypeAny, { region: string; profile: string; provider: "aws" | "gcp"; size: "small" | "medium" | "large"; disk_gb: number; zone?: string | undefined; image?: string | undefined; }, { region: string; profile: string; provider: "aws" | "gcp"; size: "small" | "medium" | "large"; zone?: string | undefined; disk_gb?: number | undefined; image?: string | undefined; }>, { region: string; profile: string; provider: "aws" | "gcp"; size: "small" | "medium" | "large"; disk_gb: number; zone?: string | undefined; image?: string | undefined; }, { region: string; profile: string; provider: "aws" | "gcp"; size: "small" | "medium" | "large"; zone?: string | undefined; disk_gb?: number | undefined; image?: string | undefined; }>; network: z.ZodDefault; inbound_ports: z.ZodDefault>; }, "strip", z.ZodTypeAny, { ssh_allowed_from: string; inbound_ports: number[]; }, { ssh_allowed_from?: string | undefined; inbound_ports?: number[] | undefined; }>>; hermes: z.ZodEffects; documents: z.ZodDefault, z.ZodString>>; environment: z.ZodDefault>; cachix: z.ZodOptional>; profiles: z.ZodDefault; config_file: z.ZodString; secrets_file: z.ZodString; documents: z.ZodDefault, z.ZodString>>; }, "strip", z.ZodTypeAny, { name: string; config_file: string; secrets_file: string; documents: Record; }, { name: string; config_file: string; secrets_file: string; documents?: Record | undefined; }>, "many">>; cron: z.ZodOptional; skills: z.ZodDefault>; deliver: z.ZodOptional; enabled: z.ZodDefault; repeat: z.ZodOptional; script: z.ZodOptional; workdir: z.ZodOptional; }, "strip", z.ZodTypeAny, { name: string; schedule: string; skills: string[]; enabled: boolean; repeat?: number | undefined; prompt?: string | undefined; deliver?: string | undefined; script?: string | undefined; workdir?: string | undefined; }, { name: string; schedule: string; repeat?: number | undefined; prompt?: string | undefined; skills?: string[] | undefined; deliver?: string | undefined; enabled?: boolean | undefined; script?: string | undefined; workdir?: string | undefined; }>, "many">>; watchdog: z.ZodOptional; interval_min: z.ZodDefault; window_min: z.ZodDefault; cooldown_min: z.ZodDefault; }, "strip", z.ZodTypeAny, { enabled: boolean; interval_min: number; window_min: number; cooldown_min: number; }, { enabled?: boolean | undefined; interval_min?: number | undefined; window_min?: number | undefined; cooldown_min?: number | undefined; }>, { enabled: boolean; interval_min: number; window_min: number; cooldown_min: number; }, { enabled?: boolean | undefined; interval_min?: number | undefined; window_min?: number | undefined; cooldown_min?: number | undefined; }>>; }, "strip", z.ZodTypeAny, { config_file: string; secrets_file: string; documents: Record; environment: Record; profiles: { name: string; config_file: string; secrets_file: string; documents: Record; }[]; nix_extra?: string | undefined; cachix?: { name: string; public_key: string; } | undefined; cron?: { name: string; schedule: string; skills: string[]; enabled: boolean; repeat?: number | undefined; prompt?: string | undefined; deliver?: string | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled: boolean; interval_min: number; window_min: number; cooldown_min: number; } | undefined; }, { config_file: string; secrets_file: string; documents?: Record | undefined; nix_extra?: string | undefined; environment?: Record | undefined; cachix?: { name: string; public_key: string; } | undefined; profiles?: { name: string; config_file: string; secrets_file: string; documents?: Record | undefined; }[] | undefined; cron?: { name: string; schedule: string; repeat?: number | undefined; prompt?: string | undefined; skills?: string[] | undefined; deliver?: string | undefined; enabled?: boolean | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled?: boolean | undefined; interval_min?: number | undefined; window_min?: number | undefined; cooldown_min?: number | undefined; } | undefined; }>, { config_file: string; secrets_file: string; documents: Record; environment: Record; profiles: { name: string; config_file: string; secrets_file: string; documents: Record; }[]; nix_extra?: string | undefined; cachix?: { name: string; public_key: string; } | undefined; cron?: { name: string; schedule: string; skills: string[]; enabled: boolean; repeat?: number | undefined; prompt?: string | undefined; deliver?: string | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled: boolean; interval_min: number; window_min: number; cooldown_min: number; } | undefined; }, { config_file: string; secrets_file: string; documents?: Record | undefined; nix_extra?: string | undefined; environment?: Record | undefined; cachix?: { name: string; public_key: string; } | undefined; profiles?: { name: string; config_file: string; secrets_file: string; documents?: Record | undefined; }[] | undefined; cron?: { name: string; schedule: string; repeat?: number | undefined; prompt?: string | undefined; skills?: string[] | undefined; deliver?: string | undefined; enabled?: boolean | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled?: boolean | undefined; interval_min?: number | undefined; window_min?: number | undefined; cooldown_min?: number | undefined; } | undefined; }>, { config_file: string; secrets_file: string; documents: Record; environment: Record; profiles: { name: string; config_file: string; secrets_file: string; documents: Record; }[]; nix_extra?: string | undefined; cachix?: { name: string; public_key: string; } | undefined; cron?: { name: string; schedule: string; skills: string[]; enabled: boolean; repeat?: number | undefined; prompt?: string | undefined; deliver?: string | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled: boolean; interval_min: number; window_min: number; cooldown_min: number; } | undefined; }, { config_file: string; secrets_file: string; documents?: Record | undefined; nix_extra?: string | undefined; environment?: Record | undefined; cachix?: { name: string; public_key: string; } | undefined; profiles?: { name: string; config_file: string; secrets_file: string; documents?: Record | undefined; }[] | undefined; cron?: { name: string; schedule: string; repeat?: number | undefined; prompt?: string | undefined; skills?: string[] | undefined; deliver?: string | undefined; enabled?: boolean | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled?: boolean | undefined; interval_min?: number | undefined; window_min?: number | undefined; cooldown_min?: number | undefined; } | undefined; }>; domain: z.ZodOptional; }, "strip", z.ZodTypeAny, { name: string; upstream_port: number; }, { name: string; upstream_port: number; }>>; }, "strip", z.ZodTypeAny, { cloud: { region: string; profile: string; provider: "aws" | "gcp"; size: "small" | "medium" | "large"; disk_gb: number; zone?: string | undefined; image?: string | undefined; }; name: string; network: { ssh_allowed_from: string; inbound_ports: number[]; }; hermes: { config_file: string; secrets_file: string; documents: Record; environment: Record; profiles: { name: string; config_file: string; secrets_file: string; documents: Record; }[]; nix_extra?: string | undefined; cachix?: { name: string; public_key: string; } | undefined; cron?: { name: string; schedule: string; skills: string[]; enabled: boolean; repeat?: number | undefined; prompt?: string | undefined; deliver?: string | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled: boolean; interval_min: number; window_min: number; cooldown_min: number; } | undefined; }; domain?: { name: string; upstream_port: number; } | undefined; }, { cloud: { region: string; profile: string; provider: "aws" | "gcp"; size: "small" | "medium" | "large"; zone?: string | undefined; disk_gb?: number | undefined; image?: string | undefined; }; name: string; hermes: { config_file: string; secrets_file: string; documents?: Record | undefined; nix_extra?: string | undefined; environment?: Record | undefined; cachix?: { name: string; public_key: string; } | undefined; profiles?: { name: string; config_file: string; secrets_file: string; documents?: Record | undefined; }[] | undefined; cron?: { name: string; schedule: string; repeat?: number | undefined; prompt?: string | undefined; skills?: string[] | undefined; deliver?: string | undefined; enabled?: boolean | undefined; script?: string | undefined; workdir?: string | undefined; }[] | undefined; watchdog?: { enabled?: boolean | undefined; interval_min?: number | undefined; window_min?: number | undefined; cooldown_min?: number | undefined; } | undefined; }; network?: { ssh_allowed_from?: string | undefined; inbound_ports?: number[] | undefined; } | undefined; domain?: { name: string; upstream_port: number; } | undefined; }>; type HermesTomlConfig = z.infer; declare function loadHermesToml(path: string): HermesTomlConfig; interface StorePaths { configDir: string; stateFile: string; lockFile: string; } declare class StateStore { private readonly paths; constructor(paths: StorePaths); read(): Promise; update(mutator: (state: StateToml) => void | Promise): Promise; private ensureConfigDir; private backup; private pruneOldBackups; } interface StatePaths { configDir: string; stateFile: string; lockFile: string; sshKeysDir: string; ageKeysDir: string; imageCacheFile: string; sshKeyForDeployment(name: string): string; ageKeyForDeployment(name: string): string; } declare function getStatePaths(): StatePaths; declare const CURRENT_SCHEMA_VERSION = 4; /** * Run forward migrations until the input reaches CURRENT_SCHEMA_VERSION. * Throws if the input claims a version newer than the CLI knows about * (means the user is running an older binary against state written by a * newer one — they should upgrade the CLI before continuing). */ declare function runMigrations(input: unknown): unknown; interface ExecResult { exitCode: number | null; stdout: string; stderr: string; } interface ExecStreamUntilResult { aborted: boolean; exitCode: number | null; } interface ShellHandle { write(data: string | Buffer): void; resize(cols: number, rows: number): void; onData(cb: (data: Buffer) => void): void; onClose(cb: () => void): void; close(): void; } interface SshSession { exec(command: string): Promise; execStream(command: string, onLine: (stream: 'stdout' | 'stderr', line: string) => void): Promise; /** * Like execStream, but runs until either the remote command exits OR * the provided AbortSignal fires. On abort, the remote stream is * signaled with TERM and ended; the returned promise resolves with * `{aborted: true}`. Used for indefinite-duration commands like * `journalctl -f` where the user terminates with Ctrl-C. */ execStreamUntil(command: string, signal: AbortSignal, onLine: (stream: 'stdout' | 'stderr', line: string) => void): Promise; uploadFile(remotePath: string, contents: Buffer | string, mode?: number): Promise; /** * Open an interactive PTY shell on the remote host. Used by the * dashboard's SSH tab to provide xterm.js-backed terminal access. * Optional — not required by the CLI flow, only by the web server. */ shell?(opts?: { term?: string; cols?: number; rows?: number; }): Promise; dispose(): Promise; } type PhaseId = 'validate' | 'ensure-keys' | 'provision' | 'dns' | 'wait-ssh' | 'bootstrap' | 'flake-update' | 'healthcheck' | 'cron'; interface Reporter { phaseStart(id: PhaseId, label: string): void; phaseDone(id: PhaseId): void; phaseFail(id: PhaseId, error: string): void; log(line: string): void; success(summary: string): void; } declare function createPlainReporter(): Reporter; interface DeployOptions { projectDir: string; provider: CloudProvider; sessionFactory: (host: string, privateKey: string) => Promise; detectPublicIp: () => Promise; sshKeyGenerator: (path: string) => Promise<{ publicKey: string; privateKeyPath: string; publicKeyPath: string; }>; ageKeyGenerator: (path: string) => Promise<{ publicKey: string; privateKeyPath: string; }>; sopsBootstrap: (projectDir: string, agePublicKey: string) => Promise; waitSsh: (host: string) => Promise; healthcheckTimeoutMs?: number; reporter?: Reporter; } interface DeployResult { health: 'healthy' | 'unhealthy'; publicIp: string; } declare function runDeploy(opts: DeployOptions): Promise; interface UpdateOptions { deploymentName: string; provider: CloudProvider; sessionFactory: (host: string, privateKey: string) => Promise; detectPublicIp: () => Promise; healthcheckTimeoutMs?: number; reporter?: Reporter; } interface UpdateResult { health: 'healthy' | 'unhealthy'; publicIp: string; /** True when the config hash matched and we short-circuited (no SSH, no rebuild). */ skipped: boolean; } /** * The update flow: re-evaluate the project's hermes.toml + secrets, * compare to the recorded config hash, and either short-circuit (no * changes) or push the new config to the existing instance via: * * 1. Validate (load toml, check SOUL exists) * 2. Hash + compare → skip if unchanged * 3. Reconcile network rules in place (no instance recreation) * 4. SSH in, upload + nixos-rebuild via shared helper * 5. Healthcheck + state update via shared helper * * Unlike `runDeploy`, this never calls provider.provision and never * regenerates SSH or age keys. The instance, security group, key pair, * and elastic IP all stay put. Typical update time on a healthy box: * 30-90 seconds (most of which is the rebuild evaluating the flake * against the warm /nix/store). */ declare function runUpdate(opts: UpdateOptions): Promise; interface DestroyOptions { deploymentName: string; provider: CloudProvider; reporter?: Reporter; } declare function runDestroy(opts: DestroyOptions): Promise; declare class HermesDeployError extends Error { readonly cause?: unknown | undefined; constructor(message: string, cause?: unknown | undefined); } declare class CloudProvisionError extends HermesDeployError { constructor(message: string, cause?: unknown); } declare class CloudQuotaError extends CloudProvisionError { constructor(message: string, cause?: unknown); } declare class SshBootstrapError extends HermesDeployError { readonly publicIp: string; constructor(message: string, publicIp: string, cause?: unknown); } declare class NixosRebuildError extends HermesDeployError { readonly logTail: string[]; constructor(message: string, logTail: string[], cause?: unknown); } declare class HealthcheckTimeoutError extends HermesDeployError { readonly journalTail: string[]; constructor(message: string, journalTail: string[]); } interface AdoptOptions { /** * Explicit deployment name. Required: unlike other commands, adopt * has nothing to walk up to because the state entry is missing by * construction. */ name?: string; /** * Project directory — either passed via --project or walked up from * cwd. Must contain a valid hermes.toml, since we read cloud/region/ * zone from there (the state we're rebuilding doesn't exist yet). */ projectPath?: string; /** * If false (default), the command refuses to overwrite an existing * state entry. Set via `--force` when the user really does want to * replace a corrupted record. */ force?: boolean; /** * Skip writing to state.toml. Used by `--dry-run` to preview the * ledger without persisting anything. */ dryRun?: boolean; } interface AdoptResult { name: string; cloud: 'aws' | 'gcp'; region: string; publicIp: string | null; /** * The reconstructed deployment record that was (or would be) written * to state.toml. Exposed so the CLI can render a preview and so * library consumers can make decisions from the rebuilt ledger * without re-reading state. */ deployment: Deployment; /** True when the state file was actually written. */ persisted: boolean; } /** * Rebuild a state.toml entry for a deployment whose record was lost by * searching the configured cloud for resources tagged with the * hermes-deploy provenance markers. This is the "I reinstalled my * laptop" recovery path. * * Flow: * 1. Resolve the project directory (explicit --project, or walk up * from cwd looking for hermes.toml) and load hermes.toml. We need * `cloud.provider`, `cloud.region`, `cloud.zone`, and * `cloud.profile` to construct the right CloudProvider. * 2. Construct the CloudProvider and call `provider.adopt(name)`. * That call uses tag/label filters to find the resources and * rebuild a ResourceLedger. The safety rail is inside the provider: * adoption ONLY returns resources carrying * `managed-by=hermes-deploy` + `hermes-deploy/deployment=`. * 3. Check that the per-deployment SSH key and age key still exist * locally (keys live in ~/.config/hermes-deploy/, outside the * state file). If the SSH key is missing, future updates will * fail — warn loudly but don't refuse to adopt. If the age key * is missing, secret operations will fail — same treatment. * 4. Write the reconstructed entry to state.toml unless --dry-run. * The existing state entry (if any) is preserved unless --force. */ declare function adoptDeployment(opts: AdoptOptions): Promise; export { type AdoptOptions, type AdoptResult, AwsProvider, type AwsProviderOptions, type AwsResources, CURRENT_SCHEMA_VERSION, type CloudProvider, CloudProvisionError, CloudQuotaError, type CreateProviderOptions, type DeployOptions, type DeployResult, type Deployment, type DestroyOptions, GcpProvider, type GcpProviderOptions, type GcpResources, HealthcheckTimeoutError, HermesDeployError, type ImageRef, type Instance, type InstanceStatus, type Location, type NetworkRules, NixosRebuildError, type ProvisionSpec, type Reporter, type ResourceLedger, SIZE_MAP_AWS, SIZE_MAP_GCP, type Size, SshBootstrapError, type StatePaths, StateStore, type StateToml, StateTomlSchema, type UpdateOptions, type UpdateResult, adoptDeployment, createCloudProvider, createPlainReporter, getStatePaths, loadHermesToml, runDeploy, runDestroy, runMigrations, runUpdate };