diff --git a/.changeset/onboarding-central-db-no-prompt.md b/.changeset/onboarding-central-db-no-prompt.md new file mode 100644 index 0000000000..d5d53c57b9 --- /dev/null +++ b/.changeset/onboarding-central-db-no-prompt.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Onboarding no longer asks whether to create the central database — it always creates it. +category: fix +dev: `runOnboard` gated central-DB creation behind `runSkippableStep(prompts, "Central DB", ...)`. Declining produced an install Fusion cannot run on, acknowledged only by a "database was not created or initialized" line, so the negative answer had no useful outcome. It also blocked non-interactive startups: a `pnpm dev --tunnel` stopped on `Run central db now? (Y/n)` never reached listening, so nothing was served. The step now runs unconditionally when the database is absent; the "already exists" path is unchanged. Scripted prompt sequences in `onboard.test.ts` lost their leading central-DB answer accordingly, and the skip-everything case now asserts the database is still created. diff --git a/packages/cli/src/commands/__tests__/onboard.test.ts b/packages/cli/src/commands/__tests__/onboard.test.ts index 0c0d1ed628..bd6f8e27cd 100644 --- a/packages/cli/src/commands/__tests__/onboard.test.ts +++ b/packages/cli/src/commands/__tests__/onboard.test.ts @@ -163,7 +163,7 @@ describe("onboard", () => { const logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); await runOnboard({ - input: inputFrom(["y", "y", "4", "y", "y", "n", "y"]), + input: inputFrom(["y", "4", "y", "y", "n", "y"]), }); expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("Creating central DB")); expect(centralInitMock).toHaveBeenCalled(); @@ -187,7 +187,7 @@ describe("onboard", () => { const logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); await runOnboard({ - input: inputFrom(["y", "y", "3", "local", "Local server", "http://localhost:8080/v1/", "", "qwen, , qwen", "y", "y", "n", "n", "n"]), + input: inputFrom(["y", "3", "local", "Local server", "http://localhost:8080/v1/", "", "qwen, , qwen", "y", "y", "n", "n", "n"]), }); const registry = JSON.parse(readFileSync(path, "utf8")); @@ -209,7 +209,7 @@ describe("onboard", () => { if (message.includes("Stored API key")) expect(persisted).toBe(true); }); - await runOnboard({ input: inputFrom(["y", "y", "1", "test-key", "y", "y", "n", "y"]) }); + await runOnboard({ input: inputFrom(["y", "1", "test-key", "y", "y", "n", "y"]) }); expect(providerAuth.setApiKey).toHaveBeenCalledWith("openrouter", "test-key"); expect(logSpy).toHaveBeenCalledWith("✓ Stored API key for openrouter"); }); @@ -219,7 +219,7 @@ describe("onboard", () => { mockProviderAuthFactory.mockReturnValue(providerAuth); const logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); - await runOnboard({ input: inputFrom(["y", "y", "1", "test-key", "y", "y", "y", "y"]) }); + await runOnboard({ input: inputFrom(["y", "1", "test-key", "y", "y", "y", "y"]) }); expect(providerAuth.setApiKey).toHaveBeenCalledWith("openrouter", "test-key"); expect(mockRunInit).toHaveBeenCalledTimes(1); @@ -241,7 +241,7 @@ describe("onboard", () => { expect(providerAuth.setApiKey).not.toHaveBeenCalled(); expect(mockRunInit).not.toHaveBeenCalled(); - await runOnboard({ force: true, input: inputFrom(["y", "n", "n", "n", "n"]) }); + await runOnboard({ force: true, input: inputFrom(["n", "n", "n", "n"]) }); expect(globalSettingsState.cliOnboardingCompletedAt).not.toBe("2026-06-01T00:00:00.000Z"); }); @@ -283,9 +283,15 @@ describe("onboard", () => { const providerAuth = makeProviderAuth(); mockProviderAuthFactory.mockReturnValue(providerAuth); - await runOnboard({ input: inputFrom(["n", "n", "n", "n", "n"]) }); + await runOnboard({ input: inputFrom(["n", "n", "n", "n"]) }); - expect(centralInitMock).not.toHaveBeenCalled(); + /* + FNXC:Onboarding 2026-08-19-03:38: + The central DB is no longer skippable: declining left an install Fusion cannot run on, and the + prompt blocked non-interactive startups outright (a `pnpm dev --tunnel` sat on it and never + listened). Skipping every OPTIONAL step must still leave a created database. + */ + expect(centralInitMock).toHaveBeenCalled(); expect(mockRunInit).not.toHaveBeenCalled(); expect(globalSettingsState.testMode).toBeUndefined(); expect(typeof globalSettingsState.cliOnboardingCompletedAt).toBe("string"); @@ -296,7 +302,7 @@ describe("onboard", () => { const providerAuth = makeProviderAuth(); mockProviderAuthFactory.mockReturnValue(providerAuth); - await runOnboard({ input: inputFrom(["y", "n", "y", "y", "n", "y"]) }); + await runOnboard({ input: inputFrom(["n", "y", "y", "n", "y"]) }); expect(providerAuth.setApiKey).not.toHaveBeenCalled(); expect(mockRunInit).toHaveBeenCalledTimes(1); expect(globalSettingsState.testMode).toBe(false); @@ -307,7 +313,7 @@ describe("onboard", () => { const providerAuth = makeProviderAuth(); mockProviderAuthFactory.mockReturnValue(providerAuth); - await runOnboard({ input: inputFrom(["y", "y", "4", "n", "y", "n", "y"]) }); + await runOnboard({ input: inputFrom(["y", "4", "n", "y", "n", "y"]) }); expect(mockRunInit).not.toHaveBeenCalled(); expect(globalSettingsState.testMode).toBe(false); expect(typeof globalSettingsState.cliOnboardingCompletedAt).toBe("string"); diff --git a/packages/cli/src/commands/onboard.ts b/packages/cli/src/commands/onboard.ts index c19c898a5c..7919b45c87 100644 --- a/packages/cli/src/commands/onboard.ts +++ b/packages/cli/src/commands/onboard.ts @@ -281,16 +281,20 @@ export async function runOnboard(options: OnboardOptions = {}): Promise { if (existsSync(centralDbPath)) { console.log(`✓ Central DB already exists: ${centralDbPath}`); } else { - const ranCentralDb = await runSkippableStep(prompts, "Central DB", async () => { - console.log(`Creating central DB: ${centralDbPath}`); - const central = new CentralCore(); - await central.init(); - await central.close(); - console.log("✓ Central DB initialized"); - }); - if (!ranCentralDb) { - console.log("Central DB setup skipped; database was not created or initialized."); - } + /* + FNXC:Onboarding 2026-08-19-03:38: + The central DB is created unconditionally — no prompt. Fusion cannot run without it, so + declining produced an install that was broken in a way the message ("database was not created + or initialized") described but did not fix. It also blocked non-interactive startups: a + `pnpm dev --tunnel` sat on "Run central db now? (Y/n)" and never listened, so nothing was + served and the tunnel had no dev server to point at. + */ + console.log("\nCentral DB:"); + console.log(`Creating central DB: ${centralDbPath}`); + const central = new CentralCore(); + await central.init(); + await central.close(); + console.log("✓ Central DB initialized"); } const authStorage = createFusionAuthStorage();