diff --git a/packages/cli/src/digitalocean/digitalocean.ts b/packages/cli/src/digitalocean/digitalocean.ts index 63074a96..07bce3a2 100644 --- a/packages/cli/src/digitalocean/digitalocean.ts +++ b/packages/cli/src/digitalocean/digitalocean.ts @@ -28,6 +28,7 @@ import { waitForSsh as sharedWaitForSsh, sleep, spawnInteractive, + waitForSshSnapshotBoot, } from "../shared/ssh"; import { ensureSshKeys, getSshFingerprint, getSshKeyOpts } from "../shared/ssh-keys"; import { @@ -1196,16 +1197,8 @@ export async function findSpawnSnapshot(agentName: string): Promise { - const serverIp = ip || _state.serverIp; - const selectedKeys = await ensureSshKeys(); - const keyOpts = getSshKeyOpts(selectedKeys); - await sharedWaitForSsh({ - host: serverIp, - user: "root", - maxAttempts: 36, - extraSshOpts: keyOpts, - }); - logInfo("SSH available (snapshot boot — skipping cloud-init)"); + const keyOpts = getSshKeyOpts(await ensureSshKeys()); + await waitForSshSnapshotBoot(ip ?? _state.serverIp, keyOpts); } // ─── SSH Execution ─────────────────────────────────────────────────────────── diff --git a/packages/cli/src/hetzner/hetzner.ts b/packages/cli/src/hetzner/hetzner.ts index c5b41b62..83803a52 100644 --- a/packages/cli/src/hetzner/hetzner.ts +++ b/packages/cli/src/hetzner/hetzner.ts @@ -18,6 +18,7 @@ import { waitForSsh as sharedWaitForSsh, sleep, spawnInteractive, + waitForSshSnapshotBoot, } from "../shared/ssh"; import { ensureSshKeys, getSshFingerprint, getSshKeyOpts } from "../shared/ssh-keys"; import { @@ -505,16 +506,8 @@ export async function findSpawnSnapshot(agentName: string): Promise { - const serverIp = ip || _state.serverIp; - const selectedKeys = await ensureSshKeys(); - const keyOpts = getSshKeyOpts(selectedKeys); - await sharedWaitForSsh({ - host: serverIp, - user: "root", - maxAttempts: 36, - extraSshOpts: keyOpts, - }); - logInfo("SSH available (snapshot boot — skipping cloud-init)"); + const keyOpts = getSshKeyOpts(await ensureSshKeys()); + await waitForSshSnapshotBoot(ip ?? _state.serverIp, keyOpts); } // ─── Provisioning ──────────────────────────────────────────────────────────── diff --git a/packages/cli/src/shared/ssh.ts b/packages/cli/src/shared/ssh.ts index 26e639e1..31600ffe 100644 --- a/packages/cli/src/shared/ssh.ts +++ b/packages/cli/src/shared/ssh.ts @@ -362,3 +362,17 @@ export async function waitForSsh(opts: WaitForSshOpts): Promise { logError(`SSH handshake failed after ${handshakeAttempts} attempts`); throw new Error("SSH connectivity timeout — handshake never succeeded"); } + +/** + * Wait for SSH availability on a snapshot-booted VM (no cloud-init needed). + * Used by cloud modules that support snapshot-based provisioning (Hetzner, DigitalOcean). + */ +export async function waitForSshSnapshotBoot(ip: string, extraSshOpts: string[]): Promise { + await waitForSsh({ + host: ip, + user: "root", + maxAttempts: 36, + extraSshOpts, + }); + logInfo("SSH available (snapshot boot — skipping cloud-init)"); +}