…ry site first (#5351)
## Related issues
- Follows the discussion on #5317: get the site-start gain without a new
cache layer.
## How AI was used in this PR
Claude (via the Pi coding agent in a Roadie session) traced the CLI
processes behind a site start, wrote the change, and ran the local
checks below. I reviewed the code.
## Proposed Changes
`startServer` ran `site list` (a full CLI process, about 0.35 s) to look
up the site before running `site start`. The only thing a start needs is
the site's path, and `readSite()` reads it from `cli.json` without a CLI
process. `stopServer` already looks the site up that way.
- `startServer` reads the site from `cli.json` with `readSite()`.
- A site that `cli.json` doesn't have now fails the start with "Site not
found" instead of doing nothing, which used to end in a false "Site
started" toast. The same applies when `cli.json` can't be parsed;
before, `site list` failed on that.
- It runs `getSite()` for the CLI's full site details only after a
failed start. Those details feed PHP error recovery (port, PHP version)
and the Sentry context.
There is no new state or cache: the start reads the same `cli.json` that
`site list` reads.
## Testing Instructions
- Locally (macOS arm64, packaged build), I timed every CLI process
during the `tools/metrics` site-startup test. In each of the 5 restarts,
`site start` now begins about 0.1 s after the click, with no `site list`
ahead of it. On trunk, a `site list` ran first.
- The CI Performance Test Results comment gives the `siteStartup`
number.
## Pre-merge Checklist
- [x] Have you checked for TypeScript, React or other console errors?
Related issues
How AI was used in this PR
Claude (via the Pi coding agent in a Roadie session) found the spawn pattern in CI logs, wrote the change and tests, and ran the local measurements below. I reviewed the design and the code.
Proposed Changes
The app ran
site list --format json(a fresh CLI process each time) for everygetSites()/getSite(). That covers each renderer refetch after a site event, and also each IPC handler that looks up a site. In a desktop E2E run, 252 of 362 CLI processes weresite list.The app already runs the
_eventsstream, and each site event carries the site's full details plusrunning, computed the same waysite listcomputes it. So the main process now keeps the list:src/lib/site-list-cache.ts: holds the CLI's site list.site listand kept current by applying each site event._eventsruns.cli-events-subscriber.ts:execute-command.ts: addsonCliCommandFinished, which the subscriber uses to drop the list after commands.getSites(): unchanged for callers. Studio's metadata and PHP-recovery state are still merged on each read, and neither is cached.Testing Instructions
npx vitest run --project studio: 274 tests pass.site-list-cache.test.tscovers events, overlapping reads, events during a fetch, dropping, age, failures, and running without the stream.157fa556e(macOS arm64). CLI processes were counted with a wrapper around the bundlednode:site list/ all CLIsite list/ all CLIsites+site-navigationtools/metricssite-startup test, 3 interleaved local runs each. These are local estimates; CI's Performance Test Results will be the real number.siteStartup: 2318 / 2324 / 1817 ms vs base 3342 / 3325 / 2316 ms.siteCreation: about the same (6436 / 6478 / 6976 vs 6967 / 6471 / 6437 ms).siteStartup2865 → 2385 ms (−16.8%),siteCreation6532 → 6500 ms, editorloadunchanged.Pre-merge Checklist