diff --git a/packages/cli/src/__tests__/docker-cloudinit-skip.test.ts b/packages/cli/src/__tests__/docker-cloudinit-skip.test.ts new file mode 100644 index 000000000..36b9fb250 --- /dev/null +++ b/packages/cli/src/__tests__/docker-cloudinit-skip.test.ts @@ -0,0 +1,30 @@ +/** + * docker-cloudinit-skip.test.ts — Verify Docker mode skips cloud-init wait. + * + * When --beta docker is active, waitForReady() must skip cloud-init polling + * and only wait for SSH. This test reads the orchestrator source files to + * verify the useDocker check is present in the waitForReady condition. + * + * Without this, non-minimal agents (openclaw, codex) wait 5 minutes for a + * cloud-init marker that never appears when using Docker app images. + */ + +import { describe, expect, it } from "bun:test"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; + +const CLI_SRC = resolve(import.meta.dir, ".."); + +describe("Docker mode skips cloud-init wait", () => { + it("Hetzner waitForReady includes useDocker in skip condition", () => { + const source = readFileSync(resolve(CLI_SRC, "hetzner/main.ts"), "utf-8"); + // The waitForReady condition must include useDocker to skip cloud-init + // when Docker mode is active (matching GCP's implementation) + expect(source).toContain("useDocker || snapshotId || cloud.skipCloudInit"); + }); + + it("GCP waitForReady includes useDocker in skip condition", () => { + const source = readFileSync(resolve(CLI_SRC, "gcp/main.ts"), "utf-8"); + expect(source).toContain("useDocker || cloud.skipCloudInit"); + }); +}); diff --git a/packages/cli/src/hetzner/main.ts b/packages/cli/src/hetzner/main.ts index d65f5f78a..d0fb96b24 100644 --- a/packages/cli/src/hetzner/main.ts +++ b/packages/cli/src/hetzner/main.ts @@ -87,7 +87,7 @@ async function main() { }, getServerName, async waitForReady() { - if (snapshotId || cloud.skipCloudInit) { + if (useDocker || snapshotId || cloud.skipCloudInit) { await waitForSshOnly(); } else { await waitForCloudInit();