feat(fleet): HARNESS-HOMES fleet MVP — profile-driven seat composition and launch (#1209) #1213

Open
Ghost wants to merge 11 commits from feat/wf-fleet-mvp into next
2 changed files with 32 additions and 4 deletions
Showing only changes of commit 5e15431027 - Show all commits
@@ -242,6 +242,28 @@ describe('managed plugin and skill links', () => {
); );
}); });
it('tolerates harness metadata files in the install root and still refuses real directories', () => {
const fx = fixture({ schema: 1, harness: 'claude', plugins: [] });
const pluginHome = join(fx.agentDir, '.claude', 'plugins');
mkdirSync(pluginHome, { recursive: true });
writeFileSync(join(pluginHome, 'installed_plugins.json'), '{}\n');
const plan = resolveFleetLaunchComposition('fred', {
systemHome: fx.systemHome,
userHome: fx.userHome,
});
expect(plan.prune).toEqual([]);
expect(readFileSync(join(pluginHome, 'installed_plugins.json'), 'utf8')).toBe('{}\n');
mkdirSync(join(pluginHome, 'stray-plugin'), { recursive: true });
expect(() =>
resolveFleetLaunchComposition('fred', {
systemHome: fx.systemHome,
userHome: fx.userHome,
}),
).toThrowError(/real plugin directory occupies managed install root.*refusing to prune/i);
});
it('surfaces a real directory at a managed link path without deleting it', () => { it('surfaces a real directory at a managed link path without deleting it', () => {
const fx = fixture({ schema: 1, harness: 'claude', plugins: ['keep'] }); const fx = fixture({ schema: 1, harness: 'claude', plugins: ['keep'] });
mkdirSync(join(fx.userHome, 'plugins', 'keep'), { recursive: true }); mkdirSync(join(fx.userHome, 'plugins', 'keep'), { recursive: true });
@@ -498,10 +498,16 @@ function resolveManagedLinks(
const path = join(installRoot, entry.name); const path = join(installRoot, entry.name);
if (desired.has(entry.name)) continue; if (desired.has(entry.name)) continue;
if (!entry.isSymbolicLink()) { if (!entry.isSymbolicLink()) {
throw new FleetLaunchError( // The harness writes its own metadata files (e.g. installed_plugins.json)
'COMPOSITION_FAILED', // beside the managed links; only a real directory is an unmanaged entry
`real ${kind} entry occupies managed install root ${path}; refusing to prune it.`, // the pruner would orphan.
); if (entry.isDirectory()) {
throw new FleetLaunchError(
'COMPOSITION_FAILED',
`real ${kind} directory occupies managed install root ${path}; refusing to prune it.`,
);
}
continue;
} }
prune.push(path); prune.push(path);
} }