Collapse mosaic wizard and mosaic gateway install into a single cohesive first-run flow; gateway config + admin bootstrap now run as terminal stages of runWizard.
Drop the fragile 10-minute $XDG_RUNTIME_DIR/mosaic-install-state.json session-file bridge — state lives in WizardState (new gateway?: slice).
Extract gatewayConfigStage + gatewayBootstrapStage as first-class stages with full spec coverage; mosaic gateway install becomes a thin wrapper.
Port override is honored even on resume; conflicting saved ports force regeneration so .env and meta.json cannot drift.
Honor state.hooks.accepted === false end-to-end: finalize sets MOSAIC_SKIP_CLAUDE_HOOKS=1, and mosaic-link-runtime-assets cleans up previously-installed hooks only when a stable "mosaic-managed": true marker (or byte-equality for legacy installs) identifies the file as ours.
Headless rerun of an already-bootstrapped gateway with no local token cache is now a successful no-op (no more false install failures).
tools/install.sh calls mosaic wizard only — the legacy follow-up mosaic gateway install auto-launch is removed.
## Summary
- Collapse `mosaic wizard` and `mosaic gateway install` into a single cohesive first-run flow; gateway config + admin bootstrap now run as terminal stages of `runWizard`.
- Drop the fragile 10-minute `$XDG_RUNTIME_DIR/mosaic-install-state.json` session-file bridge — state lives in `WizardState` (new `gateway?:` slice).
- Extract `gatewayConfigStage` + `gatewayBootstrapStage` as first-class stages with full spec coverage; `mosaic gateway install` becomes a thin wrapper.
- Port override is honored even on resume; conflicting saved ports force regeneration so `.env` and `meta.json` cannot drift.
- Honor `state.hooks.accepted === false` end-to-end: finalize sets `MOSAIC_SKIP_CLAUDE_HOOKS=1`, and `mosaic-link-runtime-assets` cleans up previously-installed hooks only when a stable `"mosaic-managed": true` marker (or byte-equality for legacy installs) identifies the file as ours.
- Headless rerun of an already-bootstrapped gateway with no local token cache is now a successful no-op (no more false install failures).
- `tools/install.sh` calls `mosaic wizard` only — the legacy follow-up `mosaic gateway install` auto-launch is removed.
## Test plan
- [x] `pnpm typecheck` (turbo, all packages)
- [x] `pnpm lint` (turbo, all packages)
- [x] `pnpm format:check`
- [x] `pnpm --filter @mosaicstack/mosaic test` — 24 files, 219 tests passing (includes 10 new stage spec tests + 3 unified-wizard integration tests)
- [x] New `gatewayConfigStage` spec — fresh install / decline-rerun / corrupt partial / MOSAIC_STORAGE_TIER=team / BETTER_AUTH_SECRET preservation / port-override regeneration
- [x] New `gatewayBootstrapStage` spec — fresh bootstrap / already-exists short-circuit / headless already-bootstrapped no-op / missing env vars / status failure / setup POST failure
- [x] New `unified-wizard.test.ts` — default `runWizard` invokes both gateway stages / skips bootstrap when config not ready / respects `skipGateway: true`
- [x] Four rounds of Codex code review applied; fifth attempt blocked by upstream quota (documented in scratchpad Session 4 remediation log)
Closes mosaicstack/mosaic-stack#427.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
mosaic wizardandmosaic gateway installinto a single cohesive first-run flow; gateway config + admin bootstrap now run as terminal stages ofrunWizard.$XDG_RUNTIME_DIR/mosaic-install-state.jsonsession-file bridge — state lives inWizardState(newgateway?:slice).gatewayConfigStage+gatewayBootstrapStageas first-class stages with full spec coverage;mosaic gateway installbecomes a thin wrapper..envandmeta.jsoncannot drift.state.hooks.accepted === falseend-to-end: finalize setsMOSAIC_SKIP_CLAUDE_HOOKS=1, andmosaic-link-runtime-assetscleans up previously-installed hooks only when a stable"mosaic-managed": truemarker (or byte-equality for legacy installs) identifies the file as ours.tools/install.shcallsmosaic wizardonly — the legacy follow-upmosaic gateway installauto-launch is removed.Test plan
pnpm typecheck(turbo, all packages)pnpm lint(turbo, all packages)pnpm format:checkpnpm --filter @mosaicstack/mosaic test— 24 files, 219 tests passing (includes 10 new stage spec tests + 3 unified-wizard integration tests)gatewayConfigStagespec — fresh install / decline-rerun / corrupt partial / MOSAIC_STORAGE_TIER=team / BETTER_AUTH_SECRET preservation / port-override regenerationgatewayBootstrapStagespec — fresh bootstrap / already-exists short-circuit / headless already-bootstrapped no-op / missing env vars / status failure / setup POST failureunified-wizard.test.ts— defaultrunWizardinvokes both gateway stages / skips bootstrap when config not ready / respectsskipGateway: trueCloses mosaicstack/mosaic-stack#427.
Co-Authored-By: Claude Opus 4.6 [email protected]
ec89675f97tof3d5ef8d7d