diff --git a/__tests__/e2e/skip-onboarding.e2e.ts b/__tests__/e2e/skip-onboarding.e2e.ts
index b27765e..0f41122 100644
--- a/__tests__/e2e/skip-onboarding.e2e.ts
+++ b/__tests__/e2e/skip-onboarding.e2e.ts
@@ -11,7 +11,7 @@ describe('when the user skips onboarding', () => {
await session.sendKey(ENTER);
// Done — no onboarding ran
- await session.waitForText('Confidence is ready');
+ await session.waitForText('Onboarding skipped');
await session.waitForText("What's next?");
// Docs and dashboard links still appear
diff --git a/__tests__/ui/screens/DoneScreen.test.tsx b/__tests__/ui/screens/DoneScreen.test.tsx
index ceae8b3..c994e43 100644
--- a/__tests__/ui/screens/DoneScreen.test.tsx
+++ b/__tests__/ui/screens/DoneScreen.test.tsx
@@ -8,10 +8,13 @@ vi.mock('../../../src/integrations/chat.js', () => ({
}));
describe('DoneScreen', () => {
- it('renders completion message', async () => {
+ it('renders skipped message when no code changes', async () => {
using sut = renderScreen(, { screen: ScreenId.Done });
await waitFor(() => {
- expect(sut.lastFrame()).toContain('Confidence is ready');
+ expect(sut.lastFrame()).toContain('Onboarding skipped');
+ expect(sut.lastFrame()).toContain(
+ 'You can always use Confidence AI plugin to run onboarding yourself later.',
+ );
});
});
@@ -39,10 +42,11 @@ describe('DoneScreen', () => {
});
describe('when code changes are present', () => {
- it('shows code changes summary', async () => {
+ it('renders completion message and code changes summary', async () => {
using sut = renderScreen(, { screen: ScreenId.Done });
store.setCodeChanges(['Added @spotify-confidence/sdk', 'Created confidence.config.ts']);
await waitFor(() => {
+ expect(sut.lastFrame()).toContain('Confidence is ready');
expect(sut.lastFrame()).toContain('What we have set up');
expect(sut.lastFrame()).toContain('confidence.config.ts');
});
diff --git a/__tests__/ui/screens/OnboardingFlow.test.tsx b/__tests__/ui/screens/OnboardingFlow.test.tsx
index 26e6d4c..fe609c8 100644
--- a/__tests__/ui/screens/OnboardingFlow.test.tsx
+++ b/__tests__/ui/screens/OnboardingFlow.test.tsx
@@ -54,7 +54,7 @@ describe('Onboarding flow', () => {
sut.stdin.write(ARROW_DOWN + ENTER);
await waitFor(() => {
- expect(sut.lastFrame()).toContain('Confidence is ready');
+ expect(sut.lastFrame()).toContain('Onboarding skipped');
});
});
});
@@ -199,7 +199,7 @@ describe('Onboarding flow', () => {
sut.stdin.write(ESCAPE);
await waitFor(() => {
- expect(sut.lastFrame()).toContain('Confidence is ready');
+ expect(sut.lastFrame()).toContain('Onboarding skipped');
});
});
diff --git a/src/integrations/cursor/onboarding.ts b/src/integrations/cursor/onboarding.ts
index aadc4e4..55f15dc 100644
--- a/src/integrations/cursor/onboarding.ts
+++ b/src/integrations/cursor/onboarding.ts
@@ -1,8 +1,8 @@
import { type ChildProcess, spawn } from 'node:child_process';
import { createInterface } from 'node:readline';
import type { OnboardingOpts, OnboardingCallbacks } from '../types.js';
-import { STATUS_PREFIX } from '../constants.js';
import { type StreamEvent, extractTextLines } from '../stream-json.js';
+import { normalizeStatusLine } from '../utils.js';
export function runOnboarding(
opts: OnboardingOpts,
@@ -50,11 +50,7 @@ export function runOnboarding(
if (!stripped) continue;
allLines.push(stripped);
callbacks.onStdout(stripped);
-
- const status = stripped.startsWith(STATUS_PREFIX)
- ? stripped.slice(STATUS_PREFIX.length)
- : stripped;
- callbacks.onStatus(status);
+ callbacks.onStatus(normalizeStatusLine(stripped));
}
});
diff --git a/src/integrations/index.ts b/src/integrations/index.ts
index 78a10ae..d70ed6c 100644
--- a/src/integrations/index.ts
+++ b/src/integrations/index.ts
@@ -20,3 +20,4 @@ export {
} from './mcp/index.js';
export { launchChatSession } from './chat.js';
export { detectInstalledPlugins, prepareIde, installPlugin } from './plugins.js';
+export { normalizeStatusLine } from './utils.js';
diff --git a/src/integrations/utils.ts b/src/integrations/utils.ts
new file mode 100644
index 0000000..35312f2
--- /dev/null
+++ b/src/integrations/utils.ts
@@ -0,0 +1,5 @@
+import { STATUS_PREFIX } from './constants.js';
+
+export function normalizeStatusLine(line: string) {
+ return line.startsWith(STATUS_PREFIX) ? line.slice(STATUS_PREFIX.length) : line;
+}
diff --git a/src/lib/onboarding-prompt/steps/rules.md b/src/lib/onboarding-prompt/steps/rules.md
index 96f6e0a..72d7832 100644
--- a/src/lib/onboarding-prompt/steps/rules.md
+++ b/src/lib/onboarding-prompt/steps/rules.md
@@ -1,6 +1,7 @@
## Rules
-- Prefix every progress update with "STATUS: " (e.g. "STATUS: Scanning for existing flag usage...", "STATUS: Installing dependencies..."). Print these before each step AND periodically within longer steps so the user sees what you're working on. Keep STATUS text short (~60 characters max). Only STATUS-prefixed lines are shown in the UI; everything else is logged silently.
+- Prefix every progress update with "STATUS: " if it isn't prefixed already (e.g. "STATUS: Scanning for existing flag usage...", "STATUS: Installing dependencies..."). Print these before each step AND periodically within longer steps so the user sees what you're working on because STATUS-prefixed lines are shown in the UI; everything else is logged silently.
+- Keep STATUS text short **(~60 characters max)**.
- Never show raw JSON payloads, MCP tool names, or secrets in output.
- Read the client secret from CONFIDENCE_CLIENT_SECRET env var in all generated code.
- Use the OpenFeature API with local resolve where supported. Access flag values via dot notation: `flag-name.property`.
diff --git a/src/ui/tui/screens/done/DoneScreen.tsx b/src/ui/tui/screens/done/DoneScreen.tsx
index aad03ee..28dff92 100644
--- a/src/ui/tui/screens/done/DoneScreen.tsx
+++ b/src/ui/tui/screens/done/DoneScreen.tsx
@@ -20,17 +20,27 @@ export function DoneScreen() {
const narrow = useIsNarrow();
const { reportFile, codeChanges, projectDir, ide } = session;
const align = narrow ? HAlign.Left : HAlign.Center;
+ const skipped = codeChanges.length === 0;
return (
-
- {Icons.check} Confidence is ready!
+
+ {skipped ? Icons.diamond : Icons.check}{' '}
+ {skipped ? 'Onboarding skipped' : 'Confidence is ready!'}
- {codeChanges.length > 0 && !isShort && (
+ {skipped && !isShort && (
+
+
+ You can always use Confidence AI plugin to run onboarding yourself later.
+
+
+ )}
+
+ {!skipped && !isShort && (
<>
What we have set up:
diff --git a/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts b/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts
index 49ce585..293fe0e 100644
--- a/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts
+++ b/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts
@@ -3,7 +3,7 @@ import { type ChildProcess } from 'node:child_process';
import { buildOnboardingPrompt } from '@lib/onboarding-prompt/index.js';
import { detectFramework } from '@frameworks/index.js';
import { ScreenId, type OnboardingGoal } from '@lib/session.js';
-import { type IdeId, getIntegration } from '@integrations/index.js';
+import { type IdeId, getIntegration, normalizeStatusLine } from '@integrations/index.js';
import type { DetectedProvider } from '@providers/types.js';
import { useLogger } from '../../hooks/useLog.js';
import { $session, store, isStaleSession } from '../../store.js';
@@ -61,10 +61,12 @@ export function useOnboardingProcess(): OnboardingProcess {
store.setReportFile('CONFIDENCE_QUICKSTART.md');
store.setCodeChanges(
lines
- ? lines.filter(
- (line) =>
- line.includes('Created') || line.includes('Modified') || line.includes('Added'),
- )
+ ? lines
+ .filter(
+ (line) =>
+ line.includes('Created') || line.includes('Modified') || line.includes('Added'),
+ )
+ .map(normalizeStatusLine)
: dryRunCodeChanges(goal),
);
setPhase('done');