Skip to content

Commit 776c6f9

Browse files
BohdanVilischukwaleedlatif1
authored andcommitted
fix(setup): detect OrbStack vs Docker Desktop before relaunching the daemon
ensureDocker() always ran `open -a Docker` to relaunch a stopped daemon on macOS, which silently no-ops for OrbStack users (no Docker.app bundle exists), leading to a misleading "GUI license acceptance" timeout error. Now it checks the docker CLI's active context first (accurate regardless of install location) and falls back to checking for OrbStack.app, so the wizard launches and messages the app that's actually installed.
1 parent 3d8b2ed commit 776c6f9

1 file changed

Lines changed: 33 additions & 6 deletions

File tree

scripts/setup/docker.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { spawnSync } from 'node:child_process'
2+
import { existsSync } from 'node:fs'
23
import { SetupError } from './errors.ts'
34
import { waitFor } from './probes.ts'
45
import * as p from './prompter.ts'
@@ -9,6 +10,10 @@ const INSTALL_HINTS = [
910
`or OrbStack (lighter on macOS): ${theme.command('brew install orbstack')}`,
1011
]
1112

13+
/** macOS GUI docker providers we know how to launch via `open -a`. */
14+
const ORBSTACK_APP = { name: 'OrbStack', path: '/Applications/OrbStack.app' } as const
15+
const DOCKER_DESKTOP_APP = { name: 'Docker', path: '/Applications/Docker.app' } as const
16+
1217
function daemonUp(): boolean {
1318
return spawnSync('docker', ['info'], { stdio: 'ignore' }).status === 0
1419
}
@@ -19,6 +24,24 @@ function installed(): boolean {
1924
return Bun.which('docker') !== null
2025
}
2126

27+
function currentDockerContext(): string | null {
28+
const result = spawnSync('docker', ['context', 'show'], { encoding: 'utf8' })
29+
return result.status === 0 ? result.stdout.trim() : null
30+
}
31+
32+
/**
33+
* Which GUI app owns the `docker` CLI on this Mac. Docker Desktop and OrbStack
34+
* both install a `docker` binary, so presence of the CLI alone doesn't tell us
35+
* which app to relaunch. Prefer the docker CLI's own active context — it's
36+
* accurate regardless of where the app bundle lives — and fall back to
37+
* checking the well-known `.app` install paths when the context doesn't say.
38+
*/
39+
function macDockerApp(): typeof ORBSTACK_APP | typeof DOCKER_DESKTOP_APP {
40+
if (currentDockerContext() === 'orbstack') return ORBSTACK_APP
41+
if (existsSync(ORBSTACK_APP.path)) return ORBSTACK_APP
42+
return DOCKER_DESKTOP_APP
43+
}
44+
2245
/**
2346
* Returns whether the Docker daemon is available, offering to launch Docker
2447
* Desktop (macOS) when it's installed but stopped. Never installs anything.
@@ -41,27 +64,31 @@ export async function ensureDocker(required: boolean): Promise<boolean> {
4164
return false
4265
}
4366

67+
const app = macDockerApp()
68+
4469
const launch = await p.confirm({
45-
message: 'Docker is installed but not running — start Docker Desktop now?',
70+
message: `Docker is installed but not running — start ${app.name} now?`,
4671
initialValue: true,
4772
})
4873
if (!launch) {
4974
if (required) {
5075
throw new SetupError('Docker is required for this mode.', [
51-
'start Docker Desktop, then re-run the wizard',
76+
`start ${app.name}, then re-run the wizard`,
5277
])
5378
}
5479
return false
5580
}
5681

57-
spawnSync('open', ['-a', 'Docker'], { stdio: 'ignore' })
82+
spawnSync('open', ['-a', app.name], { stdio: 'ignore' })
5883
const spin = p.spinner()
59-
spin.start('Waiting for the Docker daemon…')
84+
spin.start(`Waiting for the Docker daemon (${app.name})…`)
6085
const up = await waitFor(async () => daemonUp(), 90_000, 2000)
6186
spin.stop(up ? 'Docker is running' : `${glyph.fail} daemon did not come up`)
6287
if (!up) {
63-
throw new SetupError('Docker Desktop did not start within 90s.', [
64-
'first-ever launch needs a GUI license acceptance — open Docker Desktop manually once, then re-run',
88+
throw new SetupError(`${app.name} did not start within 90s.`, [
89+
app === ORBSTACK_APP
90+
? 'open OrbStack manually once to finish its first-run setup, then re-run'
91+
: 'first-ever launch needs a GUI license acceptance — open Docker Desktop manually once, then re-run',
6592
])
6693
}
6794
return true

0 commit comments

Comments
 (0)