ci/woodpecker/push/publish Pipeline failed
Co-authored-by: Jason Woltje <[email protected]>
77 lines
3.4 KiB
TypeScript
77 lines
3.4 KiB
TypeScript
import { existsSync } from 'node:fs';
|
|
import { homedir } from 'node:os';
|
|
import { join, resolve } from 'node:path';
|
|
|
|
/**
|
|
* Overridable resolution inputs (tests inject tmp homes; production reads
|
|
* the environment and the real home directory).
|
|
*/
|
|
export interface BrainHomeOptions {
|
|
/** Explicit brain home; defaults to `MOSAIC_BRAIN_HOME`. */
|
|
readonly envBrainHome?: string;
|
|
/**
|
|
* Canonical homes used for adoption. Defaults derive from the real
|
|
* `homedir()`: `{ brain: ~/.mosaic, configDefault: ~/.config/mosaic }`.
|
|
*/
|
|
readonly homes?: { readonly brain: string; readonly configDefault: string };
|
|
}
|
|
|
|
/**
|
|
* Brain-home resolution — the three-tree fleet split (stack canon
|
|
* `docs/STRUCTURE-CANON.md` §2, first carried by the USC estate brain):
|
|
*
|
|
* config home (~/.config/mosaic) framework templates + dispatch state:
|
|
* fleet/roles (baseline), fleet/roster.yaml,
|
|
* fleet/run (heartbeats), fleet/services
|
|
* brain home (~/.mosaic) user-owned fleet state, committed:
|
|
* fleet/agents/<seat>.env.*, fleet/roles.local,
|
|
* fleet/profiles working copies
|
|
*
|
|
* Resolution order:
|
|
* 1. `MOSAIC_BRAIN_HOME` env (explicit, always wins)
|
|
* 2. canonical `~/.mosaic` — adopted ONLY when mosaicHome is the real
|
|
* default config home AND `~/.mosaic/fleet/agents` exists. Custom
|
|
* `--mosaic-home` values (tests, sandboxes, canaries) never trigger
|
|
* adoption, keeping them hermetic and deterministic.
|
|
* 3. mosaicHome itself (legacy single-tree behavior).
|
|
*/
|
|
export function resolveBrainHome(mosaicHome: string, options: BrainHomeOptions = {}): string {
|
|
const explicit = options.envBrainHome ?? process.env['MOSAIC_BRAIN_HOME'];
|
|
if (explicit !== undefined && explicit.trim() !== '') {
|
|
return explicit;
|
|
}
|
|
const homes = options.homes ?? {
|
|
brain: join(homedir(), '.mosaic'),
|
|
configDefault: join(homedir(), '.config', 'mosaic'),
|
|
};
|
|
if (resolve(mosaicHome) !== resolve(homes.configDefault)) {
|
|
return mosaicHome;
|
|
}
|
|
return existsSync(join(homes.brain, 'fleet', 'agents')) ? homes.brain : mosaicHome;
|
|
}
|
|
|
|
/** True when fleet state resolves somewhere other than the config home. */
|
|
export function brainHomeIsActive(mosaicHome: string, options: BrainHomeOptions = {}): boolean {
|
|
return resolve(resolveBrainHome(mosaicHome, options)) !== resolve(mosaicHome);
|
|
}
|
|
|
|
/** Fleet state root (brain home when active, else the config home). */
|
|
export function fleetStateDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
|
|
return join(resolveBrainHome(mosaicHome, options), 'fleet');
|
|
}
|
|
|
|
/** Seat launch envs — `<brainHome>/fleet/agents` when a brain is active. */
|
|
export function fleetAgentEnvDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
|
|
return join(fleetStateDir(mosaicHome, options), 'agents');
|
|
}
|
|
|
|
/** PRESERVE-protected persona override layer — `<brainHome>/fleet/roles.local`. */
|
|
export function fleetRolesLocalDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
|
|
return join(fleetStateDir(mosaicHome, options), 'roles.local');
|
|
}
|
|
|
|
/** System-type profiles (user working copies) — `<brainHome>/fleet/profiles`. */
|
|
export function fleetProfilesDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
|
|
return join(fleetStateDir(mosaicHome, options), 'profiles');
|
|
}
|