Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a288874
Angular: Update peerDependencies to support newer versions of Angular…
EtiennePasteur Jun 29, 2026
e75258d
fix(telemetry): prevent pnpm paths from leaking into framework.name
claude Jul 2, 2026
ec91205
Core: Skip story-docs Code panel emission in portable stories
ndelangen Jul 7, 2026
875fddd
Core: Drop speculative catch on story-docs load chain
ndelangen Jul 7, 2026
f032943
Core: Throw NoFreePortError when port detection cannot bind any port
kasperpeulen Jul 7, 2026
7552e58
Address review: unique error code, propagate error, guard exact-port …
kasperpeulen Jul 7, 2026
d431c4f
Merge branch 'next' into kasper/fix-server-port-detection-crash
kasperpeulen Jul 7, 2026
a18647f
CI: Make minimal changes to ensure Webpack Angular runs on v22
Sidnioulz Jul 7, 2026
191ae13
Fix ReviewWidget story count to match the active review
ghengeveld Jul 7, 2026
b405356
Clear orphaned reviewing statuses when applying a new review
ghengeveld Jul 7, 2026
833440b
Refresh lockfile
Sidnioulz Jul 7, 2026
df2b432
CLI: Match storybook ai instances by config dir as well as cwd
kasperpeulen Jul 7, 2026
282390c
Merge pull request #35388 from storybookjs/kasper/fix-server-port-det…
Sidnioulz Jul 7, 2026
3a53335
Merge pull request #35318 from EtiennePasteur/next
Sidnioulz Jul 7, 2026
ae44971
Core: Enhance storyDocsCodePanel to skip portable stories
ndelangen Jul 7, 2026
5696acc
Core: Add test for skipping JSX rendering in portable stories
ndelangen Jul 7, 2026
deb23aa
Address review: explicit --config-dir must not fall back to cwd matching
kasperpeulen Jul 7, 2026
966786d
Core: Leave experimentalReview unset by default so the CLI channel ca…
kasperpeulen Jul 7, 2026
80490ef
Core: Update test for JSX rendering in portable stories
ndelangen Jul 7, 2026
507c408
Merge branch 'next' into kasper/ai-cli-configdir-instance-matching
kasperpeulen Jul 7, 2026
ccfbb0b
Merge branch 'next' into norbert/fix-story-docs-portable-stories
ndelangen Jul 7, 2026
88bd116
Merge branch 'next' into kasper/experimental-review-unset-default
kasperpeulen Jul 7, 2026
ada309c
Revert docs and JSDoc changes; keep the tri-state explanation in inte…
kasperpeulen Jul 7, 2026
0c91702
Merge remote-tracking branch 'origin/kasper/experimental-review-unset…
kasperpeulen Jul 7, 2026
2c887a2
Avoid double-applying review statuses on fresh reviews
ghengeveld Jul 7, 2026
8aa781f
Merge branch 'next' into fix/review-story-count-accuracy
ghengeveld Jul 7, 2026
3532b8e
Add full-defaults test guarding the untouched features preset
kasperpeulen Jul 7, 2026
cfee1c5
Merge pull request #35345 from storybookjs/claude/slack-session-xxvkl9
Sidnioulz Jul 7, 2026
80325b6
Merge pull request #35387 from storybookjs/norbert/fix-story-docs-por…
ndelangen Jul 7, 2026
be766d5
Merge branch 'next' into kasper/experimental-review-unset-default
kasperpeulen Jul 7, 2026
ded49ae
Merge pull request #35391 from storybookjs/fix/review-story-count-acc…
Sidnioulz Jul 7, 2026
8134fd3
Merge branch 'next' into kasper/ai-cli-configdir-instance-matching
kasperpeulen Jul 7, 2026
b897c04
Merge pull request #35396 from storybookjs/kasper/experimental-review…
kasperpeulen Jul 7, 2026
8c5eb42
Merge branch 'next' into kasper/ai-cli-configdir-instance-matching
kasperpeulen Jul 7, 2026
e55acd9
Fold resolveReadyInstance positional args into a target options object
kasperpeulen Jul 7, 2026
f7d3894
Simplify normalisedConfigDir with short-circuit resolve
kasperpeulen Jul 7, 2026
696e724
Merge pull request #35392 from storybookjs/kasper/ai-cli-configdir-in…
kasperpeulen Jul 7, 2026
cb7a60b
Write changelog for 10.5.0-beta.2 [skip ci]
storybook-bot Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 10.5.0-beta.2

