feat(KB-620): add multi-project first-run migration flow

- Add first-run migration detection and registration helpers for central project setup
- Wire CLI and dashboard setup routes to auto-migrate existing projects and complete setup
- Harden path resolution, overlap checks, and backward-compat project selection behavior
- Add regression tests for migration, nested project detection, and single-project compatibility
This commit is contained in:
gsxdsm
2026-04-01 14:18:57 -07:00
parent d943616cb3
commit a463670852
11 changed files with 653 additions and 306 deletions

View File

@@ -1083,28 +1083,18 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
*/
router.get("/setup-state", async (_req, res) => {
try {
const { createFirstRunExperience, CentralCore } = await import("@fusion/core");
const { createMigrationOrchestrator } = await import("@fusion/core");
const { FirstRunDetector } = await import("@fusion/core");
const { CentralCore } = await import("@fusion/core");
const central = new CentralCore();
await central.init();
const detector = new FirstRunDetector();
const state = await detector.detectFirstRunState();
const detectedProjects = await detector.detectExistingProjects(process.cwd());
try {
const migration = createMigrationOrchestrator(central);
const firstRun = createFirstRunExperience(central);
const needsMigration = await migration.needsMigration();
const state = await firstRun.getSetupState();
const detectedProjects = state.detectedProjects || [];
res.json({
state: needsMigration ? "needs-migration" : state.isFirstRun ? "setup-wizard" : "normal-operation",
detectedProjects,
hasCentralDb: true,
});
} finally {
await central.close();
}
res.json({
state,
detectedProjects,
hasCentralDb: detector.hasCentralDb(),
});
} catch (err: any) {
res.status(500).json({ error: err.message });
}
@@ -1124,19 +1114,19 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
return;
}
const { CentralCore, createFirstRunExperience } = await import("@fusion/core");
const { CentralCore, MigrationCoordinator } = await import("@fusion/core");
const central = new CentralCore();
await central.init();
try {
const firstRun = createFirstRunExperience(central);
const result = await firstRun.completeSetup(projects);
const coordinator = new MigrationCoordinator(central);
const result = await coordinator.completeSetup(projects);
res.json({
success: result.success,
registered: result.projects.map(p => p.id),
errors: [],
registered: result.projectsRegistered,
errors: result.errors,
});
} finally {
await central.close();