This commit was merged in pull request #646.
This commit is contained in:
@@ -521,6 +521,75 @@ export function runFrameworkReseed(
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Framework drift detection (#642) ────────────────────────────────────────
|
||||
//
|
||||
// `mosaic update` only re-seeds the framework when the @mosaicstack/mosaic
|
||||
// package itself is upgraded *within that command*. When the CLI is upgraded
|
||||
// some OTHER way — a direct `npm i -g @mosaicstack/mosaic`, or an upgrade run
|
||||
// where only sibling packages were outdated — the framework files in
|
||||
// ~/.config/mosaic stay stale and shipped launcher/runtime fixes never
|
||||
// activate. Comparing the on-disk framework schema version against the version
|
||||
// bundled in the installed package detects exactly that situation.
|
||||
|
||||
/** Read the framework schema version recorded on disk (~/.config/mosaic/.framework-version). */
|
||||
export function readInstalledFrameworkVersion(
|
||||
mosaicHome = join(homedir(), '.config', 'mosaic'),
|
||||
): number | undefined {
|
||||
const vf = join(mosaicHome, '.framework-version');
|
||||
if (!existsSync(vf)) return undefined;
|
||||
try {
|
||||
const n = parseInt(readFileSync(vf, 'utf-8').trim(), 10);
|
||||
return Number.isFinite(n) ? n : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the framework schema version shipped in the installed package by parsing
|
||||
* `FRAMEWORK_VERSION=<n>` out of the bundled install.sh (the authoritative
|
||||
* source the installer writes to .framework-version).
|
||||
*/
|
||||
export function readBundledFrameworkVersion(
|
||||
frameworkRoot = resolveBundledFrameworkRoot(),
|
||||
): number | undefined {
|
||||
const installer = join(frameworkRoot, 'install.sh');
|
||||
if (!existsSync(installer)) return undefined;
|
||||
try {
|
||||
const m = readFileSync(installer, 'utf-8').match(/^\s*FRAMEWORK_VERSION=(\d+)/m);
|
||||
const raw = m?.[1];
|
||||
if (!raw) return undefined;
|
||||
const n = parseInt(raw, 10);
|
||||
return Number.isFinite(n) ? n : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export interface FrameworkDrift {
|
||||
/** True only when both versions are known AND the on-disk one is older. */
|
||||
drifted: boolean;
|
||||
installed?: number;
|
||||
bundled?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether the on-disk framework is older than the framework bundled in
|
||||
* the installed CLI (#642). Conservative: if either version can't be read the
|
||||
* result is no-drift, so a missing/unreadable version file never triggers an
|
||||
* unexpected re-seed.
|
||||
*/
|
||||
export function checkFrameworkDrift(
|
||||
mosaicHome = join(homedir(), '.config', 'mosaic'),
|
||||
frameworkRoot = resolveBundledFrameworkRoot(),
|
||||
): FrameworkDrift {
|
||||
const installed = readInstalledFrameworkVersion(mosaicHome);
|
||||
const bundled = readBundledFrameworkVersion(frameworkRoot);
|
||||
const drifted =
|
||||
typeof installed === 'number' && typeof bundled === 'number' && installed < bundled;
|
||||
return { drifted, installed, bundled };
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort parse of the fleet roster for agent names (used to relaunch
|
||||
* durable agents after a re-seed). Returns [] when no roster exists.
|
||||
|
||||
Reference in New Issue
Block a user