diff --git a/code/core/src/cli/globalSettings.ts b/code/core/src/cli/globalSettings.ts
index 935944795daa..6dcc016e92ba 100644
--- a/code/core/src/cli/globalSettings.ts
+++ b/code/core/src/cli/globalSettings.ts
@@ -29,7 +29,7 @@ const userSettingSchema = z.object({
items: z
.object({
accessibilityTests: statusValue,
- aiPrepare: statusValue,
+ aiSetup: statusValue,
autodocs: statusValue,
ciTests: statusValue,
controls: statusValue,
diff --git a/code/core/src/core-events/index.ts b/code/core/src/core-events/index.ts
index 8126f8a158ea..b988a366256d 100644
--- a/code/core/src/core-events/index.ts
+++ b/code/core/src/core-events/index.ts
@@ -91,9 +91,9 @@ enum events {
// Story discovery and testing flow
GHOST_STORIES_REQUEST = 'ghostStoriesRequest',
GHOST_STORIES_RESPONSE = 'ghostStoriesResponse',
- // AI analytics - ai prepare command
- AI_PREPARE_ANALYTICS_RESPONSE = 'aiPrepareAnalyticsResponse',
- AI_PREPARE_ANALYTICS_REQUEST = 'aiPrepareAnalyticsRequest',
+ // AI analytics - ai setup command
+ AI_SETUP_ANALYTICS_RESPONSE = 'aiSetupAnalyticsResponse',
+ AI_SETUP_ANALYTICS_REQUEST = 'aiSetupAnalyticsRequest',
// Open a file in the code editor
OPEN_IN_EDITOR_REQUEST = 'openInEditorRequest',
OPEN_IN_EDITOR_RESPONSE = 'openInEditorResponse',
@@ -173,8 +173,8 @@ export const {
ARGTYPES_INFO_RESPONSE,
GHOST_STORIES_REQUEST,
GHOST_STORIES_RESPONSE,
- AI_PREPARE_ANALYTICS_RESPONSE,
- AI_PREPARE_ANALYTICS_REQUEST,
+ AI_SETUP_ANALYTICS_RESPONSE,
+ AI_SETUP_ANALYTICS_REQUEST,
OPEN_IN_EDITOR_REQUEST,
OPEN_IN_EDITOR_RESPONSE,
MANAGER_INERT_ATTRIBUTE_CHANGED,
diff --git a/code/core/src/core-server/presets/common-preset.ts b/code/core/src/core-server/presets/common-preset.ts
index b534317e022e..d4fded28c652 100644
--- a/code/core/src/core-server/presets/common-preset.ts
+++ b/code/core/src/core-server/presets/common-preset.ts
@@ -41,7 +41,7 @@ import { initializeSaveStory } from '../utils/save-story/save-story.ts';
import { parseStaticDir } from '../utils/server-statics.ts';
import { type OptionsWithRequiredCache, initializeWhatsNew } from '../utils/whats-new.ts';
import { getWsToken } from './wsToken.ts';
-import { initAIAnalyticsChannel } from '../server-channel/ai-prepare-channel.ts';
+import { initAIAnalyticsChannel } from '../server-channel/ai-setup-channel.ts';
const interpolate = (string: string, data: Record = {}) =>
Object.entries(data).reduce((acc, [k, v]) => acc.replace(new RegExp(`%${k}%`, 'g'), v), string);
diff --git a/code/core/src/core-server/server-channel/ai-prepare-channel.ts b/code/core/src/core-server/server-channel/ai-setup-channel.ts
similarity index 76%
rename from code/core/src/core-server/server-channel/ai-prepare-channel.ts
rename to code/core/src/core-server/server-channel/ai-setup-channel.ts
index 0c08fed0f8d4..f5a45f9b1667 100644
--- a/code/core/src/core-server/server-channel/ai-prepare-channel.ts
+++ b/code/core/src/core-server/server-channel/ai-setup-channel.ts
@@ -1,12 +1,12 @@
import type { Channel } from 'storybook/internal/channels';
import {
- AI_PREPARE_ANALYTICS_REQUEST,
- AI_PREPARE_ANALYTICS_RESPONSE,
+ AI_SETUP_ANALYTICS_REQUEST,
+ AI_SETUP_ANALYTICS_RESPONSE,
} from 'storybook/internal/core-events';
import {
getLastEvents,
getStorybookMetadata,
- isStoryCreatedByAIPrepare,
+ isStoryCreatedByAISetup,
telemetry,
} from 'storybook/internal/telemetry';
import type { CoreConfig, Options } from 'storybook/internal/types';
@@ -26,8 +26,8 @@ export function initAIAnalyticsChannel(
return channel;
}
- /** Send analytics about the ai prepare workflow when requested*/
- channel.on(AI_PREPARE_ANALYTICS_REQUEST, async () => {
+ /** Send analytics about the ai setup workflow when requested*/
+ channel.on(AI_SETUP_ANALYTICS_REQUEST, async () => {
const stats: {
fileCount?: number;
storyCount?: number;
@@ -36,16 +36,16 @@ export function initAIAnalyticsChannel(
try {
const lastEvents = await getLastEvents();
- const lastAIPrepare = lastEvents?.['ai-prepare'];
- const lastPrepareStoryScoringRun = lastEvents?.['ai-prepare-story-scoring'];
+ const lastAISetup = lastEvents?.['ai-setup'];
+ const lastSetupStoryScoringRun = lastEvents?.['ai-setup-story-scoring'];
- // Only run if sb ai prepare has been called
- if (!lastAIPrepare) {
+ // Only run if sb ai setup has been called
+ if (!lastAISetup) {
return;
}
// Already ran once for this project — never run again
- if (lastPrepareStoryScoringRun) {
+ if (lastSetupStoryScoringRun) {
return;
}
@@ -66,7 +66,7 @@ export function initAIAnalyticsChannel(
// disturb end user activities.
const isIdle = await waitForIdleVitest();
if (!isIdle) {
- logger.debug('AI_PREPARE_ANALYTICS_REQUEST timed out waiting for vitest to be available.');
+ logger.debug('AI_SETUP_ANALYTICS_REQUEST timed out waiting for vitest to be available.');
return;
}
@@ -74,7 +74,7 @@ export function initAIAnalyticsChannel(
const generatorPromise = getStoryIndexGeneratorPromise?.();
if (!generatorPromise) {
logger.debug(
- 'AI_PREPARE_ANALYTICS_REQUEST could not proceed as the index generator is not ready.'
+ 'AI_SETUP_ANALYTICS_REQUEST could not proceed as the index generator is not ready.'
);
return;
}
@@ -82,14 +82,14 @@ export function initAIAnalyticsChannel(
const generator = await generatorPromise;
const indexAndStats = await generator.getIndexAndStats();
if (!indexAndStats) {
- logger.debug('AI_PREPARE_ANALYTICS_REQUEST could not proceed as the index is not ready.');
+ logger.debug('AI_SETUP_ANALYTICS_REQUEST could not proceed as the index is not ready.');
return;
}
const aiStoryFiles = new Set();
let aiStoryCount = 0;
for (const entry of Object.values(indexAndStats.storyIndex.entries)) {
- if (isStoryCreatedByAIPrepare(entry)) {
+ if (isStoryCreatedByAISetup(entry)) {
aiStoryFiles.add(entry.importPath);
aiStoryCount++;
}
@@ -97,7 +97,7 @@ export function initAIAnalyticsChannel(
if (aiStoryFiles.size > 0) {
const aiTestRunResult = await runGhostStories([...aiStoryFiles]);
- telemetry('ai-prepare-story-scoring', {
+ telemetry('ai-setup-story-scoring', {
stats: {
fileCount: aiStoryFiles.size,
storyCount: aiStoryCount,
@@ -107,7 +107,7 @@ export function initAIAnalyticsChannel(
...(aiTestRunResult.runError ? { runError: aiTestRunResult.runError } : {}),
});
} else {
- telemetry('ai-prepare-story-scoring', {
+ telemetry('ai-setup-story-scoring', {
stats: {
fileCount: 0,
storyCount: 0,
@@ -117,13 +117,13 @@ export function initAIAnalyticsChannel(
});
}
} catch {
- telemetry('ai-prepare-story-scoring', {
+ telemetry('ai-setup-story-scoring', {
stats,
runError: 'Unknown error during AI story scoring',
});
} finally {
// we don't currently do anything with this, but will be useful in the future
- channel.emit(AI_PREPARE_ANALYTICS_RESPONSE);
+ channel.emit(AI_SETUP_ANALYTICS_RESPONSE);
}
});
diff --git a/code/core/src/core-server/server-channel/ghost-stories-channel.ts b/code/core/src/core-server/server-channel/ghost-stories-channel.ts
index e09f574b6eb9..157d0144990c 100644
--- a/code/core/src/core-server/server-channel/ghost-stories-channel.ts
+++ b/code/core/src/core-server/server-channel/ghost-stories-channel.ts
@@ -38,11 +38,11 @@ export function initGhostStoriesChannel(
const ghostRunStart = Date.now();
const lastEvents = await getLastEvents();
const lastInit = lastEvents?.init;
- const lastAIPrepare = lastEvents?.['ai-prepare'];
+ const lastAISetup = lastEvents?.['ai-setup'];
const lastGhostStoriesRun = lastEvents?.['ghost-stories'];
- // We only want to run ghost stories immediately after init or ai prepare.
- const lastRelevantEvent = lastAIPrepare ?? lastInit;
+ // We only want to run ghost stories immediately after init or ai setup.
+ const lastRelevantEvent = lastAISetup ?? lastInit;
if (!lastRelevantEvent) {
return;
}
@@ -53,7 +53,7 @@ export function initGhostStoriesChannel(
}
const sessionId = await getSessionId();
- // We only capture ghost stories in the first ever session since init or ai prepare.
+ // We only capture ghost stories in the first ever session since init or ai setup.
if (lastRelevantEvent.body?.sessionId && lastRelevantEvent.body.sessionId !== sessionId) {
return;
}
diff --git a/code/core/src/core-server/utils/checklist.test.ts b/code/core/src/core-server/utils/checklist.test.ts
index 72dcb363e990..c961d83c5828 100644
--- a/code/core/src/core-server/utils/checklist.test.ts
+++ b/code/core/src/core-server/utils/checklist.test.ts
@@ -69,7 +69,7 @@ describe('initializeChecklist', () => {
} as unknown as Awaited>);
});
- it('keeps aiPrepare as open when no ai-prepare event exists in cache', async () => {
+ it('keeps aiSetup as open when no ai-setup event exists in cache', async () => {
const { get: getEventCacheEntry } = await import('../../telemetry/event-cache.ts');
vi.mocked(getEventCacheEntry).mockResolvedValue(undefined);
@@ -77,41 +77,41 @@ describe('initializeChecklist', () => {
await initializeChecklist();
const state = mockStore.getState();
- expect(state.items.aiPrepare.status).toBe('open');
+ expect(state.items.aiSetup.status).toBe('open');
});
- it('marks aiPrepare as done when ai-prepare event exists in cache', async () => {
+ it('marks aiSetup as done when ai-setup event exists in cache', async () => {
const { get: getEventCacheEntry } = await import('../../telemetry/event-cache.ts');
vi.mocked(getEventCacheEntry).mockResolvedValue({
timestamp: Date.now(),
- body: { eventType: 'ai-prepare' } as TelemetryEvent,
+ body: { eventType: 'ai-setup' } as TelemetryEvent,
} satisfies CacheEntry);
const { initializeChecklist } = await import('./checklist.ts');
await initializeChecklist();
const state = mockStore.getState();
- expect(state.items.aiPrepare.status).toBe('done');
+ expect(state.items.aiSetup.status).toBe('done');
});
- it('does not overwrite aiPrepare status if already done from persisted state', async () => {
- // Simulate persisted user state where aiPrepare is already 'skipped'
+ it('does not overwrite aiSetup status if already done from persisted state', async () => {
+ // Simulate persisted user state where aiSetup is already 'skipped'
mockSettingsValue.checklist = {
- items: { aiPrepare: { status: 'skipped' } },
+ items: { aiSetup: { status: 'skipped' } },
widget: {},
};
const { get: getEventCacheEntry } = await import('../../telemetry/event-cache.ts');
vi.mocked(getEventCacheEntry).mockResolvedValue({
timestamp: Date.now(),
- body: { eventType: 'ai-prepare' } as TelemetryEvent,
+ body: { eventType: 'ai-setup' } as TelemetryEvent,
} satisfies CacheEntry);
const { initializeChecklist } = await import('./checklist.ts');
await initializeChecklist();
const state = mockStore.getState();
- // The ai-prepare event was found, but status was 'skipped' (not 'open'), so it stays 'skipped'
- expect(state.items.aiPrepare.status).toBe('skipped');
+ // The ai-setup event was found, but status was 'skipped' (not 'open'), so it stays 'skipped'
+ expect(state.items.aiSetup.status).toBe('skipped');
});
});
diff --git a/code/core/src/core-server/utils/checklist.ts b/code/core/src/core-server/utils/checklist.ts
index fbc8fdb9781a..53f939ad5b52 100644
--- a/code/core/src/core-server/utils/checklist.ts
+++ b/code/core/src/core-server/utils/checklist.ts
@@ -63,14 +63,14 @@ export async function initializeChecklist() {
}) satisfies StoreState
);
- // Check if ai-prepare has ever been run and mark it as done
- const aiPrepareEvent = await getEventCacheEntry('ai-prepare');
- if (aiPrepareEvent) {
+ // Check if ai-setup has ever been run and mark it as done
+ const aiSetupEvent = await getEventCacheEntry('ai-setup');
+ if (aiSetupEvent) {
const currentState = store.getState();
- if (currentState.items.aiPrepare?.status === 'open') {
+ if (currentState.items.aiSetup?.status === 'open') {
store.setState((state) => ({
...state,
- items: { ...state.items, aiPrepare: { ...state.items.aiPrepare, status: 'done' } },
+ items: { ...state.items, aiSetup: { ...state.items.aiSetup, status: 'done' } },
}));
}
}
diff --git a/code/core/src/core-server/utils/doTelemetry.ts b/code/core/src/core-server/utils/doTelemetry.ts
index f1b3374ee2aa..7196568efa08 100644
--- a/code/core/src/core-server/utils/doTelemetry.ts
+++ b/code/core/src/core-server/utils/doTelemetry.ts
@@ -1,5 +1,5 @@
import {
- collectAiPrepareEvidence,
+ collectAiSetupEvidence,
getPrecedingUpgrade,
telemetry,
} from 'storybook/internal/telemetry';
@@ -45,7 +45,7 @@ export async function doTelemetry(
// directly. This is the entry point for collecting evidence about those side effects and
// recording them in telemetry.
if (indexAndStats) {
- collectAiPrepareEvidence('dev', options.configDir, indexAndStats.storyIndex);
+ collectAiSetupEvidence('dev', options.configDir, indexAndStats.storyIndex);
}
const { versionCheck, versionUpdates } = options;
diff --git a/code/core/src/core-server/withTelemetry.test.ts b/code/core/src/core-server/withTelemetry.test.ts
index 622b9c738738..e39a63ebcef0 100644
--- a/code/core/src/core-server/withTelemetry.test.ts
+++ b/code/core/src/core-server/withTelemetry.test.ts
@@ -4,7 +4,7 @@ import { cache, isCI, loadAllPresets } from 'storybook/internal/common';
import { prompt } from 'storybook/internal/node-logger';
import {
ErrorCollector,
- collectAiPrepareEvidence,
+ collectAiSetupEvidence,
oneWayHash,
telemetry,
} from 'storybook/internal/telemetry';
@@ -34,7 +34,7 @@ describe('withTelemetry', () => {
vi.resetAllMocks();
vi.mocked(ErrorCollector.getErrors).mockReturnValue([]);
vi.mocked(telemetry).mockResolvedValue(undefined);
- vi.mocked(collectAiPrepareEvidence).mockResolvedValue(undefined);
+ vi.mocked(collectAiSetupEvidence).mockResolvedValue(undefined);
});
it('works in happy path', async () => {
const run = vi.fn();
@@ -42,7 +42,7 @@ describe('withTelemetry', () => {
await withTelemetry('dev', { cliOptions }, run);
expect(telemetry).toHaveBeenCalledTimes(1);
- expect(collectAiPrepareEvidence).toHaveBeenCalledTimes(1);
+ expect(collectAiSetupEvidence).toHaveBeenCalledTimes(1);
expect(telemetry).toHaveBeenCalledWith('boot', { eventType: 'dev' }, { stripMetadata: true });
});
@@ -52,7 +52,7 @@ describe('withTelemetry', () => {
await withTelemetry('dev', { cliOptions: { disableTelemetry: true } }, run);
expect(telemetry).toHaveBeenCalledTimes(0);
- expect(collectAiPrepareEvidence).toHaveBeenCalledTimes(0);
+ expect(collectAiSetupEvidence).toHaveBeenCalledTimes(0);
});
describe('when command fails', () => {
@@ -67,7 +67,7 @@ describe('withTelemetry', () => {
).rejects.toThrow(error);
expect(telemetry).toHaveBeenCalledWith('boot', { eventType: 'dev' }, { stripMetadata: true });
- expect(collectAiPrepareEvidence).toHaveBeenCalledTimes(1);
+ expect(collectAiSetupEvidence).toHaveBeenCalledTimes(1);
});
it('does not send boot when cli option is passed', async () => {
@@ -76,7 +76,7 @@ describe('withTelemetry', () => {
).rejects.toThrow(error);
expect(telemetry).toHaveBeenCalledTimes(0);
- expect(collectAiPrepareEvidence).toHaveBeenCalledTimes(0);
+ expect(collectAiSetupEvidence).toHaveBeenCalledTimes(0);
});
it('sends error message when no options are passed', async () => {
@@ -85,7 +85,7 @@ describe('withTelemetry', () => {
).rejects.toThrow(error);
expect(telemetry).toHaveBeenCalledTimes(2);
- expect(collectAiPrepareEvidence).toHaveBeenCalledTimes(1);
+ expect(collectAiSetupEvidence).toHaveBeenCalledTimes(1);
expect(telemetry).toHaveBeenCalledWith(
'error',
expect.objectContaining({
@@ -149,7 +149,7 @@ describe('withTelemetry', () => {
).rejects.toThrow(error);
expect(telemetry).toHaveBeenCalledTimes(0);
- expect(collectAiPrepareEvidence).toHaveBeenCalledTimes(0);
+ expect(collectAiSetupEvidence).toHaveBeenCalledTimes(0);
expect(telemetry).not.toHaveBeenCalledWith(
'error',
expect.objectContaining({}),
diff --git a/code/core/src/core-server/withTelemetry.ts b/code/core/src/core-server/withTelemetry.ts
index 9903e34fc0a3..81162aaf900c 100644
--- a/code/core/src/core-server/withTelemetry.ts
+++ b/code/core/src/core-server/withTelemetry.ts
@@ -1,7 +1,7 @@
import { HandledError, cache, isCI, loadAllPresets } from 'storybook/internal/common';
import { logger, prompt } from 'storybook/internal/node-logger';
import {
- collectAiPrepareEvidence,
+ collectAiSetupEvidence,
ErrorCollector,
getPrecedingUpgrade,
oneWayHash,
@@ -189,7 +189,7 @@ export async function withTelemetry(
if (enableTelemetry) {
// Fire-and-forget: don't await, don't block the command
const configDir = options.cliOptions.configDir || options.presetOptions?.configDir;
- collectAiPrepareEvidence(eventType, configDir);
+ collectAiSetupEvidence(eventType, configDir);
}
try {
diff --git a/code/core/src/manager/components/sidebar/ChecklistWidget.stories.tsx b/code/core/src/manager/components/sidebar/ChecklistWidget.stories.tsx
index 159204f39ec6..0783b17fe21f 100644
--- a/code/core/src/manager/components/sidebar/ChecklistWidget.stories.tsx
+++ b/code/core/src/manager/components/sidebar/ChecklistWidget.stories.tsx
@@ -95,14 +95,14 @@ export const Narrow = meta.story({
play,
});
-export const WithAiPrepare = meta.story({
+export const WithAiSetup = meta.story({
beforeEach: async () => {
mockStore.setState({
loaded: true,
widget: {},
items: {
...initialState.items,
- // aiPrepare is intentionally left 'open' so it appears in the widget's task list
+ // aiSetup is intentionally left 'open' so it appears in the widget's task list
controls: { status: 'accepted' },
renderComponent: { status: 'done' },
},
diff --git a/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.test.ts b/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.test.ts
index cb10dba6793e..f08f92153bb9 100644
--- a/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.test.ts
+++ b/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.test.ts
@@ -3,7 +3,7 @@ import { renderHook } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import {
- AI_PREPARE_ANALYTICS_REQUEST,
+ AI_SETUP_ANALYTICS_REQUEST,
GHOST_STORIES_REQUEST,
PREVIEW_INITIALIZED,
} from 'storybook/internal/core-events';
@@ -66,7 +66,7 @@ describe('useDelayedAnalyticsTrigger', () => {
expect(api.emit).not.toHaveBeenCalled();
});
- it('emits GHOST_STORIES_REQUEST and AI_PREPARE_ANALYTICS_REQUEST after delay', () => {
+ it('emits GHOST_STORIES_REQUEST and AI_SETUP_ANALYTICS_REQUEST after delay', () => {
const api = createMockApi();
mockUseStorybookApi.mockReturnValue(api as any);
@@ -78,7 +78,7 @@ describe('useDelayedAnalyticsTrigger', () => {
vi.advanceTimersByTime(4 * 60 * 1000);
expect(api.emit).toHaveBeenCalledWith(GHOST_STORIES_REQUEST);
- expect(api.emit).toHaveBeenCalledWith(AI_PREPARE_ANALYTICS_REQUEST);
+ expect(api.emit).toHaveBeenCalledWith(AI_SETUP_ANALYTICS_REQUEST);
expect(api.emit).toHaveBeenCalledTimes(2);
});
diff --git a/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.ts b/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.ts
index 9458a5eaf642..d9a16706c275 100644
--- a/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.ts
+++ b/code/core/src/manager/components/sidebar/useDelayedAnalyticsTrigger.ts
@@ -1,7 +1,7 @@
import { useEffect, useRef } from 'react';
import {
- AI_PREPARE_ANALYTICS_REQUEST,
+ AI_SETUP_ANALYTICS_REQUEST,
GHOST_STORIES_REQUEST,
PREVIEW_INITIALIZED,
} from 'storybook/internal/core-events';
@@ -33,12 +33,12 @@ export function useDelayedAnalyticsTrigger(): void {
}
fired.current = true;
- // if `ai prepare` is in the same session, we run ghost stories and ai prepare analytics.
+ // if `ai setup` is in the same session, we run ghost stories and ai setup analytics.
if (
- global.STORYBOOK_LAST_EVENTS?.['ai-prepare']?.body.sessionId === global.STORYBOOK_SESSION_ID
+ global.STORYBOOK_LAST_EVENTS?.['ai-setup']?.body.sessionId === global.STORYBOOK_SESSION_ID
) {
api.emit(GHOST_STORIES_REQUEST);
- api.emit(AI_PREPARE_ANALYTICS_REQUEST);
+ api.emit(AI_SETUP_ANALYTICS_REQUEST);
}
};
diff --git a/code/core/src/manager/globals/exports.ts b/code/core/src/manager/globals/exports.ts
index c6df44d8b486..29dc2b59f4f4 100644
--- a/code/core/src/manager/globals/exports.ts
+++ b/code/core/src/manager/globals/exports.ts
@@ -574,9 +574,9 @@ export default {
'withReset',
],
'storybook/internal/core-events': [
- 'AI_PREPARE_ANALYTICS_REQUEST',
- 'AI_PREPARE_ANALYTICS_RESPONSE',
'AI_PROMPT_NUDGE',
+ 'AI_SETUP_ANALYTICS_REQUEST',
+ 'AI_SETUP_ANALYTICS_RESPONSE',
'ARGTYPES_INFO_REQUEST',
'ARGTYPES_INFO_RESPONSE',
'CHANNEL_CREATED',
diff --git a/code/core/src/manager/settings/Checklist/AiSetupBlock.stories.tsx b/code/core/src/manager/settings/Checklist/AiSetupBlock.stories.tsx
index 4baa70c22c60..8cad1b1341d2 100644
--- a/code/core/src/manager/settings/Checklist/AiSetupBlock.stories.tsx
+++ b/code/core/src/manager/settings/Checklist/AiSetupBlock.stories.tsx
@@ -23,14 +23,14 @@ const managerContext: any = {
},
};
-// Get the raw aiPrepare item. Cast through unknown to avoid deep discriminated-union issues
+// Get the raw aiSetup item. Cast through unknown to avoid deep discriminated-union issues
// with the as-const typed checklistData — the shape is correct at runtime.
-const rawAiPrepareItem = checklistData.sections
+const rawAiSetupItem = checklistData.sections
.flatMap((s) => s.items as unknown as ChecklistItem[])
- .find((item) => item.id === 'aiPrepare')!;
+ .find((item) => item.id === 'aiSetup')!;
const makeItem = (overrides: Partial = {}): ChecklistItem => ({
- ...rawAiPrepareItem,
+ ...rawAiSetupItem,
itemIndex: 0,
sectionId: 'basics',
sectionIndex: 0,
diff --git a/code/core/src/manager/settings/Checklist/AiSetupBlock.tsx b/code/core/src/manager/settings/Checklist/AiSetupBlock.tsx
index 6d38a3467603..b4f3e3033214 100644
--- a/code/core/src/manager/settings/Checklist/AiSetupBlock.tsx
+++ b/code/core/src/manager/settings/Checklist/AiSetupBlock.tsx
@@ -8,7 +8,7 @@ import { CheckIcon, UndoIcon } from '@storybook/icons';
import { type API, useStorybookApi } from 'storybook/manager-api';
import { styled } from 'storybook/theming';
-import { AI_PREPARE_PROMPT } from '../../../shared/constants/ai-prompts.ts';
+import { AI_SETUP_PROMPT } from '../../../shared/constants/ai-prompts.ts';
import { useCopyButton } from '../../../shared/useCopyButton.ts';
import type { ItemId } from '../../../shared/checklist-store/index.ts';
import type { ChecklistItem } from '../../components/sidebar/useChecklist.ts';
@@ -61,9 +61,9 @@ const CopyButton = ({ api }: { api: API }) => {
Copied!
>
),
- content: AI_PREPARE_PROMPT,
+ content: AI_SETUP_PROMPT,
onCopy: () => {
- api.emit(AI_PROMPT_NUDGE, { id: 'prepare', origin: 'onboarding-guide-page' });
+ api.emit(AI_PROMPT_NUDGE, { id: 'setup', origin: 'onboarding-guide-page' });
},
});
diff --git a/code/core/src/manager/settings/Checklist/Checklist.stories.tsx b/code/core/src/manager/settings/Checklist/Checklist.stories.tsx
index e19cdb66d033..c4381c950ec0 100644
--- a/code/core/src/manager/settings/Checklist/Checklist.stories.tsx
+++ b/code/core/src/manager/settings/Checklist/Checklist.stories.tsx
@@ -84,27 +84,27 @@ export const Default = meta.story({
args: { availableItems, ...checklistStore },
});
-export const WithAiPrepare = meta.story({
+export const WithAiSetup = meta.story({
args: {
availableItems: buildItems({
controls: 'accepted',
renderComponent: 'done',
whatsNewStorybook10: 'done',
viewports: 'skipped',
- // aiPrepare is intentionally omitted → status 'open'
+ // aiSetup is intentionally omitted → status 'open'
}),
...checklistStore,
},
});
-export const WithAiPrepareSkipped = meta.story({
+export const WithAiSetupSkipped = meta.story({
args: {
availableItems: buildItems({
controls: 'accepted',
renderComponent: 'done',
whatsNewStorybook10: 'done',
viewports: 'skipped',
- aiPrepare: 'skipped',
+ aiSetup: 'skipped',
}),
...checklistStore,
},
diff --git a/code/core/src/manager/settings/GuidePage.stories.tsx b/code/core/src/manager/settings/GuidePage.stories.tsx
index 308c252e5711..c617468fdba7 100644
--- a/code/core/src/manager/settings/GuidePage.stories.tsx
+++ b/code/core/src/manager/settings/GuidePage.stories.tsx
@@ -58,7 +58,7 @@ export const AiCtaSkipped = meta.story({
widget: {},
items: {
...initialState.items,
- aiPrepare: { status: 'skipped' },
+ aiSetup: { status: 'skipped' },
controls: { status: 'accepted' },
renderComponent: { status: 'done' },
viewports: { status: 'skipped' },
@@ -74,7 +74,7 @@ export const AiCtaDone = meta.story({
widget: {},
items: {
...initialState.items,
- aiPrepare: { status: 'done' },
+ aiSetup: { status: 'done' },
controls: { status: 'accepted' },
renderComponent: { status: 'done' },
viewports: { status: 'skipped' },
diff --git a/code/core/src/manager/settings/GuidePage.tsx b/code/core/src/manager/settings/GuidePage.tsx
index 6d7d28d9121a..9dae45ec510b 100644
--- a/code/core/src/manager/settings/GuidePage.tsx
+++ b/code/core/src/manager/settings/GuidePage.tsx
@@ -38,7 +38,7 @@ const Intro = styled.div(({ theme }) => ({
export const GuidePage = () => {
const checklist = useChecklist();
- const aiPrepareItem = checklist.availableItems.find((item) => item.id === 'aiPrepare');
+ const aiSetupItem = checklist.availableItems.find((item) => item.id === 'aiSetup');
return (
@@ -49,10 +49,10 @@ export const GuidePage = () => {
will help you make the most of your Storybook.
- {aiPrepareItem && (
-
+ {aiSetupItem && (
+
)}
-
+
{global.FEATURES?.sidebarOnboardingChecklist !== false && (
<>
{checklist.openItems.length === 0 ? (
diff --git a/code/core/src/shared/checklist-store/checklistData.state.ts b/code/core/src/shared/checklist-store/checklistData.state.ts
index 39899531c972..0f85b44b26f9 100644
--- a/code/core/src/shared/checklist-store/checklistData.state.ts
+++ b/code/core/src/shared/checklist-store/checklistData.state.ts
@@ -3,7 +3,7 @@ import type { StoreState } from './index.ts';
export const initialState = {
items: {
accessibilityTests: { status: 'open' },
- aiPrepare: { status: 'open' },
+ aiSetup: { status: 'open' },
autodocs: { status: 'open' },
ciTests: { status: 'open' },
controls: { status: 'open' },
diff --git a/code/core/src/shared/checklist-store/checklistData.tsx b/code/core/src/shared/checklist-store/checklistData.tsx
index 7cc0e02061f9..0be79c578c2a 100644
--- a/code/core/src/shared/checklist-store/checklistData.tsx
+++ b/code/core/src/shared/checklist-store/checklistData.tsx
@@ -35,7 +35,7 @@ import { ADDON_ID as ADDON_DOCS_ID } from '../../docs-tools/shared.ts';
import { TourGuide } from '../../manager/components/TourGuide/TourGuide.tsx';
import { LocationMonitor } from '../../manager/hooks/useLocation.ts';
import type { initialState } from './checklistData.state.ts';
-import { AI_PREPARE_PROMPT } from '../constants/ai-prompts.ts';
+import { AI_SETUP_PROMPT } from '../constants/ai-prompts.ts';
const CodeWrapper = styled.div(({ theme }) => ({
alignSelf: 'stretch',
@@ -163,16 +163,16 @@ export const checklistData = {
title: 'Storybook basics',
items: [
{
- id: 'aiPrepare',
+ id: 'aiSetup',
label: 'Set up with AI',
icon: WandIcon,
- criteria: 'ai prepare command has been run',
+ criteria: 'ai setup command has been run',
showOnGuidePage: false,
action: {
label: 'Copy prompt',
- copyContent: AI_PREPARE_PROMPT,
+ copyContent: AI_SETUP_PROMPT,
onClick: ({ api }) => {
- api.emit(AI_PROMPT_NUDGE, { id: 'prepare', origin: 'onboarding-checklist-side' });
+ api.emit(AI_PROMPT_NUDGE, { id: 'setup', origin: 'onboarding-checklist-side' });
},
},
},
diff --git a/code/core/src/shared/constants/ai-prompts.ts b/code/core/src/shared/constants/ai-prompts.ts
index 245769b65b12..0c1d6f904bd5 100644
--- a/code/core/src/shared/constants/ai-prompts.ts
+++ b/code/core/src/shared/constants/ai-prompts.ts
@@ -2,4 +2,4 @@
* Source of truth for AI prompts throughout the application.
*/
-export const AI_PREPARE_PROMPT = `Run \`npx storybook ai prepare\` and follow its instructions precisely.`;
+export const AI_SETUP_PROMPT = `Run \`npx storybook ai setup\` and follow its instructions precisely.`;
diff --git a/code/core/src/telemetry/ai-prepare-utils.test.ts b/code/core/src/telemetry/ai-setup-utils.test.ts
similarity index 86%
rename from code/core/src/telemetry/ai-prepare-utils.test.ts
rename to code/core/src/telemetry/ai-setup-utils.test.ts
index afd0384fcd03..184f34c1cfb3 100644
--- a/code/core/src/telemetry/ai-prepare-utils.test.ts
+++ b/code/core/src/telemetry/ai-setup-utils.test.ts
@@ -4,10 +4,10 @@ import type { IndexEntry, StoryIndex } from 'storybook/internal/types';
import {
checkPreviewChanged,
- collectAiPrepareEvidence,
+ collectAiSetupEvidence,
countAiAuthoredStories,
- isStoryCreatedByAIPrepare,
-} from './ai-prepare-utils.ts';
+ isStoryCreatedByAISetup,
+} from './ai-setup-utils.ts';
// Mock modules with spy pattern
vi.mock('storybook/internal/common', async (importOriginal) => {
@@ -26,7 +26,7 @@ vi.mock('./event-cache.ts', async (importOriginal) => {
const actual = await importOriginal();
return {
...actual,
- getAiPreparePending: vi.fn(() => undefined),
+ getAiSetupPending: vi.fn(() => undefined),
};
});
@@ -42,7 +42,7 @@ vi.mock('./index.ts', async (importOriginal) => {
import { findConfigFile } from 'storybook/internal/common';
import { readFile } from 'node:fs/promises';
import { detectAgent } from './detect-agent.ts';
-import { getAiPreparePending } from './event-cache.ts';
+import { getAiSetupPending } from './event-cache.ts';
import { SESSION_TIMEOUT } from './session-id.ts';
import { telemetry } from './index.ts';
@@ -73,10 +73,10 @@ beforeEach(() => {
vi.mocked(telemetry).mockResolvedValue(undefined);
});
-describe('isStoryCreatedByAIPrepare', () => {
+describe('isStoryCreatedByAISetup', () => {
it('returns true for stories with the ai-generated tag', () => {
expect(
- isStoryCreatedByAIPrepare({
+ isStoryCreatedByAISetup({
type: 'story',
title: 'Foo',
tags: ['ai-generated', 'dev', 'play-fn'],
@@ -85,7 +85,7 @@ describe('isStoryCreatedByAIPrepare', () => {
});
it('returns false for regular stories', () => {
- expect(isStoryCreatedByAIPrepare({ type: 'story', title: 'Foo' } as IndexEntry)).toBe(false);
+ expect(isStoryCreatedByAISetup({ type: 'story', title: 'Foo' } as IndexEntry)).toBe(false);
});
});
@@ -192,53 +192,53 @@ describe('checkPreviewChanged', () => {
});
});
-describe('collectAiPrepareEvidence', () => {
+describe('collectAiSetupEvidence', () => {
it('does not fire when no agent detected', async () => {
vi.mocked(detectAgent).mockReturnValue(undefined);
- await collectAiPrepareEvidence('dev', '/test/config');
+ await collectAiSetupEvidence('dev', '/test/config');
expect(telemetry).not.toHaveBeenCalled();
});
it('does not fire when no pending record', async () => {
vi.mocked(detectAgent).mockReturnValue({ name: 'claude' });
- vi.mocked(getAiPreparePending).mockResolvedValue(undefined);
+ vi.mocked(getAiSetupPending).mockResolvedValue(undefined);
- await collectAiPrepareEvidence('dev', '/test/config');
+ await collectAiSetupEvidence('dev', '/test/config');
expect(telemetry).not.toHaveBeenCalled();
});
it('does not fire when pending record is expired', async () => {
vi.mocked(detectAgent).mockReturnValue({ name: 'claude' });
- vi.mocked(getAiPreparePending).mockResolvedValue(
+ vi.mocked(getAiSetupPending).mockResolvedValue(
makePendingRecord({ timestamp: Date.now() - SESSION_TIMEOUT - 1000 })
);
- await collectAiPrepareEvidence('dev', '/test/config');
+ await collectAiSetupEvidence('dev', '/test/config');
expect(telemetry).not.toHaveBeenCalled();
});
it('does not fire when configDir does not match', async () => {
vi.mocked(detectAgent).mockReturnValue({ name: 'claude' });
- vi.mocked(getAiPreparePending).mockResolvedValue(
+ vi.mocked(getAiSetupPending).mockResolvedValue(
makePendingRecord({ configDir: '/other/project/.storybook' })
);
- await collectAiPrepareEvidence('dev', '/test/config');
+ await collectAiSetupEvidence('dev', '/test/config');
expect(telemetry).not.toHaveBeenCalled();
});
it('fires event with correct payload when all gates pass', async () => {
vi.mocked(detectAgent).mockReturnValue({ name: 'claude' });
const pending = makePendingRecord({ configDir: '/test/config' });
- vi.mocked(getAiPreparePending).mockResolvedValue(pending);
+ vi.mocked(getAiSetupPending).mockResolvedValue(pending);
vi.mocked(findConfigFile).mockReturnValue(pending.previewPath);
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
- await collectAiPrepareEvidence('dev', '/test/config');
+ await collectAiSetupEvidence('dev', '/test/config');
expect(telemetry).toHaveBeenCalledWith(
- 'ai-prepare-evidence',
+ 'ai-setup-evidence',
expect.objectContaining({
previewChanged: true,
aiAuthoredStories: undefined,
@@ -254,13 +254,13 @@ describe('collectAiPrepareEvidence', () => {
it('reports aiAuthoredStories as undefined when no story index provided', async () => {
vi.mocked(detectAgent).mockReturnValue({ name: 'claude' });
const pending = makePendingRecord({ configDir: '/test/config' });
- vi.mocked(getAiPreparePending).mockResolvedValue(pending);
+ vi.mocked(getAiSetupPending).mockResolvedValue(pending);
vi.mocked(findConfigFile).mockReturnValue(null);
- await collectAiPrepareEvidence('dev', '/test/config');
+ await collectAiSetupEvidence('dev', '/test/config');
expect(telemetry).toHaveBeenCalledWith(
- 'ai-prepare-evidence',
+ 'ai-setup-evidence',
expect.objectContaining({
aiAuthoredStories: undefined,
}),
@@ -275,7 +275,7 @@ describe('collectAiPrepareEvidence', () => {
previewFile: null,
previewHash: null,
});
- vi.mocked(getAiPreparePending).mockResolvedValue(pending);
+ vi.mocked(getAiSetupPending).mockResolvedValue(pending);
vi.mocked(findConfigFile).mockReturnValue(null);
const storyIndex = makeStoryIndex({
@@ -296,10 +296,10 @@ describe('collectAiPrepareEvidence', () => {
},
});
- await collectAiPrepareEvidence('dev', '/test/config', storyIndex);
+ await collectAiSetupEvidence('dev', '/test/config', storyIndex);
expect(telemetry).toHaveBeenCalledWith(
- 'ai-prepare-evidence',
+ 'ai-setup-evidence',
expect.objectContaining({
aiAuthoredStories: 1,
}),
diff --git a/code/core/src/telemetry/ai-prepare-utils.ts b/code/core/src/telemetry/ai-setup-utils.ts
similarity index 81%
rename from code/core/src/telemetry/ai-prepare-utils.ts
rename to code/core/src/telemetry/ai-setup-utils.ts
index 203c744c97d4..fac23a2098a8 100644
--- a/code/core/src/telemetry/ai-prepare-utils.ts
+++ b/code/core/src/telemetry/ai-setup-utils.ts
@@ -1,4 +1,4 @@
-import { flushAiPreparePending, getAiPreparePending } from './event-cache.ts';
+import { flushAiSetupPending, getAiSetupPending } from './event-cache.ts';
import { SESSION_TIMEOUT } from './session-id.ts';
import { createHash } from 'node:crypto';
import { readFile } from 'node:fs/promises';
@@ -10,19 +10,19 @@ import type { EventType } from './types.ts';
import type { IndexEntry, StoryIndex } from 'storybook/internal/types';
/**
- * Determines whether a story index entry was authored by the `sb ai prepare` flow.
+ * Determines whether a story index entry was authored by the `sb ai setup` flow.
* Currently checks title prefix. When we migrate to a tag-based approach,
* swap this to check for the tag instead — this is the single swap point.
*/
-export function isStoryCreatedByAIPrepare(entry: IndexEntry): boolean {
+export function isStoryCreatedByAISetup(entry: IndexEntry): boolean {
return entry.type === 'story' && (entry.tags?.includes('ai-generated') ?? false);
}
/**
- * Count stories in the index that were created by `sb ai prepare`.
+ * Count stories in the index that were created by `sb ai setup`.
*/
export function countAiAuthoredStories(storyIndex: StoryIndex): number {
- return Object.values(storyIndex.entries).filter(isStoryCreatedByAIPrepare).length;
+ return Object.values(storyIndex.entries).filter(isStoryCreatedByAISetup).length;
}
/**
@@ -48,7 +48,7 @@ export async function snapshotPreviewFile(
}
/**
- * Check whether the preview file has changed from an ai-prepare baseline.
+ * Check whether the preview file has changed from an ai-setup baseline.
* Returns true if: hash differs, file appeared, file disappeared, or file is unreadable.
*/
export async function checkPreviewChanged(
@@ -73,7 +73,7 @@ export async function checkPreviewChanged(
}
/**
- * Check for a pending ai-prepare record and fire an evidence event if found.
+ * Check for a pending ai-setup record and fire an evidence event if found.
*
* Called from:
* - `withTelemetry` after the boot event for non-dev/build CLI commands (no story index)
@@ -81,7 +81,7 @@ export async function checkPreviewChanged(
*
* Gated on: agent detected → pending record exists → within session window → configDir matches.
*/
-export async function collectAiPrepareEvidence(
+export async function collectAiSetupEvidence(
eventType: EventType,
configDir: string | undefined,
storyIndex?: StoryIndex
@@ -93,8 +93,8 @@ export async function collectAiPrepareEvidence(
return;
}
- // Gate 2: Is there a pending ai-prepare record?
- const pending = await getAiPreparePending();
+ // Gate 2: Is there a pending ai-setup record?
+ const pending = await getAiSetupPending();
if (!pending) {
return;
}
@@ -105,17 +105,17 @@ export async function collectAiPrepareEvidence(
}
// Gate 4: Is it within the session window?
- const timeSincePrepare = Date.now() - pending.timestamp;
- if (timeSincePrepare > SESSION_TIMEOUT) {
+ const timeSinceSetup = Date.now() - pending.timestamp;
+ if (timeSinceSetup > SESSION_TIMEOUT) {
// Session expired, clean up pending record.
- await flushAiPreparePending();
+ await flushAiSetupPending();
return;
}
- // Don't fire evidence for ai-prepare itself — the prepare command gives the
+ // Don't fire evidence for ai-setup itself — the setup command gives the
// prompt to the agent and exits, so we only expect changes after the agent
// has started processing it.
- if (eventType === 'ai-prepare') {
+ if (eventType === 'ai-setup') {
return;
}
@@ -126,12 +126,12 @@ export async function collectAiPrepareEvidence(
const aiAuthoredStories = storyIndex ? countAiAuthoredStories(storyIndex) : undefined;
await telemetry(
- 'ai-prepare-evidence',
+ 'ai-setup-evidence',
{
previewChanged,
aiAuthoredStories,
sessionId: pending.sessionId,
- timeSincePrepare,
+ timeSinceSetup,
},
{
immediate: true,
diff --git a/code/core/src/telemetry/event-cache.test.ts b/code/core/src/telemetry/event-cache.test.ts
index 76b7a701e156..bd0f9494c7c9 100644
--- a/code/core/src/telemetry/event-cache.test.ts
+++ b/code/core/src/telemetry/event-cache.test.ts
@@ -5,8 +5,8 @@ import { cache } from 'storybook/internal/common';
import type { CacheEntry } from './event-cache.ts';
import {
- flushAiPreparePending,
- getAiPreparePending,
+ flushAiSetupPending,
+ getAiSetupPending,
getLastEvents,
getPrecedingUpgrade,
set,
@@ -354,7 +354,7 @@ describe('event-cache', () => {
});
});
- describe('ai-prepare pending cache', () => {
+ describe('ai-setup pending cache', () => {
let cacheGetMock: MockInstance;
let cacheRemoveMock: MockInstance;
@@ -364,7 +364,7 @@ describe('event-cache', () => {
cacheRemoveMock = vi.mocked(cache.remove);
});
- it('returns cached ai-prepare pending record when present', async () => {
+ it('returns cached ai-setup pending record when present', async () => {
const pending = {
timestamp: 123,
sessionId: 'session-1',
@@ -375,18 +375,18 @@ describe('event-cache', () => {
cacheGetMock.mockResolvedValueOnce(pending);
- await expect(getAiPreparePending()).resolves.toEqual(pending);
- expect(cacheGetMock).toHaveBeenCalledWith('ai-prepare-pending');
+ await expect(getAiSetupPending()).resolves.toEqual(pending);
+ expect(cacheGetMock).toHaveBeenCalledWith('ai-setup-pending');
});
- it('removes the cached ai-prepare pending record and returns undefined', async () => {
+ it('removes the cached ai-setup pending record and returns undefined', async () => {
cacheRemoveMock.mockResolvedValueOnce(undefined);
cacheGetMock.mockResolvedValueOnce(undefined);
- await expect(flushAiPreparePending()).resolves.toBeUndefined();
- expect(cacheRemoveMock).toHaveBeenCalledWith('ai-prepare-pending');
- await expect(getAiPreparePending()).resolves.toBeUndefined();
- expect(cacheGetMock).toHaveBeenCalledWith('ai-prepare-pending');
+ await expect(flushAiSetupPending()).resolves.toBeUndefined();
+ expect(cacheRemoveMock).toHaveBeenCalledWith('ai-setup-pending');
+ await expect(getAiSetupPending()).resolves.toBeUndefined();
+ expect(cacheGetMock).toHaveBeenCalledWith('ai-setup-pending');
});
});
});
diff --git a/code/core/src/telemetry/event-cache.ts b/code/core/src/telemetry/event-cache.ts
index ae3d265d10a1..84b1a98a889d 100644
--- a/code/core/src/telemetry/event-cache.ts
+++ b/code/core/src/telemetry/event-cache.ts
@@ -82,11 +82,11 @@ export const getPrecedingUpgrade = async (
: undefined;
};
/**
- * Record cached at ai-prepare time.
+ * Record cached at ai-setup time.
* Read by subsequent CLI entry points for evidence collection.
* Canonical definition — imported by event-cache.ts and prepare-requirements.ts.
*/
-export interface AiPreparePendingRecord {
+export interface AiSetupPendingRecord {
timestamp: number;
sessionId: string;
configDir: string;
@@ -94,15 +94,15 @@ export interface AiPreparePendingRecord {
previewHash: string | null;
}
-export const getAiPreparePending = async (): Promise => {
+export const getAiSetupPending = async (): Promise => {
// Wait for any pending set operations to complete before reading
await processingPromise;
- return (await cache.get('ai-prepare-pending')) ?? undefined;
+ return (await cache.get('ai-setup-pending')) ?? undefined;
};
-export const flushAiPreparePending = async (): Promise => {
+export const flushAiSetupPending = async (): Promise => {
// Wait for any pending set operations to complete before removing
await processingPromise;
- await cache.remove('ai-prepare-pending');
+ await cache.remove('ai-setup-pending');
return undefined;
};
diff --git a/code/core/src/telemetry/index.ts b/code/core/src/telemetry/index.ts
index a27b99e44e55..438b38799c71 100644
--- a/code/core/src/telemetry/index.ts
+++ b/code/core/src/telemetry/index.ts
@@ -16,21 +16,21 @@ export * from './sanitize.ts';
export * from './error-collector.ts';
-export * from './ai-prepare-utils.ts';
+export * from './ai-setup-utils.ts';
export {
getPrecedingUpgrade,
getLastEvents,
type CacheEntry,
- getAiPreparePending,
- type AiPreparePendingRecord,
+ getAiSetupPending,
+ type AiSetupPendingRecord,
} from './event-cache.ts';
export { getSessionId, SESSION_TIMEOUT } from './session-id.ts';
export { addToGlobalContext } from './telemetry.ts';
-export { detectAgent } from './detect-agent.ts';
+export { detectAgent, type AgentInfo } from './detect-agent.ts';
/** Is this story part of the CLI generated examples, including user-created stories in those files */
export const isExampleStoryId = (storyId: string) =>
diff --git a/code/core/src/telemetry/types.ts b/code/core/src/telemetry/types.ts
index de4945851310..9b784604d6ab 100644
--- a/code/core/src/telemetry/types.ts
+++ b/code/core/src/telemetry/types.ts
@@ -45,9 +45,9 @@ export type EventType =
| 'doctor'
| 'share'
| 'ghost-stories'
- | 'ai-prepare'
- | 'ai-prepare-evidence'
- | 'ai-prepare-story-scoring'
+ | 'ai-setup'
+ | 'ai-setup-evidence'
+ | 'ai-setup-story-scoring'
| 'ai-prompt-nudge';
export interface Dependency {
diff --git a/code/lib/cli-storybook/src/ai/index.ts b/code/lib/cli-storybook/src/ai/index.ts
index 5110b798b050..4107590ffc68 100644
--- a/code/lib/cli-storybook/src/ai/index.ts
+++ b/code/lib/cli-storybook/src/ai/index.ts
@@ -8,7 +8,7 @@ import {
getSessionId,
snapshotPreviewFile,
telemetry,
- type AiPreparePendingRecord,
+ type AiSetupPendingRecord,
} from 'storybook/internal/telemetry';
import { SupportedLanguage } from 'storybook/internal/types';
@@ -16,9 +16,9 @@ import { ProjectTypeService } from '../../../create-storybook/src/services/Proje
import { getStorybookData } from '../automigrate/helpers/mainConfigFile.ts';
import { generateMarkdownOutput } from './prompt.ts';
-import type { ProjectInfo, AiPrepareOptions } from './types.ts';
+import type { ProjectInfo, AiSetupOptions } from './types.ts';
-export async function aiPrepare(options: AiPrepareOptions): Promise {
+export async function aiSetup(options: AiSetupOptions): Promise {
const { configDir: userConfigDir, packageManager: packageManagerName, output } = options;
let projectInfo: ProjectInfo;
@@ -82,7 +82,7 @@ export async function aiPrepare(options: AiPrepareOptions): Promise {
const result = generateMarkdownOutput(projectInfo);
const markdownOutput = result.markdown;
- await telemetry('ai-prepare', {
+ await telemetry('ai-setup', {
cliOptions: {
output: output ? 'file' : undefined,
configDir: projectInfo.configDir,
@@ -103,13 +103,13 @@ export async function aiPrepare(options: AiPrepareOptions): Promise {
const resolvedConfigDir = resolve(projectInfo.configDir);
const previewSnapshot = await snapshotPreviewFile(resolvedConfigDir);
const sessionId = await getSessionId();
- const pendingRecord: AiPreparePendingRecord = {
+ const pendingRecord: AiSetupPendingRecord = {
timestamp: Date.now(),
sessionId,
configDir: resolvedConfigDir,
...previewSnapshot,
};
- await cache.set('ai-prepare-pending', pendingRecord);
+ await cache.set('ai-setup-pending', pendingRecord);
if (output) {
const outputPath = resolve(output);
diff --git a/code/lib/cli-storybook/src/ai/types.ts b/code/lib/cli-storybook/src/ai/types.ts
index 5d7e0abeb2ec..3a9a1b52be28 100644
--- a/code/lib/cli-storybook/src/ai/types.ts
+++ b/code/lib/cli-storybook/src/ai/types.ts
@@ -1,6 +1,6 @@
import type { SupportedRenderer } from 'storybook/internal/types';
-export interface AiPrepareOptions {
+export interface AiSetupOptions {
configDir?: string;
packageManager?: string;
output?: string;
diff --git a/code/lib/cli-storybook/src/bin/run.ts b/code/lib/cli-storybook/src/bin/run.ts
index 28ad72ca7ad8..bb96b8e94ac3 100644
--- a/code/lib/cli-storybook/src/bin/run.ts
+++ b/code/lib/cli-storybook/src/bin/run.ts
@@ -23,7 +23,7 @@ import { doctor } from '../doctor/index.ts';
import { link } from '../link.ts';
import { migrate } from '../migrate.ts';
import { sandbox } from '../sandbox.ts';
-import { aiPrepare } from '../ai/index.ts';
+import { aiSetup } from '../ai/index.ts';
import { type UpgradeOptions, upgrade } from '../upgrade.ts';
addToGlobalContext('cliVersion', versions.storybook);
@@ -307,7 +307,7 @@ const aiCommand = command('ai')
);
aiCommand
- .command('prepare')
+ .command('setup')
.description('Generate setup instructions to write stories for real components')
.addOption(
new Option('--package-manager ', 'Force package manager for installing deps').choices(
@@ -318,8 +318,8 @@ aiCommand
.action(async (options, cmd) => {
const parentOptions = cmd.parent?.opts() ?? {};
const mergedOptions = { ...parentOptions, ...options };
- await withTelemetry('ai-prepare', { cliOptions: mergedOptions }, async () => {
- await aiPrepare(mergedOptions);
+ await withTelemetry('ai-setup', { cliOptions: mergedOptions }, async () => {
+ await aiSetup(mergedOptions);
}).catch(handleCommandFailure(mergedOptions.logfile));
});
diff --git a/code/lib/create-storybook/src/commands/FinalizationCommand.test.ts b/code/lib/create-storybook/src/commands/FinalizationCommand.test.ts
index 1a45fd8601a0..7eec40c78880 100644
--- a/code/lib/create-storybook/src/commands/FinalizationCommand.test.ts
+++ b/code/lib/create-storybook/src/commands/FinalizationCommand.test.ts
@@ -126,7 +126,7 @@ describe('FinalizationCommand', () => {
expect(logger.step).toHaveBeenCalledWith(
expect.stringContaining('is not entirely set up yet')
);
- expect(logger.step).toHaveBeenCalledWith(expect.stringContaining('npx storybook ai prepare'));
+ expect(logger.step).toHaveBeenCalledWith(expect.stringContaining('npx storybook ai setup'));
});
it('should show standard success message when showAgentFollowUp=false with AI instructions', async () => {
@@ -180,7 +180,7 @@ describe('FinalizationCommand', () => {
expect(logger.step).toHaveBeenCalledWith(
expect.stringContaining('To finalize setting up with AI')
);
- expect(logger.step).toHaveBeenCalledWith(expect.stringContaining('npx storybook ai prepare'));
+ expect(logger.step).toHaveBeenCalledWith(expect.stringContaining('npx storybook ai setup'));
});
it('should NOT show AI instructions when showAiInstructions=false', async () => {
diff --git a/code/lib/create-storybook/src/commands/FinalizationCommand.ts b/code/lib/create-storybook/src/commands/FinalizationCommand.ts
index 78348f277fef..e8665ca1e907 100644
--- a/code/lib/create-storybook/src/commands/FinalizationCommand.ts
+++ b/code/lib/create-storybook/src/commands/FinalizationCommand.ts
@@ -9,7 +9,7 @@ import { dedent } from 'ts-dedent';
export type FinalizationCommandOptions = {
logfile: string | boolean | undefined;
- /** When true, show the agent follow-up message ("run npx storybook ai prepare") instead of the normal success message */
+ /** When true, show the agent follow-up message ("run npx storybook ai setup") instead of the normal success message */
showAgentFollowUp: boolean;
/** When true, show the "paste this prompt to your AI agent" instructions */
showAiInstructions: boolean;
@@ -89,7 +89,7 @@ export class FinalizationCommand {
logger.step(
CLI_COLORS.storybook(
dedent`Storybook is installed but is not entirely set up yet.
- To finish setting up, now run \`npx storybook ai prepare\` and follow its instructions precisely.`
+ To finish setting up, now run \`npx storybook ai setup\` and follow its instructions precisely.`
)
);
} else {
@@ -111,7 +111,7 @@ export class FinalizationCommand {
if (this.options.showAiInstructions) {
logger.step(dedent`To finalize setting up with AI, paste this prompt to your AI agent:
- ${CLI_COLORS.storybook(`Run \`npx storybook ai prepare\` and follow its instructions precisely.`)}
+ ${CLI_COLORS.storybook(`Run \`npx storybook ai setup\` and follow its instructions precisely.`)}
`);
}
}
diff --git a/code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts b/code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts
index f62b63ce47c2..c7b2186b289a 100644
--- a/code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts
+++ b/code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts
@@ -21,7 +21,7 @@ interface CommandWithPrivates {
telemetryService: {
trackNewUserCheck: ReturnType;
trackInstallType: ReturnType;
- trackAiPromptNudge: ReturnType;
+ trackAiSetupNudge: ReturnType;
};
}
@@ -35,7 +35,7 @@ describe('UserPreferencesCommand', () => {
renderer: 'react' as SupportedRenderer,
projectType: ProjectType.REACT,
isTestFeatureAvailable: true,
- isAiPrepareAvailable: false,
+ isAiSetupAvailable: false,
};
afterAll(() => {
@@ -93,7 +93,7 @@ describe('UserPreferencesCommand', () => {
const mockTelemetryService = {
trackNewUserCheck: vi.fn(),
trackInstallType: vi.fn(),
- trackAiPromptNudge: vi.fn(),
+ trackAiSetupNudge: vi.fn(),
};
// Inject mocked services
@@ -225,7 +225,7 @@ describe('UserPreferencesCommand', () => {
const result = await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
expect(prompt.confirm).toHaveBeenCalledWith(
@@ -249,7 +249,7 @@ describe('UserPreferencesCommand', () => {
const result = await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
expect(result.selectedFeatures.has(Feature.AI)).toBe(false);
@@ -263,7 +263,7 @@ describe('UserPreferencesCommand', () => {
const result = await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
expect(prompt.confirm).not.toHaveBeenCalled();
@@ -287,19 +287,19 @@ describe('UserPreferencesCommand', () => {
(yesCommand as unknown as CommandWithPrivates).telemetryService = {
trackNewUserCheck: vi.fn(),
trackInstallType: vi.fn(),
- trackAiPromptNudge: vi.fn(),
+ trackAiSetupNudge: vi.fn(),
};
const result = await yesCommand.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
expect(prompt.confirm).not.toHaveBeenCalled();
expect(result.selectedFeatures.has(Feature.AI)).toBe(true);
});
- it('should not prompt for AI setup when isAiPrepareAvailable is false', async () => {
+ it('should not prompt for AI setup when isAiSetupAvailable is false', async () => {
Object.defineProperty(process.stdout, 'isTTY', {
value: true,
configurable: true,
@@ -309,7 +309,7 @@ describe('UserPreferencesCommand', () => {
const result = await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: false,
+ isAiSetupAvailable: false,
});
expect(prompt.confirm).not.toHaveBeenCalled();
@@ -329,7 +329,7 @@ describe('UserPreferencesCommand', () => {
const result = await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
expect(result.selectedFeatures.has(Feature.AI)).toBe(true);
@@ -351,7 +351,7 @@ describe('UserPreferencesCommand', () => {
const result = await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
expect(result.selectedFeatures.has(Feature.AI)).toBe(false);
@@ -370,11 +370,11 @@ describe('UserPreferencesCommand', () => {
await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
const telemetryService = (command as unknown as CommandWithPrivates).telemetryService;
- expect(telemetryService.trackAiPromptNudge).toHaveBeenCalledWith({ skipPrompt: false });
+ expect(telemetryService.trackAiSetupNudge).toHaveBeenCalledWith({ skipPrompt: false });
});
it('should not track ai-prompt-nudge telemetry when user declines AI setup', async () => {
@@ -388,23 +388,23 @@ describe('UserPreferencesCommand', () => {
await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
const telemetryService = (command as unknown as CommandWithPrivates).telemetryService;
- expect(telemetryService.trackAiPromptNudge).not.toHaveBeenCalled();
+ expect(telemetryService.trackAiSetupNudge).not.toHaveBeenCalled();
});
it('should track ai-prompt-nudge telemetry when AI is auto-accepted in non-interactive mode', async () => {
// Non-interactive (no TTY) with AI available — auto-accepts
const result = await command.execute({
...defaultExecuteOptions,
- isAiPrepareAvailable: true,
+ isAiSetupAvailable: true,
});
expect(result.selectedFeatures.has(Feature.AI)).toBe(true);
const telemetryService = (command as unknown as CommandWithPrivates).telemetryService;
- expect(telemetryService.trackAiPromptNudge).toHaveBeenCalledWith({ skipPrompt: true });
+ expect(telemetryService.trackAiSetupNudge).toHaveBeenCalledWith({ skipPrompt: true });
});
});
diff --git a/code/lib/create-storybook/src/commands/UserPreferencesCommand.ts b/code/lib/create-storybook/src/commands/UserPreferencesCommand.ts
index f16a6af3c815..bc25b712bc7d 100644
--- a/code/lib/create-storybook/src/commands/UserPreferencesCommand.ts
+++ b/code/lib/create-storybook/src/commands/UserPreferencesCommand.ts
@@ -35,7 +35,7 @@ export interface UserPreferencesOptions {
renderer: SupportedRenderer;
projectType: ProjectType;
isTestFeatureAvailable: boolean;
- isAiPrepareAvailable: boolean;
+ isAiSetupAvailable: boolean;
}
/**
@@ -80,9 +80,7 @@ export class UserPreferencesCommand {
: 'recommended';
// Ask about AI setup (only available for compatible projects, e.g. React + Vite)
- const useAiForSetup = options.isAiPrepareAvailable
- ? await this.promptAiSetup(skipPrompt)
- : false;
+ const useAiForSetup = options.isAiSetupAvailable ? await this.promptAiSetup(skipPrompt) : false;
const selectedFeatures = this.determineFeatures(
installType,
@@ -228,7 +226,7 @@ export class UserPreferencesCommand {
});
if (useAi) {
- await this.telemetryService.trackAiPromptNudge({ skipPrompt });
+ await this.telemetryService.trackAiSetupNudge({ skipPrompt });
}
return useAi;
diff --git a/code/lib/create-storybook/src/initiate.ts b/code/lib/create-storybook/src/initiate.ts
index e8ec6c27e546..5b6452862004 100644
--- a/code/lib/create-storybook/src/initiate.ts
+++ b/code/lib/create-storybook/src/initiate.ts
@@ -29,7 +29,7 @@ import type { CommandOptions } from './generators/types.ts';
import { FeatureCompatibilityService } from './services/FeatureCompatibilityService.ts';
import { TelemetryService } from './services/TelemetryService.ts';
-/** Validate test feature compatibility and check AI prepare support */
+/** Validate test feature compatibility and check AI setup support */
async function checkFeatureSupport(
packageManager: JsPackageManager,
framework: SupportedFramework | null,
@@ -37,7 +37,7 @@ async function checkFeatureSupport(
renderer: SupportedRenderer
): Promise<{
isTestFeatureAvailable: boolean;
- isAiPrepareAvailable: boolean;
+ isAiSetupAvailable: boolean;
}> {
const featureService = new FeatureCompatibilityService(packageManager);
@@ -47,11 +47,11 @@ async function checkFeatureSupport(
process.cwd()
);
- const aiPrepare = FeatureCompatibilityService.supportsAIPrepareFeature(renderer, builder);
+ const aiSetup = FeatureCompatibilityService.supportsAISetupFeature(renderer, builder);
return {
isTestFeatureAvailable: result.compatible,
- isAiPrepareAvailable: aiPrepare,
+ isAiSetupAvailable: aiSetup,
};
}
@@ -97,7 +97,7 @@ export async function doInitiate(options: CommandOptions): Promise<
);
// Step 4: Get user preferences and feature selections (with framework/builder for validation)
- const { isTestFeatureAvailable, isAiPrepareAvailable } = await checkFeatureSupport(
+ const { isTestFeatureAvailable, isAiSetupAvailable } = await checkFeatureSupport(
packageManager,
framework,
builder,
@@ -111,7 +111,7 @@ export async function doInitiate(options: CommandOptions): Promise<
renderer,
projectType,
isTestFeatureAvailable,
- isAiPrepareAvailable,
+ isAiSetupAvailable,
});
// Step 5: Execute generator with dependency collector (now with frameworkInfo)
diff --git a/code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts b/code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts
index 3f6145b596d3..93e0b7b71042 100644
--- a/code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts
+++ b/code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts
@@ -44,10 +44,10 @@ describe('FeatureCompatibilityService', () => {
});
});
- describe('supportsAIPrepareFeature', () => {
+ describe('supportsAISetupFeature', () => {
it('should return true for react renderer with vite builder', () => {
expect(
- FeatureCompatibilityService.supportsAIPrepareFeature(
+ FeatureCompatibilityService.supportsAISetupFeature(
SupportedRenderer.REACT,
SupportedBuilder.VITE
)
@@ -56,7 +56,7 @@ describe('FeatureCompatibilityService', () => {
it('should return false for vue3 renderer with vite builder', () => {
expect(
- FeatureCompatibilityService.supportsAIPrepareFeature(
+ FeatureCompatibilityService.supportsAISetupFeature(
SupportedRenderer.VUE3,
SupportedBuilder.VITE
)
@@ -65,7 +65,7 @@ describe('FeatureCompatibilityService', () => {
it('should return false for react renderer with webpack5 builder', () => {
expect(
- FeatureCompatibilityService.supportsAIPrepareFeature(
+ FeatureCompatibilityService.supportsAISetupFeature(
SupportedRenderer.REACT,
SupportedBuilder.WEBPACK5
)
@@ -74,14 +74,14 @@ describe('FeatureCompatibilityService', () => {
it('should return false for non-react renderer with non-vite builder', () => {
expect(
- FeatureCompatibilityService.supportsAIPrepareFeature(
+ FeatureCompatibilityService.supportsAISetupFeature(
SupportedRenderer.ANGULAR,
SupportedBuilder.WEBPACK5
)
).toBe(false);
expect(
- FeatureCompatibilityService.supportsAIPrepareFeature(
+ FeatureCompatibilityService.supportsAISetupFeature(
SupportedRenderer.SVELTE,
SupportedBuilder.WEBPACK5
)
diff --git a/code/lib/create-storybook/src/services/FeatureCompatibilityService.ts b/code/lib/create-storybook/src/services/FeatureCompatibilityService.ts
index 7f78a1214027..3097b2406b2d 100644
--- a/code/lib/create-storybook/src/services/FeatureCompatibilityService.ts
+++ b/code/lib/create-storybook/src/services/FeatureCompatibilityService.ts
@@ -33,8 +33,8 @@ export class FeatureCompatibilityService {
);
}
- /** Check if AI-assisted setup (storybook ai prepare) is supported for this project configuration */
- static supportsAIPrepareFeature(renderer: SupportedRenderer, builder: SupportedBuilder): boolean {
+ /** Check if AI-assisted setup (storybook ai setup) is supported for this project configuration */
+ static supportsAISetupFeature(renderer: SupportedRenderer, builder: SupportedBuilder): boolean {
return renderer === SupportedRenderer.REACT && builder === SupportedBuilder.VITE;
}
diff --git a/code/lib/create-storybook/src/services/TelemetryService.test.ts b/code/lib/create-storybook/src/services/TelemetryService.test.ts
index 404957f7d3be..b816482ce6be 100644
--- a/code/lib/create-storybook/src/services/TelemetryService.test.ts
+++ b/code/lib/create-storybook/src/services/TelemetryService.test.ts
@@ -73,20 +73,20 @@ describe('TelemetryService', () => {
});
it('should track ai-prompt-nudge event with context when prompt was shown', async () => {
- await telemetryService.trackAiPromptNudge({ skipPrompt: false });
+ await telemetryService.trackAiSetupNudge({ skipPrompt: false });
expect(telemetry).toHaveBeenCalledWith('ai-prompt-nudge', {
- id: 'prepare',
+ id: 'setup',
origin: 'init',
context: { skipPrompt: false },
});
});
it('should track ai-prompt-nudge event with context when prompt was skipped', async () => {
- await telemetryService.trackAiPromptNudge({ skipPrompt: true });
+ await telemetryService.trackAiSetupNudge({ skipPrompt: true });
expect(telemetry).toHaveBeenCalledWith('ai-prompt-nudge', {
- id: 'prepare',
+ id: 'setup',
origin: 'init',
context: { skipPrompt: true },
});
@@ -137,7 +137,7 @@ describe('TelemetryService', () => {
});
it('should not track ai-prompt-nudge event', async () => {
- await telemetryService.trackAiPromptNudge({ skipPrompt: false });
+ await telemetryService.trackAiSetupNudge({ skipPrompt: false });
expect(telemetry).not.toHaveBeenCalled();
});
diff --git a/code/lib/create-storybook/src/services/TelemetryService.ts b/code/lib/create-storybook/src/services/TelemetryService.ts
index 56bc1ba6e9de..00f570f33857 100644
--- a/code/lib/create-storybook/src/services/TelemetryService.ts
+++ b/code/lib/create-storybook/src/services/TelemetryService.ts
@@ -33,9 +33,9 @@ export class TelemetryService {
}
/** Track when a user accepts the AI setup nudge prompt */
- async trackAiPromptNudge(context: { skipPrompt: boolean }): Promise {
+ async trackAiSetupNudge(context: { skipPrompt: boolean }): Promise {
await this.runTelemetryIfEnabled('ai-prompt-nudge', {
- id: 'prepare',
+ id: 'setup',
origin: 'init',
context,
});