From 781f8e0b834ce864eac8be728c55f474d71c76a1 Mon Sep 17 00:00:00 2001 From: Ahmed Abushagur Date: Wed, 29 Apr 2026 16:27:34 -0700 Subject: [PATCH 1/3] fix(local): use get.docker.com convenience script instead of apt-get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Linux branch of ensureDocker() assumed apt — fine on Debian/Ubuntu, broken on Fedora/Arch/Alpine/openSUSE. Switch to Docker's official convenience script, which handles distro detection, repo setup, and service enablement in one call. Bumps CLI 1.0.27 -> 1.0.28. --- packages/cli/package.json | 2 +- packages/cli/src/local/local.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 8b2c002aa..a9b9e0fbc 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openrouter/spawn", - "version": "1.0.27", + "version": "1.0.28", "type": "module", "bin": { "spawn": "cli.js" diff --git a/packages/cli/src/local/local.ts b/packages/cli/src/local/local.ts index 4183bff53..c81a50671 100644 --- a/packages/cli/src/local/local.ts +++ b/packages/cli/src/local/local.ts @@ -460,7 +460,7 @@ export async function ensureDocker(): Promise { process.exit(1); } } else { - logStep("Docker not found — installing docker.io..."); + logStep("Docker not found — installing via get.docker.com..."); const hasSudo = Bun.spawnSync( [ @@ -475,12 +475,12 @@ export async function ensureDocker(): Promise { ], }, ).exitCode === 0; - const prefix = hasSudo ? "sudo " : ""; + const shellCmd = hasSudo ? "sudo sh" : "sh"; const result = Bun.spawnSync( [ "bash", "-c", - `${prefix}apt-get update -qq && ${prefix}apt-get install -y -qq docker.io`, + `curl -fsSL https://get.docker.com | ${shellCmd}`, ], { stdio: [ @@ -491,7 +491,7 @@ export async function ensureDocker(): Promise { }, ); if (result.exitCode !== 0) { - logInfo("Auto-install failed. Install Docker manually: sudo apt-get install docker.io"); + logInfo("Auto-install failed. Install Docker manually: https://docs.docker.com/engine/install/"); process.exit(1); } } From 5c9e30801db070bc63e1e8a2ecdf9093c641c3bf Mon Sep 17 00:00:00 2001 From: Ahmed Abushagur Date: Wed, 29 Apr 2026 17:53:34 -0700 Subject: [PATCH 2/3] fix(local): gate get.docker.com install behind PostHog flag Restores apt-get as the default Linux install path and gates the get.docker.com convenience script behind the `linux_docker_install` PostHog flag (variant "test"). This lets us measure whether the convenience script reduces install failures on non-apt distros (Fedora/Arch/Alpine) before flipping the default. Exposure event ($feature_flag_called) is captured automatically by getFeatureFlag(). --- packages/cli/src/local/local.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/local/local.ts b/packages/cli/src/local/local.ts index c81a50671..528b09c9c 100644 --- a/packages/cli/src/local/local.ts +++ b/packages/cli/src/local/local.ts @@ -4,6 +4,7 @@ import { copyFileSync, mkdirSync, mkdtempSync, rmSync, statSync } from "node:fs" import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { tryCatch } from "@openrouter/spawn-shared"; +import { getFeatureFlag } from "../shared/feature-flags.js"; import { DOCKER_CONTAINER_NAME, DOCKER_REGISTRY } from "../shared/orchestrate.js"; import { getUserHome } from "../shared/paths.js"; import { getLocalShell } from "../shared/shell.js"; @@ -460,7 +461,6 @@ export async function ensureDocker(): Promise { process.exit(1); } } else { - logStep("Docker not found — installing via get.docker.com..."); const hasSudo = Bun.spawnSync( [ @@ -475,12 +475,19 @@ export async function ensureDocker(): Promise { ], }, ).exitCode === 0; - const shellCmd = hasSudo ? "sudo sh" : "sh"; + // PostHog experiment: "test" variant uses Docker's official convenience + // script (distro-agnostic — covers Fedora/Arch/Alpine, not just apt). + const useConvenienceScript = getFeatureFlag("linux_docker_install", "control") === "test"; + const installLabel = useConvenienceScript ? "via get.docker.com" : "docker.io"; + logStep(`Docker not found — installing ${installLabel}...`); + const installCmd = useConvenienceScript + ? `curl -fsSL https://get.docker.com | ${hasSudo ? "sudo sh" : "sh"}` + : `${hasSudo ? "sudo " : ""}apt-get update -qq && ${hasSudo ? "sudo " : ""}apt-get install -y -qq docker.io`; const result = Bun.spawnSync( [ "bash", "-c", - `curl -fsSL https://get.docker.com | ${shellCmd}`, + installCmd, ], { stdio: [ @@ -491,7 +498,10 @@ export async function ensureDocker(): Promise { }, ); if (result.exitCode !== 0) { - logInfo("Auto-install failed. Install Docker manually: https://docs.docker.com/engine/install/"); + const manualHint = useConvenienceScript + ? "https://docs.docker.com/engine/install/" + : "sudo apt-get install docker.io"; + logInfo(`Auto-install failed. Install Docker manually: ${manualHint}`); process.exit(1); } } From fbde6b2156ec46e369ccd4f54422460b977bfd0a Mon Sep 17 00:00:00 2001 From: Ahmed Abushagur Date: Wed, 29 Apr 2026 18:00:02 -0700 Subject: [PATCH 3/3] fix(local): runtime apt detection + add docker to fast_provision experiment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - local.ts: prefer apt-get if `which apt-get` succeeds; otherwise fall back to Docker's convenience script. Drops the linux_docker_install PostHog flag in favor of a simple capability check. - index.ts: fast_provision test variant now pushes both "images" and "docker" — the experiment evaluates the full provisioning-speed bundle. --- packages/cli/src/index.ts | 4 ++-- packages/cli/src/local/local.ts | 32 +++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 0892969e7..8f09decbe 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -959,12 +959,12 @@ async function main(): Promise { // fast_provision experiment: if the user did NOT pass --beta or --fast, // bucket them on the PostHog `fast_provision` flag. The `test` variant - // turns on images by default; control behaves as before. + // turns on images + docker by default; control behaves as before. // Exposure is captured for both variants so PostHog can compute conversion. if (!userOptedIntoBeta) { const variant = getFeatureFlag("fast_provision", "control"); if (variant === "test") { - betaFeatures.push("images"); + betaFeatures.push("images", "docker"); } } diff --git a/packages/cli/src/local/local.ts b/packages/cli/src/local/local.ts index 528b09c9c..bfa5d5f4e 100644 --- a/packages/cli/src/local/local.ts +++ b/packages/cli/src/local/local.ts @@ -4,7 +4,6 @@ import { copyFileSync, mkdirSync, mkdtempSync, rmSync, statSync } from "node:fs" import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { tryCatch } from "@openrouter/spawn-shared"; -import { getFeatureFlag } from "../shared/feature-flags.js"; import { DOCKER_CONTAINER_NAME, DOCKER_REGISTRY } from "../shared/orchestrate.js"; import { getUserHome } from "../shared/paths.js"; import { getLocalShell } from "../shared/shell.js"; @@ -475,14 +474,27 @@ export async function ensureDocker(): Promise { ], }, ).exitCode === 0; - // PostHog experiment: "test" variant uses Docker's official convenience - // script (distro-agnostic — covers Fedora/Arch/Alpine, not just apt). - const useConvenienceScript = getFeatureFlag("linux_docker_install", "control") === "test"; - const installLabel = useConvenienceScript ? "via get.docker.com" : "docker.io"; + const hasApt = + Bun.spawnSync( + [ + "which", + "apt-get", + ], + { + stdio: [ + "ignore", + "ignore", + "ignore", + ], + }, + ).exitCode === 0; + // Prefer apt-get on Debian/Ubuntu (small, fast, distro-trusted). + // Fall back to Docker's convenience script for Fedora/Arch/Alpine/etc. + const installLabel = hasApt ? "docker.io" : "via get.docker.com"; logStep(`Docker not found — installing ${installLabel}...`); - const installCmd = useConvenienceScript - ? `curl -fsSL https://get.docker.com | ${hasSudo ? "sudo sh" : "sh"}` - : `${hasSudo ? "sudo " : ""}apt-get update -qq && ${hasSudo ? "sudo " : ""}apt-get install -y -qq docker.io`; + const installCmd = hasApt + ? `${hasSudo ? "sudo " : ""}apt-get update -qq && ${hasSudo ? "sudo " : ""}apt-get install -y -qq docker.io` + : `curl -fsSL https://get.docker.com | ${hasSudo ? "sudo sh" : "sh"}`; const result = Bun.spawnSync( [ "bash", @@ -498,9 +510,7 @@ export async function ensureDocker(): Promise { }, ); if (result.exitCode !== 0) { - const manualHint = useConvenienceScript - ? "https://docs.docker.com/engine/install/" - : "sudo apt-get install docker.io"; + const manualHint = hasApt ? "sudo apt-get install docker.io" : "https://docs.docker.com/engine/install/"; logInfo(`Auto-install failed. Install Docker manually: ${manualHint}`); process.exit(1); }