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

- Add FirstRunDetector for fresh-install and migration state detection
- Implement MigrationOrchestrator for auto-registering existing projects
- Create BackwardCompat layer to maintain single-project CLI workflows
- Add fn init command for manual project registration
- Add dashboard first-run wizard API endpoints (/api/setup-state, /api/complete-setup)
- Add runtimeLog, ipcLog, projectManagerLog, hybridExecutorLog to engine logger
- Include changeset documenting migration features and rollback procedure
This commit is contained in:
gsxdsm
2026-04-01 07:19:44 -07:00
parent 228648adfa
commit 0559962685
11 changed files with 2006 additions and 2 deletions

View File

@@ -1066,6 +1066,68 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
// Get GitHub token from options or env
const githubToken = options?.githubToken ?? process.env.GITHUB_TOKEN;
// ── Setup and Migration Routes ───────────────────────────────────────────
/**
* GET /api/setup-state
* Returns the first-run state and detected projects for migration/setup wizard.
* Response: { state: FirstRunState, detectedProjects: DetectedProject[], hasCentralDb: boolean }
*/
router.get("/setup-state", async (_req, res) => {
try {
const { FirstRunDetector } = await import("@fusion/core");
const { CentralCore } = await import("@fusion/core");
const detector = new FirstRunDetector();
const state = await detector.detectFirstRunState();
const detectedProjects = await detector.detectExistingProjects(process.cwd());
res.json({
state,
detectedProjects,
hasCentralDb: detector.hasCentralDb(),
});
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
/**
* POST /api/complete-setup
* Complete setup by registering selected projects.
* Body: { projects: Array<{ path: string, name: string, isolationMode?: string }> }
* Response: { success: boolean, registered: string[], errors: string[] }
*/
router.post("/complete-setup", async (req, res) => {
try {
const { projects } = req.body;
if (!Array.isArray(projects)) {
res.status(400).json({ error: "projects array is required" });
return;
}
const { CentralCore, MigrationCoordinator } = await import("@fusion/core");
const central = new CentralCore();
await central.init();
try {
const coordinator = new MigrationCoordinator(central);
const result = await coordinator.completeSetup(projects);
res.json({
success: result.success,
registered: result.projectsRegistered,
errors: result.errors,
});
} finally {
await central.close();
}
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
// Scheduler config (includes persisted settings)
router.get("/config", async (_req, res) => {
try {