- Angular: Support Angular 22 in Webpack framework - [#35318](https://github.com/storybookjs/storybook/pull/35318), thanks @EtiennePasteur!
- CLI: Match `storybook ai` instances by config dir as well as cwd - [#35392](https://github.com/storybookjs/storybook/pull/35392), thanks @kasperpeulen!
- Core: Fix cryptic invariant crash when dev server port detection fails - [#35388](https://github.com/storybookjs/storybook/pull/35388), thanks @kasperpeulen!
- Core: Leave experimentalReview unset by default so the AI CLI plugins can enable review - [#35396](https://github.com/storybookjs/storybook/pull/35396), thanks @kasperpeulen!
- Core: Skip story-docs Code panel emission in portable stories - [#35387](https://github.com/storybookjs/storybook/pull/35387), thanks @ndelangen!
- Review: Fix inaccurate review story counts in sidebar - [#35391](https://github.com/storybookjs/storybook/pull/35391), thanks @ghengeveld!
- Telemetry: Prevent pnpm paths from leaking into framework.name - [#35345](https://github.com/storybookjs/storybook/pull/35345), thanks @Sidnioulz!

## 10.5.0-beta.1

- Core: Add experimentalReview feature flag and make the features type augmentable - [#35379](https://github.com/storybookjs/storybook/pull/35379), thanks @yannbf!
Expand Down
66 changes: 61 additions & 5 deletions code/core/src/cli/ai/mcp/intercepts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import { describe, expect, it } from 'vitest';
import { getInterceptMarkdown } from './intercepts.ts';
import type { StorybookInstanceRecord } from './types.ts';

const record = (cwd: string, url: string): StorybookInstanceRecord => ({
const record = (
cwd: string,
url: string,
overrides: Partial<StorybookInstanceRecord> = {}
): StorybookInstanceRecord => ({
schemaVersion: 1,
instanceId: 'i-1',
pid: 1,
cwd,
url,
port: 6006,
mcp: { status: 'ready', endpoint: '/mcp' },
...overrides,
});

describe('getInterceptMarkdown', () => {
Expand All @@ -20,16 +25,67 @@ describe('getInterceptMarkdown', () => {
expect(markdown).toContain('storybook dev');
});

it('no-instance with candidates lists the running cwds', () => {
it('no-instance with candidates lists the running instances and a copyable --cwd retry', () => {
const markdown = getInterceptMarkdown('no-instance', {
records: [record('/projects/foo', 'http://localhost:6006')],
});
expect(markdown).toContain('Running Storybooks:');
expect(markdown).toContain('- `/projects/foo` (http://localhost:6006)');
expect(markdown).toContain('--cwd');
expect(markdown).toContain('- cwd `/projects/foo` (http://localhost:6006)');
expect(markdown).toContain('- `storybook ai --cwd /projects/foo <command> [args...]`');
expect(markdown).toContain('BEFORE the command name');
expect(markdown).not.toContain('storybook ai --config-dir');
});

it('port-mismatch lists the ports running at the cwd', () => {
it('no-instance with candidates includes the recorded config dir and a --config-dir retry', () => {
const markdown = getInterceptMarkdown('no-instance', {
records: [
record('/repo', 'http://localhost:6006', {
configDir: '/repo/packages/ui/.storybook',
}),
],
});
expect(markdown).toContain(
'- cwd `/repo`, config dir `/repo/packages/ui/.storybook` (http://localhost:6006)'
);
expect(markdown).toContain(
'- `storybook ai --config-dir /repo/packages/ui/.storybook <command> [args...]`'
);
// A bare `--cwd /repo` retry would fail metadata loading when the config is not at
// /repo/.storybook, so it must not be offered for records with a configDir.
expect(markdown).not.toContain('storybook ai --cwd');
});

it('no-instance quotes paths containing whitespace in retry examples', () => {
const markdown = getInterceptMarkdown('no-instance', {
records: [
record('/Users/John Smith/proj', 'http://localhost:6006'),
record('/repo', 'http://localhost:6007', {
instanceId: 'i-2',
pid: 2,
configDir: '/repo/my packages/ui/.storybook',
}),
],
});
expect(markdown).toContain(
'- `storybook ai --cwd "/Users/John Smith/proj" <command> [args...]`'
);
expect(markdown).toContain(
'- `storybook ai --config-dir "/repo/my packages/ui/.storybook" <command> [args...]`'
);
});

it('no-instance deduplicates retry examples across records sharing a cwd', () => {
const markdown = getInterceptMarkdown('no-instance', {
records: [
record('/projects/foo', 'http://localhost:6006'),
record('/projects/foo', 'http://localhost:6007', { instanceId: 'i-2', pid: 2 }),
],
});
const occurrences = markdown.split('`storybook ai --cwd /projects/foo').length - 1;
expect(occurrences).toBe(1);
});

it('port-mismatch lists the ports running for the project', () => {
const markdown = getInterceptMarkdown('port-mismatch', {
port: 9999,
records: [record('/projects/foo', 'http://localhost:6006')],
Expand Down
33 changes: 28 additions & 5 deletions code/core/src/cli/ai/mcp/intercepts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,39 @@ import type { InterceptReason, StorybookInstanceRecord } from './types.ts';
*/
const NO_INSTANCE_EMPTY = `Storybook is not running at this cwd. Start \`storybook dev\` from the project's cwd and retry the command.`;

const buildNoInstanceWithCandidates = (records: StorybookInstanceRecord[]) =>
`No Storybook is running at this cwd. Either start Storybook from the project's cwd, or retry with \`--cwd\` set to one of the running cwds below.
const quotePath = (path: string) => (/\s/.test(path) ? `"${path}"` : path);

const buildNoInstanceWithCandidates = (records: StorybookInstanceRecord[]) => {
const instances = records.map((r) => {
const configDir = r.configDir ? `, config dir \`${r.configDir}\`` : '';
return `- cwd \`${r.cwd}\`${configDir} (${r.url})`;
});
// One concrete invocation per instance, built from its recorded values so the agent can copy it
// verbatim. Prefer `--config-dir` when recorded: a bare `--cwd` retry fails for instances whose
// config is not at `<cwd>/.storybook`, because command metadata loads from there first.
const examples = [
...new Set(
records.map((r) =>
r.configDir
? `- \`storybook ai --config-dir ${quotePath(r.configDir)} <command> [args...]\``
: `- \`storybook ai --cwd ${quotePath(r.cwd)} <command> [args...]\``
)
),
];

return `No running Storybook matches this project (neither its cwd nor its Storybook config dir). Either start \`storybook dev\` from this project, or retry with \`--cwd\` or \`--config-dir\` pointing at one of the running Storybooks below. Both flags must be placed BEFORE the command name.

Running Storybooks:
${records.map((r) => `- \`${r.cwd}\` (${r.url})`).join('\n')}`;
${instances.join('\n')}

Retry examples (replace \`<command>\` with the command you ran):
${examples.join('\n')}`;
};

const buildPortMismatch = (port: number | undefined, records: StorybookInstanceRecord[]) =>
`Storybook is running at this cwd, but not on port \`${port ?? 'unknown'}\`. Retry with one of the running ports below, or omit \`--port\` to route by cwd alone.
`Storybook is running for this project, but not on port \`${port ?? 'unknown'}\`. Retry with one of the running ports below, or omit \`--port\` to route by project alone.

Running Storybooks at this cwd:
Running Storybooks for this project:
${records.map((r) => `- port \`${r.port}\` (${r.url}, status: \`${r.mcp.status}\`)`).join('\n')}`;

const ADDON_MISSING = `Storybook is running but does not provide these commands. The \`@storybook/addon-mcp\` addon is missing.
Expand Down
2 changes: 1 addition & 1 deletion code/core/src/cli/ai/mcp/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function isAiCliFeatureEnabled(env: NodeJS.ProcessEnv = process.env): boo

const CWD_DESCRIPTION = 'Project directory of the target Storybook; place before the command name';
const CONFIG_DIR_DESCRIPTION =
'Storybook config directory for help and local commands; place before the command name';
'Storybook config directory of the target Storybook; place before the command name';
const PORT_DESCRIPTION =
'Port of the target Storybook for runtime commands; place before the command name';

Expand Down
9 changes: 9 additions & 0 deletions code/core/src/cli/ai/mcp/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ describe('readRegistry', () => {
await expect(readRegistry(REGISTRY_DIR)).resolves.toEqual([minimal]);
});

it('accepts records with an optional configDir (written by Storybook >= 10.5)', async () => {
const withConfigDir = { ...aliveRecord, configDir: '/projects/alive/packages/ui/.storybook' };
vol.fromNestedJSON({
[REGISTRY_DIR]: { 'config-dir.json': JSON.stringify(withConfigDir) },
});

await expect(readRegistry(REGISTRY_DIR)).resolves.toEqual([withConfigDir]);
});

it('accepts records with optional agent provenance', async () => {
const agentRecord = { ...aliveRecord, agent: 'claude-preview' };
vol.fromNestedJSON({ [REGISTRY_DIR]: { 'agent.json': JSON.stringify(agentRecord) } });
Expand Down
Loading
Loading