Repository navigation
Studio CLI: Load the MCP server only when studio mcp runs - #5235
Merged
Merged
Conversation
commands/mcp.ts imported the MCP runtime at the top, and the CLI entry imports every command module at startup, so every studio command loaded the whole agent runtime (the Pi agent, its tools, highlight.js, typebox) before running: 3,765 modules for studio --version. The MCP runtime now loads inside the command, as studio ai already does. A test imports everything the entry imports statically and checks the agent runtime stays unloaded. Vitest gets the @studio/local alias the build already has, so commands/ui.ts can load in tests.
chubes4
marked this pull request as ready for review
October 21, 2026 04:14
Collaborator
📊 Performance Test ResultsComparing 017afa5 vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
1 task done
chubes4
added a commit
that referenced
this pull request
Oct 23, 2026
## Related issues - Follows #5235, which stopped every `studio` command from loading the agent runtime. The Studio app runs the CLI for nearly everything (site list, start, stop, events), so CLI startup time adds to each of those. ## How AI was used in this PR Claude (via the Pi coding agent in a Roadie session) profiled `studio` startup in the packaged app, found the cost, wrote the change and the test, and took the timings below. I reviewed the diff and the numbers. ## Proposed Changes The CLI keeps its npm dependencies external, so an import of the `date-fns` root loads every date-fns function: about 300 modules, for the 8 functions Studio uses. With the packaged app's Node and `node_modules`, `import( 'date-fns' )` alone takes about 0.9 s; `import( 'date-fns/isSameDay' )` takes about 15 ms. Every `studio` command paid this, because `lib/snapshots.ts` and `lib/site-runtime-stats.ts` are on the startup path. - Each date-fns function is imported from its own path (`date-fns/format`, …), in the CLI and in the two `@studio/common` files the CLI uses. `DurationUnit` stays a type-only import from the root, which is erased at build time. - The startup-imports test from #5235 now also checks that nothing on the startup path loads the `date-fns` root. It fails on trunk. ## Testing Instructions - `npx vitest run apps/cli/tests/startup-imports.test.ts` passes; on trunk it fails. - CLI unit tests (124 files, 1,241 tests) and `packages/common` tests (87 files, 862 tests) pass. - Timings on an M-series Mac, using the packaged app's `resources/bin/node` and `resources/cli/node_modules` with each build's `dist/cli`, runs interleaved: | | Trunk | This branch | |---|---|---| | `studio site list --help`, 12 runs | median 1.13 s (0.83–3.36) | median 0.53 s (0.42–1.62) | | `studio --version`, 7 runs | median 1.53 s | median 0.72 s | | Modules loaded by `studio --version` | 863 | 621 | - The "Performance Test Results" comment on this PR should show lower `siteCreation` and `siteStartup`. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
This was referenced Oct 23, 2026
chubes4
added a commit
that referenced
this pull request
Oct 27, 2026
## Related issues - Follows #5235, #5313 and #5316, which kept the MCP server, the `date-fns` root and `@inquirer/prompts` off CLI startup. ## How AI was used in this PR Claude (via the Pi coding agent in a Roadie session) profiled CLI startup, wrote the change and the test, and measured the before/after timings. I reviewed the diff and the measurements. ## Proposed Changes `apps/cli/index.ts` statically imported every top-level command module, and each module held the command's whole implementation. So every `studio` invocation loaded the implementation of every command before running one, including the export, import, push and pull code and its archive, upload and certificate libraries: 1,375 dependency files from 109 packages for `studio --version`. Each top-level command now has a `.command` module that defines the command (name, description, options) and loads the implementation with `await import()` in its handler, the pattern `wp` and `_events` already use. The implementation modules keep their paths and their `runCommand` exports, so their other callers are unchanged; each one's former handler body is now its exported `commandHandler`. - `studio list`, `start`, `stop`, `create` and `wp` load 520 dependency files at startup instead of 1,375. - Help output, unknown-command errors and option validation are byte-identical to trunk. - A `CommandArgs< typeof builder >` type keeps each handler typed from its command's options. Local timings on macOS (median of 8 alternating runs, Node 24): | Command | trunk | this PR | | --- | --- | --- | | `studio --version` | 0.40 s | 0.21 s | | `studio list` | 0.39 s | 0.23 s | | `studio status` | 0.42 s | 0.24 s | | `studio wp option get blogname` | 0.67 s | 0.48 s | | `studio stop` / `start` (already in that state) | 0.44 s | 0.26 s | The saving is a fixed cost per CLI process, so it applies to every command the desktop app and Studio Code run through the CLI. ## Testing Instructions - `npx vitest run --project cli apps/cli/tests/startup-imports.test.ts`: loading what `index.ts` imports statically must not load any command implementation. Making a `.command` module import its implementation statically fails it. - Build the CLI and compare `studio --help`, `studio create --help` and `studio foo` with trunk's output. - Time `studio list` or `studio wp option get blogname` against trunk. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issues
studio wpfrom the agent's shell, sostudiostartup time adds to every WP-CLI call.How AI was used in this PR
Claude (via the Pi coding agent in a Roadie session) profiled
studiostartup, traced the import chain, wrote the change and the test, and took the timings below. I reviewed the diff and the numbers.Proposed Changes
Every
studiocommand loaded the whole agent runtime before running. The CLI entry imports each command module up front, andcommands/mcp.tsimported the MCP server at its top, which brings every agent tool and the Pi agent with them (highlight.js, typebox, undici, …).studio --versionloaded 3,765 modules, and about 4,000 in the shipped 1.24.0 app.studio mcpnow loads the MCP server inside the command, the same waystudio aialready loads its runtime.index.ts, so a command added later is covered too. It fails on trunk.@studio/localalias the build already has. Without it, no test could loadcommands/ui.ts.Testing Instructions
npx vitest run apps/cli/tests/startup-imports.test.tspasses; with thecommands/mcp.tschange reverted, it fails.npx vitest run --project cli: 1,158 pass.cd apps/cli && npx vite build --config ./vite.config.dev.ts), same machine, 5 runs each:node dist/cli/main.mjs --versionnode dist/cli/main.mjs wp --path=<site> option get siteurlstudio mcpstill starts the MCP server: afterinitialize,tools/listreturns its 30 tools.Pre-merge Checklist