Skip to content

Commit 9da422f

Browse files
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.
1 parent 634df5a commit 9da422f

24 files changed

Lines changed: 972 additions & 241 deletions

File tree

docs/packages/cli.mdx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,6 @@ Needs a local Chrome, the same one `render` uses. Run
428428
within a frame or two — a different headless-Chrome audio sample rate can shift
429429
a beat slightly.
430430

431-
## Look at it
432-
433431
### `preview`
434432

435433
Start a live preview server with hot reload.
@@ -438,6 +436,8 @@ Start a live preview server with hot reload.
438436
npx hyperframes preview [dir]
439437
npx hyperframes preview --port 4567
440438
npx hyperframes preview --background # keep running after the command exits
439+
npx hyperframes preview --foreground # stay attached in a non-interactive shell
440+
npx hyperframes preview --status --json # inspect a managed preview from an agent
441441
npx hyperframes preview --list # every running preview
442442
```
443443

@@ -446,6 +446,8 @@ npx hyperframes preview --list # every running preview
446446
| `--port` | Server port (default 3002) |
447447
| `--open` / `--no-open` | Open a browser, or leave it closed |
448448
| `--background` | Keep an embedded preview running after the command exits |
449+
| `--foreground` | Keep the preview attached even when the shell is non-interactive |
450+
| `--json` | Emit one versioned JSON result for managed start, status, stop, list, and kill-all operations |
449451
| `--browser-gpu` / `--no-browser-gpu` | Hardware GPU for Studio thumbnails and frame capture, or deterministic SwiftShader (default: auto-detect) |
450452
| `--proxy` / `--no-proxy` | Auto-transcode browser-hostile codecs (HEVC, ProRes, AV1) to a cached authoring proxy (default: on) |
451453
| `--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
455457
`--force-new` starts a second server for a project that already has one. Each
456458
exits straight after.
457459

460+
Bare `preview` chooses the safest lifecycle for its caller: it stays in the
461+
foreground in a human interactive terminal, while a non-interactive or agent
462+
shell starts a managed background preview. Re-running the command for the same
463+
project reuses the healthy preview. Every start or status result includes the
464+
exact Studio project URL as well as the underlying server URL, so agents can
465+
hand off the intended project without guessing from the port.
466+
458467
To read a running Studio from a script: `--selection` prints the selected
459468
element and `--context` prints the agent-readable context, both with `--json`.
460469
Narrow the context with `--context-fields` (`server`, `selection`, `lint`,

packages/cli/README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,20 @@ Start the live preview studio in your browser:
3333

3434
```bash
3535
npx hyperframes preview
36-
# Studio running at http://localhost:3002
36+
# Studio: http://localhost:3002/#project/my-video
37+
# Server: http://localhost:3002
3738

3839
npx hyperframes preview --port 4567
3940
```
4041

42+
In an interactive terminal, the preview stays attached until you press
43+
Ctrl+C. In a non-interactive shell such as a coding-agent session, the same
44+
command starts a managed preview that survives after the command returns. Use
45+
`--background` or `--foreground` to choose explicitly, and manage persistent
46+
previews with `--status`, `--stop`, `--list`, and `--kill-all`. Add `--json` to
47+
managed lifecycle commands for machine-readable output. `--foreground --json`
48+
prints the ready-session envelope once, then remains attached until stopped.
49+
4150
### `render`
4251

4352
Render a composition to MP4. Run from the project directory; the positional

packages/cli/src/commands/coreSkillContent.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,15 @@ describe("media treatment routing documentation", () => {
125125
expect(template).toContain("do not improvise equivalent CSS/SVG filters or overlays");
126126
}
127127
});
128+
129+
it("gives agents a process-owned preview lifecycle in new project instructions", () => {
130+
for (const file of ["AGENTS.md", "CLAUDE.md"]) {
131+
const template = read("packages", "cli", "src", "templates", "_shared", file);
132+
expect(template).toContain("npx hyperframes preview --background");
133+
expect(template).toContain("npx hyperframes preview --status");
134+
expect(template).toContain("npx hyperframes preview --stop");
135+
expect(template).toContain("leaving refreshes at `ERR_CONNECTION_TIMED_OUT`");
136+
expect(template).not.toContain("run_in_background: true");
137+
}
138+
});
128139
});

0 commit comments

Comments
 (0)