@vercel/next-browser 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,25 +10,45 @@ Built for agents. An LLM can't read a DevTools panel, but it can run
10
10
  command is a stateless one-shot against a long-lived browser daemon, so an
11
11
  agent loop can fire them off without managing browser lifecycle.
12
12
 
13
- ## Install
13
+ ## Getting started
14
14
 
15
- ```bash
16
- pnpm add -g @vercel/next-browser
17
- ```
15
+ You don't install or run this directly. Your agent does.
18
16
 
19
- Requires Node `>=20`.
17
+ 1. **Add the skill to your project.** From your Next.js repo:
18
+
19
+ ```bash
20
+ npx skills add vercel-labs/next-browser
21
+ ```
22
+
23
+ Works with Claude Code, Cursor, Cline, and [others](https://skills.sh).
24
+
25
+ 2. **Start your agent** in that project.
26
+
27
+ 3. **Type `/next-browser`** to invoke the skill.
20
28
 
21
- ## Usage
29
+ 4. The skill checks for the CLI and **installs `@vercel/next-browser`
30
+ globally** if it's missing (plus `playwright install chromium`).
31
+
32
+ 5. It asks for your dev server URL and any cookies it needs, opens the
33
+ browser, and from there it's **pair programming** — tell it what you're
34
+ debugging and it drives the tree, navigates pages, inspects components,
35
+ and reads errors for you.
36
+
37
+ That's the whole flow. Run `npx skills upgrade` later to pull updates.
38
+
39
+ The rest of this README documents the raw CLI for the rare case where you're
40
+ scripting it yourself.
41
+
42
+ ---
43
+
44
+ ## Manual install
22
45
 
23
46
  ```bash
24
- next-browser open http://localhost:3000
25
- next-browser tree
26
- next-browser ppr lock
27
- next-browser push /dashboard
28
- next-browser ppr unlock
29
- next-browser close
47
+ pnpm add -g @vercel/next-browser
30
48
  ```
31
49
 
50
+ Requires Node `>=20`.
51
+
32
52
  ## Commands
33
53
 
34
54
  ```
@@ -41,7 +61,7 @@ back go back in history
41
61
  reload reload current page
42
62
  restart-server restart the Next.js dev server (clears fs cache)
43
63
 
44
- ppr lock enter PPR instant-navigation mode
64
+ ppr lock enter PPR instant-navigation mode (requires cacheComponents)
45
65
  ppr unlock exit PPR mode and show shell analysis
46
66
 
47
67
  tree show React component tree
package/dist/sourcemap.js CHANGED
@@ -24,6 +24,23 @@ export async function resolve(origin, file, line, column) {
24
24
  return null;
25
25
  return { file: frame.file, line: frame.line1, column: frame.column1 };
26
26
  }
27
+ import { resolve as resolvePath } from "node:path";
28
+ import * as mcp from "./mcp.js";
29
+ const projectRoots = new Map();
30
+ async function projectRoot(origin) {
31
+ if (projectRoots.has(origin))
32
+ return projectRoots.get(origin);
33
+ const meta = await mcp.call(origin, "get_project_metadata").catch(() => null);
34
+ const root = typeof meta?.projectPath === "string" ? meta.projectPath : null;
35
+ projectRoots.set(origin, root);
36
+ return root;
37
+ }
38
+ async function absolutize(origin, path) {
39
+ if (path.startsWith("/") || path.startsWith("node_modules/"))
40
+ return path;
41
+ const root = await projectRoot(origin);
42
+ return root ? resolvePath(root, path) : path;
43
+ }
27
44
  function normalize(file, origin) {
28
45
  const stripped = file.replace(/^about:\/\/React\/[^/]+\//, "");
29
46
  const isServer = file !== stripped;
@@ -48,7 +65,7 @@ export async function resolveViaMap(origin, file, line, column) {
48
65
  const pos = consumer.originalPositionFor({ line, column });
49
66
  if (!pos.source)
50
67
  return null;
51
- return { file: cleanPath(pos.source), line: pos.line, column: pos.column };
68
+ return { file: await absolutize(origin, cleanPath(pos.source)), line: pos.line, column: pos.column };
52
69
  }
53
70
  async function load(origin, path) {
54
71
  if (consumers.has(path))
package/dist/suspense.js CHANGED
@@ -276,10 +276,7 @@ async function inPageSuspense(inspect) {
276
276
  const awaited = entry?.awaited;
277
277
  if (!awaited)
278
278
  continue;
279
- const desc = awaited.description
280
- || awaited.value?.value
281
- || awaited.value?.preview_long
282
- || "";
279
+ const desc = preview(awaited.description) || preview(awaited.value);
283
280
  boundary.suspendedBy.push({
284
281
  name: awaited.name ?? "unknown",
285
282
  description: desc,
@@ -311,4 +308,25 @@ async function inPageSuspense(inspect) {
311
308
  }
312
309
  }
313
310
  }
311
+ function preview(v) {
312
+ if (v == null)
313
+ return "";
314
+ if (typeof v === "string")
315
+ return v;
316
+ if (typeof v !== "object")
317
+ return String(v);
318
+ if (typeof v.preview_long === "string")
319
+ return v.preview_long;
320
+ if (typeof v.preview_short === "string")
321
+ return v.preview_short;
322
+ if (typeof v.value === "string")
323
+ return v.value;
324
+ try {
325
+ const s = JSON.stringify(v);
326
+ return s.length > 80 ? s.slice(0, 77) + "..." : s;
327
+ }
328
+ catch {
329
+ return "";
330
+ }
331
+ }
314
332
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/next-browser",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Headed Playwright browser with React DevTools pre-loaded",
5
5
  "license": "MIT",
6
6
  "repository": {