feat(cli): run a managed background preview in every launch mode (#3310)

`--background` was rejected outside the embedded server. It now re-execs the
CLI in foreground, which makes it mode-agnostic by construction: whichever
server the child resolves to serves the config endpoint the readiness probe
looks for. `--foreground` is its counterpart, for a non-interactive shell that
wants to stay attached, and a bare launch keeps the same promise — attached in
an interactive terminal, managed in an agent session.

That generalization exposed an existing hole. Local-studio mode runs Vite with
the studio package as its cwd and needs that package's own Vite config, which
the published tarball does not carry, but resolving the package was treated as
proof the mode was usable. An npm-installed studio therefore took a path that
can never come up — previously a clear error, now a ten-second silent timeout.
The predicate becomes "can this studio actually be served", so a published
install falls back to embedded mode, which works.

Over the 1k line budget at ~1.3k. The overage is one command file and its
tests carrying one invariant, and the seam that would split it further is
inside a single request-handling function — a split there would produce two
PRs neither of which starts a preview on its own.
This commit is contained in:
Miguel Ángel
2026-08-19 17:02:44 -04:00
committed by GitHub
parent 634df5a5af
commit 9da422fd7f
24 changed files with 980 additions and 249 deletions
+11 -2
View File
@@ -428,8 +428,6 @@ Needs a local Chrome, the same one `render` uses. Run
within a frame or two — a different headless-Chrome audio sample rate can shift
a beat slightly.
## Look at it
### `preview`
Start a live preview server with hot reload.
@@ -438,6 +436,8 @@ Start a live preview server with hot reload.
npx hyperframes preview [dir]
npx hyperframes preview --port 4567
npx hyperframes preview --background # keep running after the command exits
npx hyperframes preview --foreground # stay attached in a non-interactive shell
npx hyperframes preview --status --json # inspect a managed preview from an agent
npx hyperframes preview --list # every running preview
```
@@ -446,6 +446,8 @@ npx hyperframes preview --list # every running preview
| `--port` | Server port (default 3002) |
| `--open` / `--no-open` | Open a browser, or leave it closed |
| `--background` | Keep an embedded preview running after the command exits |
| `--foreground` | Keep the preview attached even when the shell is non-interactive |
| `--json` | Emit one versioned JSON result for managed start, status, stop, list, and kill-all operations |
| `--browser-gpu` / `--no-browser-gpu` | Hardware GPU for Studio thumbnails and frame capture, or deterministic SwiftShader (default: auto-detect) |
| `--proxy` / `--no-proxy` | Auto-transcode browser-hostile codecs (HEVC, ProRes, AV1) to a cached authoring proxy (default: on) |
| `--browser-path` | Open a specific browser. `--user-data-dir`, `--remote-debugging-port`, and `--browser-no-gpu` require it. |
@@ -455,6 +457,13 @@ background preview, `--list` and `--kill-all` act on all of them, and
`--force-new` starts a second server for a project that already has one. Each
exits straight after.
Bare `preview` chooses the safest lifecycle for its caller: it stays in the
foreground in a human interactive terminal, while a non-interactive or agent
shell starts a managed background preview. Re-running the command for the same
project reuses the healthy preview. Every start or status result includes the
exact Studio project URL as well as the underlying server URL, so agents can
hand off the intended project without guessing from the port.
To read a running Studio from a script: `--selection` prints the selected
element and `--context` prints the agent-readable context, both with `--json`.
Narrow the context with `--context-fields` (`server`, `selection`, `lint`,