FN-5811: respect persisted CLI onboarding completion marker

Ensure CLI onboarding only auto-runs once by honoring a valid persisted completion timestamp.

- add `isCliOnboardingComplete` helper to validate non-empty `cliOnboardingCompletedAt` marker values
- use the helper in `runOnboard` so reruns are blocked unless `--force` is provided
- extend onboard tests to cover marker validation and verify the rerun guidance log

Files changed:
 packages/cli/src/commands/__tests__/onboard.test.ts | 10 ++++++++++
 packages/cli/src/commands/onboard.ts                | 10 +++++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-5811
Fusion-Task-Lineage: 1547fd85-d06f-4ad0-adca-3a22709447fa
This commit is contained in:
gsxdsm
2026-06-01 14:39:00 -07:00
parent 379d01ae45
commit bf37ce89f6
2 changed files with 19 additions and 1 deletions

View File

@@ -85,6 +85,14 @@ function makeProviderAuth() {
}
describe("onboard", () => {
it("isCliOnboardingComplete handles marker presence correctly", () => {
expect(__testUtils.isCliOnboardingComplete({})).toBe(false);
expect(__testUtils.isCliOnboardingComplete({ cliOnboardingCompletedAt: "" })).toBe(false);
expect(__testUtils.isCliOnboardingComplete({ cliOnboardingCompletedAt: "2026-06-01T00:00:00.000Z" })).toBe(
true,
);
});
beforeEach(() => {
vi.clearAllMocks();
for (const key of Object.keys(globalSettingsState)) delete globalSettingsState[key];
@@ -166,9 +174,11 @@ describe("onboard", () => {
it("re-runs only with force when marker already exists", async () => {
const providerAuth = makeProviderAuth();
mockProviderAuthFactory.mockReturnValue(providerAuth);
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
globalSettingsState.cliOnboardingCompletedAt = "2026-06-01T00:00:00.000Z";
await runOnboard({ input: inputFrom(["y", "3", "y", "y", "n", "y"]) });
expect(logSpy).toHaveBeenCalledWith("Onboarding already completed. Re-run with --force to run it again.");
expect(providerAuth.setApiKey).not.toHaveBeenCalled();
expect(mockRunInit).not.toHaveBeenCalled();

View File

@@ -150,12 +150,19 @@ async function runSkippableStep(
return true;
}
export function isCliOnboardingComplete(settings: { cliOnboardingCompletedAt?: string }): boolean {
return (
typeof settings.cliOnboardingCompletedAt === "string" &&
settings.cliOnboardingCompletedAt.trim().length > 0
);
}
export async function runOnboard(options: OnboardOptions = {}): Promise<void> {
const globalSettingsStore = new GlobalSettingsStore();
await globalSettingsStore.init();
const settings = await globalSettingsStore.getSettings();
if (settings.cliOnboardingCompletedAt && !options.force) {
if (isCliOnboardingComplete(settings) && !options.force) {
console.log("Onboarding already completed. Re-run with --force to run it again.");
return;
}
@@ -267,5 +274,6 @@ export const __testUtils = {
createPromptSession,
validateMaxConcurrent,
runSkippableStep,
isCliOnboardingComplete,
PROMPT_CANCELLED_ERROR,
};