Skip to content

CLI: Match storybook ai instances by config dir as well as cwd - #35392

Merged
kasperpeulen merged 7 commits into
nextfrom
kasper/ai-cli-configdir-instance-matching
Jul 7, 2026
Merged

kasperpeulen merged 7 commits into
nextfrom
kasper/ai-cli-configdir-instance-matching

Conversation

@kasperpeulen

@kasperpeulen kasperpeulen commented Jul 7, 2026 •

Copy link
Copy Markdown
Member

Related to #35359 (makes storybook ai instance resolution robust in monorepos; the static --help command listing from that issue is a separate change). Amends the exact-cwd matching introduced in #34826.

What I did

storybook dev writes a runtime instance record to ~/.storybook/instances/<instanceId>.json, and storybook ai looked it up by exact cwd equality only. In a monorepo that breaks in both directions: a dev server started at the repo root with -c packages/ui/.storybook is invisible to storybook ai run from packages/ui, and one started from the leaf is invisible from the root.

Three changes:

  1. Writer (code/core/src/core-server/utils/runtime-instance-registry.ts, called from build-dev.ts): the record now includes the resolved absolute configDir of the running Storybook.

  2. Reader (code/core/src/cli/ai/mcp/): matching rule in resolveInstance:

    • With an explicit --config-dir, only instances whose recorded configDir equals the flag's resolved value match. The flag expresses precise intent — a same-cwd instance serving a different config must not win (previously the cwd fallback could silently route the command to the wrong Storybook, e.g. two package Storybooks both started from the repo root).
    • Without the flag, an instance matches when its recorded configDir equals the defaulted <cwd>/.storybook or its recorded cwd equals the target cwd (previous behavior). This is what makes the plain storybook ai <command> from a monorepo leaf find a root-started dev server.
    • All comparisons stay exact-normalized; no prefix matching. configDir is optional in the reader schema, so records written by older Storybooks still parse and keep matching by cwd (an explicit --config-dir can't select them; the failure guidance offers their --cwd instead).
  3. Actionable no-instance guidance: when nothing matches but Storybooks are running, the intercept markdown lists each instance with its recorded cwd and config dir, plus one copyable retry invocation per instance built from the recorded values (quoted when paths contain whitespace), and states that --cwd/--config-dir must be placed before the command name (the program uses enablePositionalOptions/passThroughOptions, so tokens after the command name are command arguments). Records with a configDir get a --config-dir example — a bare --cwd retry would fail command-metadata loading whenever the config is not at <cwd>/.storybook:

    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:
    - cwd `/repo`, config dir `/repo/packages/ui/.storybook` (http://localhost:6006)
    
    Retry examples (replace `<command>` with the command you ran):
    - `storybook ai --config-dir /repo/packages/ui/.storybook <command> [args...]`
    

    The multi-instance warning was also updated: matches can now span cwds, so each competing instance line carries its own cwd/config dir.

Review notes

The branch was reviewed by two independent automated reviewers (a Claude subagent with verified repros, and codex gpt-5.5 at xhigh reasoning). Their converging finding — explicit --config-dir being overridden by cwd matches — plus the non-copyable --cwd retry example, the stale multi-instance warning wording, and unquoted paths were all fixed in the follow-up commit. Verified fine by review: valibot 1.4.0 strips unknown keys, so old CLIs parse new records (dropping configDir) and the new CLI parses old records; the pathe-writer/node:path-reader round-trip also matches on Windows.

Note: code/core/src/cli/ai/mcp/types.ts carries comments saying it is copied from @storybook/mcp-proxy (storybookjs/mcp). That proxy is slated for deletion, so no sync is needed; the stale "keep in sync" comments can be cleaned up when the proxy removal lands.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Suites updated next to each changed file: resolve-instance.test.ts, registry.test.ts, intercepts.test.ts, run-tool.test.ts, runtime-instance-registry.test.ts (144 tests passing).

Manual testing

  1. In a monorepo with Storybook in a leaf package (e.g. an npm-workspaces repo with packages/ui/.storybook), start the dev server from the repo root: npx storybook dev -c packages/ui/.storybook
  2. From packages/ui, run STORYBOOK_FEATURE_AI_CLI=1 npx storybook ai get-changed-stories — the command should reach the running instance (previously: no-instance intercept).
  3. Repeat inverted: start storybook dev from packages/ui, then from the repo root run STORYBOOK_FEATURE_AI_CLI=1 npx storybook ai --config-dir packages/ui/.storybook get-changed-stories — should also resolve.
  4. From the repo root, run STORYBOOK_FEATURE_AI_CLI=1 npx storybook ai --config-dir packages/other/.storybook <command> targeting a package whose Storybook is NOT running — you should get the no-instance guidance (not a silent call to the wrong instance), listing the running instance with a copyable --config-dir retry.

Documentation

  • Add or update documentation reflecting your changes (storybook ai is behind the experimental STORYBOOK_FEATURE_AI_CLI flag; no public docs yet)
  • If you are deprecating/removing a feature, make sure to update MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts
  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

Summary by CodeRabbit

  • New Features

    • Added matching of running Storybook instances using the configured config directory in addition to working directory, including monorepo root-vs-package scenarios.
    • Enhanced “no-instance” and retry guidance with copyable storybook ai commands, including deduped examples and correct quoting; prefers --config-dir when available.
  • Bug Fixes

    • Port-mismatch and multi-instance messaging is now more project-scoped and includes relevant cwd/config directory context.
  • Documentation

    • Updated CLI help text for --config-dir to reflect correct placement before the command name.

Record the resolved configDir in the runtime instance record written by
storybook dev, and let storybook ai resolve an instance when either its
recorded cwd or its recorded config dir matches the CLI's target, so
monorepo instances are found from a different cwd. When nothing matches,
the no-instance guidance now lists the running instances with their
recorded cwd/config dir and copyable retry invocations.

Related to #35359
@kasperpeulen kasperpeulen added feature request cli ci:normal Run our default set of CI jobs (choose this for most PRs). labels Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 782a7c86-d5b8-4e41-987f-6ffccdd1cc07

📥 Commits

Reviewing files that changed from the base of the PR and between 8c5eb42 and f7d3894.

📒 Files selected for processing (2)
  • code/core/src/cli/ai/mcp/resolve-instance.ts
  • code/core/src/cli/ai/mcp/run-tool.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • code/core/src/cli/ai/mcp/resolve-instance.ts
  • code/core/src/cli/ai/mcp/run-tool.ts

📝 Walkthrough

Walkthrough

This PR adds optional configDir support to runtime instance records and MCP matching, updates resolution to use a ResolveTarget options object, and revises intercept/help text and tests for project-scoped cwd/configDir routing.

Changes

configDir-aware instance resolution

Layer / File(s) Summary
Runtime record and schema support
code/core/src/core-server/utils/runtime-instance-registry.ts, code/core/src/core-server/utils/runtime-instance-registry.test.ts, code/core/src/core-server/build-dev.ts, code/core/src/cli/ai/mcp/types.ts, code/core/src/cli/ai/mcp/registry.test.ts
RuntimeInstanceRecord and StorybookInstanceRecordSchema add optional configDir; runtime record creation and persistence forward it, and registry parsing accepts stored records with the field.
Resolve instances by cwd or configDir
code/core/src/cli/ai/mcp/resolve-instance.ts, code/core/src/cli/ai/mcp/resolve-instance.test.ts, code/core/src/cli/ai/mcp/run-tool.ts, code/core/src/cli/ai/mcp/run-tool.test.ts
resolveInstance switches to a ResolveTarget options object, normalizes cwd/configDir, matches project records by cwd or configDir, applies port filtering after project matching, and returns port-mismatch with project matches; call sites and tests are updated.
Project-scoped intercept and help text
code/core/src/cli/ai/mcp/intercepts.ts, code/core/src/cli/ai/mcp/intercepts.test.ts, code/core/src/cli/ai/mcp/register.ts, code/core/src/cli/ai/mcp/run-tool.test.ts
buildNoInstanceWithCandidates now lists cwd and optional config dir with deduplicated retry commands, buildPortMismatch uses project-scoped wording, CONFIG_DIR_DESCRIPTION is updated, and tests assert the new markdown and routing messages.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • storybookjs/storybook#35212: Both PRs update the storybook ai CLI to propagate and interpret --config-dir through shared option and routing code.
  • storybookjs/storybook#35235: Both PRs modify the resolve-instance and run-tool flow, extending the instance selection inputs and matching logic.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@kasperpeulen
kasperpeulen requested a review from huang-julien July 7, 2026 13:11
@kasperpeulen kasperpeulen added the qa:needed Pull Requests that will need manual QA prior to release. label Jul 7, 2026
Findings from a dual review (subagent + codex gpt-5.5 xhigh):
- An explicit --config-dir now restricts matching to records with that
  exact configDir; previously a same-cwd instance serving a different
  config could silently win. The defaulted .storybook guess keeps the
  either-or union.
- No-instance retry examples emit --config-dir (not --cwd) for records
  with a configDir, since a bare --cwd retry fails metadata loading when
  the config is not at <cwd>/.storybook; paths with whitespace are quoted.
- The multi-instance warning no longer claims 'at this cwd' and lists
  each competing instance's cwd/config dir, since matches can span cwds.
@kasperpeulen
kasperpeulen enabled auto-merge July 7, 2026 14:41

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/core/src/cli/ai/mcp/resolve-instance.ts (1)

68-98: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

code/core/src/cli/ai/mcp/resolve-instance.ts:81-87 — Handle case-insensitive cwd/configDir matching. resolve() preserves casing, so exact equality will miss the same directory when the path differs only by case on Windows/macOS. Canonicalize both sides before comparing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/core/src/cli/ai/mcp/resolve-instance.ts` around lines 68 - 98, The
current `resolveInstance` matching logic compares `cwd` and `configDir` with
exact `resolve()` equality, which can miss the same directory when only path
casing differs. Update the `matchesConfigDir` helper and the `projectMatches`
filter in `resolveInstance` to compare canonicalized, case-insensitive paths for
both `cwd` and `configDir`, so the same location is matched reliably on
Windows/macOS.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@code/core/src/cli/ai/mcp/resolve-instance.ts`:
- Around line 68-98: The current `resolveInstance` matching logic compares `cwd`
and `configDir` with exact `resolve()` equality, which can miss the same
directory when only path casing differs. Update the `matchesConfigDir` helper
and the `projectMatches` filter in `resolveInstance` to compare canonicalized,
case-insensitive paths for both `cwd` and `configDir`, so the same location is
matched reliably on Windows/macOS.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5610cde1-e526-4fa3-a728-198f494cbf12

📥 Commits

Reviewing files that changed from the base of the PR and between df2b432 and 8c5eb42.

📒 Files selected for processing (6)
  • code/core/src/cli/ai/mcp/intercepts.test.ts
  • code/core/src/cli/ai/mcp/intercepts.ts
  • code/core/src/cli/ai/mcp/resolve-instance.test.ts
  • code/core/src/cli/ai/mcp/resolve-instance.ts
  • code/core/src/cli/ai/mcp/run-tool.test.ts
  • code/core/src/cli/ai/mcp/run-tool.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • code/core/src/cli/ai/mcp/intercepts.test.ts
  • code/core/src/cli/ai/mcp/run-tool.ts
  • code/core/src/cli/ai/mcp/run-tool.test.ts
  • code/core/src/cli/ai/mcp/intercepts.ts
  • code/core/src/cli/ai/mcp/resolve-instance.test.ts

Comment thread code/core/src/cli/ai/mcp/intercepts.ts
Comment thread code/core/src/cli/ai/mcp/run-tool.ts Outdated
Comment thread code/core/src/cli/ai/mcp/run-tool.ts Outdated
Comment thread code/core/src/cli/ai/mcp/resolve-instance.ts Outdated
This was referenced Jul 14, 2026
@JReinhold JReinhold added qa:success Pull Requests that were successfully QA'ed by the release team. and removed qa:needed Pull Requests that will need manual QA prior to release. labels Aug 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor
Fails
🚫

node failed.

Log

Details
Error:  Error: Could not find the Dangerfile at scripts/dangerfile.ts - if it is local, perhaps you have a typo? If it's using a remote file, it doesn't have a repo reference.
    at /usr/src/danger/dist/platforms/GitHub.js:161:27
    at step (/usr/src/danger/dist/platforms/GitHub.js:44:23)
    at Object.next (/usr/src/danger/dist/platforms/GitHub.js:25:53)
    at /usr/src/danger/dist/platforms/GitHub.js:19:71
    at new Promise (<anonymous>)
    at __awaiter (/usr/src/danger/dist/platforms/GitHub.js:15:12)
    at Object.executeRuntimeEnvironment (/usr/src/danger/dist/platforms/GitHub.js:144:88)
    at /usr/src/danger/dist/commands/danger-runner.js:101:47
    at step (/usr/src/danger/dist/commands/danger-runner.js:34:23)
    at Object.next (/usr/src/danger/dist/commands/danger-runner.js:15:53)
danger-results://tmp/danger-results-f667354d.json

Generated by 🚫 dangerJS against f7d3894

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). cli feature request qa:success Pull Requests that were successfully QA'ed by the release team. upgrade:10.5 Issues/PRs found during 10.5 upgrade QA and post-release regressions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants