mosaic update only re-seeded ~/.config/mosaic when the @mosaicstack/mosaic package was upgraded within that same command. When the CLI is upgraded another way — a direct npm i -g @mosaicstack/mosaic, or an update run where only sibling packages were outdated — the framework files (launchers, runtime adapters, fleet tools) silently stayed stale, so shipped fixes never activated. Worse, the "all packages up to date" branch returned before any re-seed could run, so a drifted-but-current host had no path to reconcile. (#642)
Fix
Add framework drift detection: compare the on-disk schema version (~/.config/mosaic/.framework-version) against the version bundled in the installed package (FRAMEWORK_VERSION in the bundled install.sh). mosaic update now re-seeds when the mosaic package updated OR the on-disk framework is older than bundled — including from the up-to-date branch.
Detection is conservative: if either version can't be read it reports no drift, so a missing/unreadable version file never triggers an unexpected re-seed. --no-reseed still opts out. The re-seed + unit-refresh + relaunch sequence is factored into one local helper shared by both paths (no behavior change to the existing path beyond also firing on drift).
## Summary
`mosaic update` only re-seeded `~/.config/mosaic` when the **@mosaicstack/mosaic** package was upgraded *within that same command*. When the CLI is upgraded another way — a direct `npm i -g @mosaicstack/mosaic`, or an update run where only sibling packages were outdated — the framework files (launchers, runtime adapters, fleet tools) silently stayed stale, so shipped fixes never activated. Worse, the **"all packages up to date"** branch returned *before* any re-seed could run, so a drifted-but-current host had no path to reconcile. (#642)
## Fix
Add **framework drift detection**: compare the on-disk schema version (`~/.config/mosaic/.framework-version`) against the version bundled in the installed package (`FRAMEWORK_VERSION` in the bundled `install.sh`). `mosaic update` now re-seeds when the mosaic package updated **OR** the on-disk framework is older than bundled — **including from the up-to-date branch**.
Detection is **conservative**: if either version can't be read it reports no drift, so a missing/unreadable version file never triggers an unexpected re-seed. `--no-reseed` still opts out. The re-seed + unit-refresh + relaunch sequence is factored into one local helper shared by both paths (no behavior change to the existing path beyond also firing on drift).
## New helpers (exported + unit-tested)
- `readInstalledFrameworkVersion` / `readBundledFrameworkVersion`
- `checkFrameworkDrift` → `{ drifted, installed, bundled }`
## Verification
`tsc --noEmit` clean · eslint clean · `vitest` 17/17 in `update-checker.reseed.spec.ts` (8 new drift cases: older/equal/newer/unreadable) · `tsc` build clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
`mosaic update` only re-seeded ~/.config/mosaic when the @mosaicstack/mosaic
package was upgraded *within that same command*. When the CLI is upgraded
another way — a direct `npm i -g @mosaicstack/mosaic`, or an update run where
only sibling packages were outdated — the framework files (launchers, runtime
adapters, fleet tools) silently stayed stale, so shipped fixes never activated.
Critically, the "all packages up to date" branch returned before any re-seed
could run, so a drifted-but-current host had no path to reconcile.
Add framework drift detection: compare the on-disk schema version
(~/.config/mosaic/.framework-version) against the version bundled in the
installed package (FRAMEWORK_VERSION in the bundled install.sh). `mosaic update`
now re-seeds when the mosaic package updated OR the on-disk framework is older
than bundled — including from the up-to-date branch. Detection is conservative:
if either version can't be read it reports no drift, so a missing/unreadable
version file never triggers an unexpected re-seed. `--no-reseed` still opts out.
The re-seed + unit-refresh + relaunch sequence is factored into a single local
helper shared by both the post-update and drift paths (no behavior change to the
existing path beyond also firing on drift).
New exported, unit-tested helpers in update-checker.ts:
- readInstalledFrameworkVersion / readBundledFrameworkVersion
- checkFrameworkDrift -> { drifted, installed, bundled }
Co-Authored-By: Claude Opus 4.8 <[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 updateonly re-seeded~/.config/mosaicwhen the @mosaicstack/mosaic package was upgraded within that same command. When the CLI is upgraded another way — a directnpm i -g @mosaicstack/mosaic, or an update run where only sibling packages were outdated — the framework files (launchers, runtime adapters, fleet tools) silently stayed stale, so shipped fixes never activated. Worse, the "all packages up to date" branch returned before any re-seed could run, so a drifted-but-current host had no path to reconcile. (#642)Fix
Add framework drift detection: compare the on-disk schema version (
~/.config/mosaic/.framework-version) against the version bundled in the installed package (FRAMEWORK_VERSIONin the bundledinstall.sh).mosaic updatenow re-seeds when the mosaic package updated OR the on-disk framework is older than bundled — including from the up-to-date branch.Detection is conservative: if either version can't be read it reports no drift, so a missing/unreadable version file never triggers an unexpected re-seed.
--no-reseedstill opts out. The re-seed + unit-refresh + relaunch sequence is factored into one local helper shared by both paths (no behavior change to the existing path beyond also firing on drift).New helpers (exported + unit-tested)
readInstalledFrameworkVersion/readBundledFrameworkVersioncheckFrameworkDrift→{ drifted, installed, bundled }Verification
tsc --noEmitclean · eslint clean ·vitest17/17 inupdate-checker.reseed.spec.ts(8 new drift cases: older/equal/newer/unreadable) ·tscbuild clean.🤖 Generated with Claude Code
`mosaic update` only re-seeded ~/.config/mosaic when the @mosaicstack/mosaic package was upgraded *within that same command*. When the CLI is upgraded another way — a direct `npm i -g @mosaicstack/mosaic`, or an update run where only sibling packages were outdated — the framework files (launchers, runtime adapters, fleet tools) silently stayed stale, so shipped fixes never activated. Critically, the "all packages up to date" branch returned before any re-seed could run, so a drifted-but-current host had no path to reconcile. Add framework drift detection: compare the on-disk schema version (~/.config/mosaic/.framework-version) against the version bundled in the installed package (FRAMEWORK_VERSION in the bundled install.sh). `mosaic update` now re-seeds when the mosaic package updated OR the on-disk framework is older than bundled — including from the up-to-date branch. Detection is conservative: if either version can't be read it reports no drift, so a missing/unreadable version file never triggers an unexpected re-seed. `--no-reseed` still opts out. The re-seed + unit-refresh + relaunch sequence is factored into a single local helper shared by both the post-update and drift paths (no behavior change to the existing path beyond also firing on drift). New exported, unit-tested helpers in update-checker.ts: - readInstalledFrameworkVersion / readBundledFrameworkVersion - checkFrameworkDrift -> { drifted, installed, bundled } Co-Authored-By: Claude Opus 4.8 <[email protected]>