@browserbasehq/cli 0.3.0 → 0.3.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Browserbase, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,20 +1,181 @@
1
1
  # Browserbase CLI
2
2
 
3
- Browserbase's Bun-native development repo for the `bb` CLI.
3
+ The official CLI for [Browserbase](https://browserbase.com). Manage sessions, deploy serverless functions, browse the web, and interact with the full Browserbase platform from your terminal.
4
4
 
5
- ## Development
5
+ ## Installation
6
6
 
7
7
  ```bash
8
- bun install
9
- bun run check
10
- bun run cli -- --help
8
+ npm install -g @browserbasehq/cli
9
+ ```
10
+
11
+ Requires Node.js 18+.
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Set your API key
17
+ export BROWSERBASE_API_KEY=bb_live_...
18
+
19
+ # Fetch a webpage
20
+ bb fetch https://example.com
21
+
22
+ # Search the web
23
+ bb search "browserbase documentation"
24
+
25
+ # Browse interactively
26
+ bb browse https://example.com
27
+
28
+ # List your sessions
29
+ bb sessions list
11
30
  ```
12
31
 
13
- ## Build
32
+ ## Commands
33
+
34
+ ### `bb fetch <url>`
35
+
36
+ Retrieve webpage content without a full browser session.
14
37
 
15
38
  ```bash
16
- bun run build
39
+ bb fetch https://example.com
40
+ bb fetch https://example.com --output page.json
41
+ bb fetch https://example.com --proxies --allow-redirects
17
42
  ```
18
43
 
19
- The published artifact is Node-compatible JavaScript in `dist/`, even though local
20
- development stays Bun-native.
44
+ | Flag | Description |
45
+ |------|-------------|
46
+ | `--output <path>` | Write response to file |
47
+ | `--proxies` | Enable Browserbase proxy support |
48
+ | `--allow-redirects` | Follow HTTP redirects |
49
+ | `--allow-insecure-ssl` | Bypass TLS certificate verification |
50
+
51
+ ### `bb search <query>`
52
+
53
+ Search the web using the Browserbase Search API.
54
+
55
+ ```bash
56
+ bb search "web automation tools"
57
+ bb search "browserbase" --num-results 5
58
+ ```
59
+
60
+ | Flag | Description |
61
+ |------|-------------|
62
+ | `--num-results <n>` | Number of results (1-25, default 10) |
63
+ | `--output <path>` | Write results to file |
64
+
65
+ ### `bb browse [args...]`
66
+
67
+ Launch a browser session. Forwards to the `@browserbasehq/browse-cli` package (auto-installs on first use).
68
+
69
+ ```bash
70
+ bb browse https://example.com
71
+ bb browse --yes # skip install prompt
72
+ ```
73
+
74
+ ### `bb sessions`
75
+
76
+ Manage remote browser sessions.
77
+
78
+ ```bash
79
+ bb sessions list # List all sessions
80
+ bb sessions list --q "status=RUNNING" # Filter by metadata
81
+ bb sessions get <session-id> # Get session details
82
+ bb sessions create --body '{"projectId":"..."}'
83
+ bb sessions update <id> --status REQUEST_RELEASE
84
+ bb sessions debug <id> # Get debugger connection URLs
85
+ bb sessions logs <id> # View session logs
86
+ bb sessions recording <id> # Get rrweb recording events
87
+ bb sessions downloads get <id> # Download session artifacts (ZIP)
88
+ bb sessions uploads create <id> <file> # Upload a file to a session
89
+ ```
90
+
91
+ ### `bb functions`
92
+
93
+ Write and deploy serverless browser automation to the cloud.
94
+
95
+ ```bash
96
+ # Scaffold a new project
97
+ bb functions init my-function
98
+
99
+ # Run locally
100
+ bb functions dev handler.ts --port 3000
101
+
102
+ # Deploy to Browserbase
103
+ bb functions publish handler.ts
104
+ bb functions publish handler.ts --dry-run # preview without deploying
105
+
106
+ # Invoke a deployed function
107
+ bb functions invoke <function-id> --params '{"url":"https://example.com"}'
108
+ bb functions invoke --check-status <invocation-id>
109
+ ```
110
+
111
+ | Subcommand | Description |
112
+ |------------|-------------|
113
+ | `init [name]` | Scaffold a Functions project (`--package-manager npm\|pnpm`) |
114
+ | `dev <entry>` | Start local dev server (`--port`, `--host`, `--verbose`) |
115
+ | `publish <entry>` | Deploy function (`--dry-run`) |
116
+ | `invoke [id]` | Invoke a function (`--params`, `--no-wait`, `--check-status`) |
117
+
118
+ ### `bb projects`
119
+
120
+ Manage Browserbase projects.
121
+
122
+ ```bash
123
+ bb projects list
124
+ bb projects get <project-id>
125
+ bb projects usage <project-id>
126
+ ```
127
+
128
+ ### `bb contexts`
129
+
130
+ Persist browser state (cookies, localStorage) across sessions.
131
+
132
+ ```bash
133
+ bb contexts create --body '{"projectId":"..."}'
134
+ bb contexts get <context-id>
135
+ bb contexts update <context-id> # Refresh upload URL
136
+ bb contexts delete <context-id>
137
+ ```
138
+
139
+ ### `bb extensions`
140
+
141
+ Manage Chrome extensions for remote sessions.
142
+
143
+ ```bash
144
+ bb extensions upload extension.zip
145
+ bb extensions get <extension-id>
146
+ bb extensions delete <extension-id>
147
+ ```
148
+
149
+ ### `bb skills`
150
+
151
+ Install Browserbase agent skills for Claude Code.
152
+
153
+ ```bash
154
+ bb skills # Interactive install
155
+ bb skills install # Non-interactive install
156
+ bb skills --yes # Auto-accept prompts
157
+ ```
158
+
159
+ ## Configuration
160
+
161
+ | Environment Variable | Description |
162
+ |---------------------|-------------|
163
+ | `BROWSERBASE_API_KEY` | Your Browserbase API key (required) |
164
+ | `BROWSERBASE_PROJECT_ID` | Default project ID for Functions |
165
+ | `BROWSERBASE_BASE_URL` | Custom API base URL |
166
+
167
+ All environment variables can be overridden per-command with `--api-key`, `--project-id`, or `--base-url` flags.
168
+
169
+ ## Development
170
+
171
+ ```bash
172
+ bun install
173
+ bun run cli -- --help # Run locally
174
+ bun run check # Type-check
175
+ bun run build # Build to dist/
176
+ bun run test # Build + run tests
177
+ ```
178
+
179
+ ## License
180
+
181
+ This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
package/dist/cli.js CHANGED
@@ -4,7 +4,6 @@ import { attachBrowseCommand } from "./commands/browse.js";
4
4
  const require = createRequire(import.meta.url);
5
5
  const { version } = require("../package.json");
6
6
  import { attachContextsCommand } from "./commands/contexts.js";
7
- import { attachDashboardCommand } from "./commands/dashboard.js";
8
7
  import { attachExtensionsCommand } from "./commands/extensions.js";
9
8
  import { attachFetchCommand } from "./commands/fetch.js";
10
9
  import { attachFunctionsCommand } from "./commands/functions.js";
@@ -12,6 +11,7 @@ import { attachSearchCommand } from "./commands/search.js";
12
11
  import { attachProjectsCommand } from "./commands/projects.js";
13
12
  import { attachSessionsCommand } from "./commands/sessions.js";
14
13
  import { attachSkillsCommand } from "./commands/skills.js";
14
+ import { attachBCommand } from "./commands/b.js";
15
15
  export function buildProgram() {
16
16
  const program = new Command();
17
17
  program
@@ -27,12 +27,12 @@ export function buildProgram() {
27
27
  attachFetchCommand(program);
28
28
  attachSearchCommand(program);
29
29
  attachSessionsCommand(program);
30
- attachDashboardCommand(program);
31
30
  attachFunctionsCommand(program);
32
31
  attachProjectsCommand(program);
33
32
  attachContextsCommand(program);
34
33
  attachExtensionsCommand(program);
35
34
  attachSkillsCommand(program);
35
+ attachBCommand(program);
36
36
  return program;
37
37
  }
38
38
  export async function run(argv) {
@@ -0,0 +1,19 @@
1
+ const B_LINES = [
2
+ "██████╗ ",
3
+ "██╔══██╗",
4
+ "██████╔╝",
5
+ "██╔══██╗",
6
+ "██████╔╝",
7
+ "╚═════╝ ",
8
+ ];
9
+ export function attachBCommand(program) {
10
+ program
11
+ .command("b [extra]", { hidden: true })
12
+ .description("🅱️")
13
+ .action((extra) => {
14
+ const count = 1 + (extra ? extra.length : 0);
15
+ for (const line of B_LINES) {
16
+ console.log(Array(count).fill(line).join(" "));
17
+ }
18
+ });
19
+ }
@@ -1,5 +1,24 @@
1
+ import * as readline from "node:readline/promises";
1
2
  import { fail } from "../lib/command.js";
2
3
  import { findExecutable, spawnPassthrough } from "../lib/process.js";
4
+ async function installBrowseCli() {
5
+ const npmPath = await findExecutable("npm");
6
+ if (!npmPath) {
7
+ fail([
8
+ "`npm` is not installed.",
9
+ "Install Node.js from https://nodejs.org to get npm,",
10
+ "then rerun `bb browse`.",
11
+ ].join("\n"));
12
+ }
13
+ const exitCode = await spawnPassthrough(npmPath, [
14
+ "install",
15
+ "-g",
16
+ "@browserbasehq/browse-cli",
17
+ ]);
18
+ if (exitCode !== 0) {
19
+ process.exitCode = exitCode;
20
+ }
21
+ }
3
22
  export function attachBrowseCommand(program) {
4
23
  program
5
24
  .command("browse")
@@ -8,18 +27,42 @@ export function attachBrowseCommand(program) {
8
27
  .allowUnknownOption(true)
9
28
  .allowExcessArguments(true)
10
29
  .passThroughOptions()
30
+ .helpOption(false)
11
31
  .action(async (args) => {
12
- const browsePath = await findExecutable("browse");
32
+ let browsePath = await findExecutable("browse");
13
33
  if (!browsePath) {
14
- fail([
34
+ console.log([
35
+ "",
15
36
  "`browse` is not installed.",
16
- "Install it with:",
17
- "npm install -g @browserbasehq/browse-cli",
37
+ "Automate web browser interactions using natural language via CLI commands.",
38
+ "",
39
+ " npm install -g @browserbasehq/browse-cli",
18
40
  "",
19
- "Then rerun your `bb browse ...` command.",
20
41
  ].join("\n"));
42
+ const rl = readline.createInterface({
43
+ input: process.stdin,
44
+ output: process.stdout,
45
+ });
46
+ try {
47
+ const answer = await rl.question("Install now? [Y/n] ");
48
+ if (answer.trim().toLowerCase() === "n") {
49
+ return;
50
+ }
51
+ }
52
+ finally {
53
+ rl.close();
54
+ }
55
+ await installBrowseCli();
56
+ browsePath = await findExecutable("browse");
57
+ if (!browsePath) {
58
+ fail([
59
+ "Installation succeeded but `browse` was not found on PATH.",
60
+ "You may need to restart your shell, then rerun your command.",
61
+ ].join("\n"));
62
+ }
21
63
  }
22
- const exitCode = await spawnPassthrough(browsePath, args ?? []);
64
+ const forwardArgs = args && args.length > 0 ? args : ["--help"];
65
+ const exitCode = await spawnPassthrough(browsePath, forwardArgs);
23
66
  if (exitCode !== 0) {
24
67
  process.exitCode = exitCode;
25
68
  }
@@ -1,4 +1,4 @@
1
- import { addCommonApiOptions, createBrowserbaseClient, mergeProjectIdIntoBody, outputJson, parseOptionalJsonObjectArg, requestBrowserbase, requestBrowserbaseJson, resolveProjectId, } from "../lib/command.js";
1
+ import { addCommonApiOptions, createBrowserbaseClient, outputJson, parseOptionalJsonObjectArg, requestBrowserbase, requestBrowserbaseJson, } from "../lib/command.js";
2
2
  export function attachContextsCommand(program) {
3
3
  const contexts = program
4
4
  .command("contexts")
@@ -12,7 +12,7 @@ export function attachContextsCommand(program) {
12
12
  .description("Create a context.")
13
13
  .option("--body <body>", "Optional JSON request body.")).action(async (options) => {
14
14
  const client = createBrowserbaseClient(options);
15
- const body = mergeProjectIdIntoBody(resolveProjectId(options), parseOptionalJsonObjectArg(options.body, "body"));
15
+ const body = parseOptionalJsonObjectArg(options.body, "body");
16
16
  outputJson(await client.contexts.create(body));
17
17
  });
18
18
  addCommonApiOptions(contexts
@@ -16,20 +16,15 @@ export function attachFetchCommand(program) {
16
16
  });
17
17
  if (options.output) {
18
18
  await writeOutputFile(options.output, result.content);
19
- if (options.json) {
20
- outputJson({ ...result, outputPath: options.output });
21
- return;
22
- }
23
- console.log(`Saved fetched content to ${options.output}`);
19
+ outputJson({
20
+ ok: true,
21
+ outputPath: options.output,
22
+ contentType: result.contentType,
23
+ statusCode: result.statusCode,
24
+ sizeBytes: Buffer.byteLength(result.content, "utf8"),
25
+ });
24
26
  return;
25
27
  }
26
- if (options.json) {
27
- outputJson(result);
28
- return;
29
- }
30
- process.stdout.write(result.content);
31
- if (!result.content.endsWith("\n")) {
32
- process.stdout.write("\n");
33
- }
28
+ outputJson(result);
34
29
  });
35
30
  }
@@ -13,30 +13,15 @@ export function attachSearchCommand(program) {
13
13
  });
14
14
  if (options.output) {
15
15
  await writeOutputFile(options.output, JSON.stringify(result, null, 2));
16
- if (options.json) {
17
- outputJson({ ...result, outputPath: options.output });
18
- return;
19
- }
20
- console.log(`Saved search results to ${options.output}`);
16
+ outputJson({
17
+ ok: true,
18
+ outputPath: options.output,
19
+ requestId: result.requestId,
20
+ query: result.query,
21
+ resultCount: result.results.length,
22
+ });
21
23
  return;
22
24
  }
23
- if (options.json) {
24
- outputJson(result);
25
- return;
26
- }
27
- for (const [i, r] of result.results.entries()) {
28
- const num = i + 1;
29
- console.log(`${String(num)}. ${r.title}`);
30
- console.log(` ${r.url}`);
31
- const meta = [];
32
- if (r.author)
33
- meta.push(r.author);
34
- if (r.publishedDate)
35
- meta.push(r.publishedDate);
36
- if (meta.length > 0) {
37
- console.log(` ${meta.join(" · ")}`);
38
- }
39
- console.log();
40
- }
25
+ outputJson(result);
41
26
  });
42
27
  }
@@ -1,5 +1,5 @@
1
1
  import { Option } from "commander";
2
- import { addCommonApiOptions, createBrowserbaseClient, fail, mergeProjectIdIntoBody, outputJson, parseOptionalJsonObjectArg, resolveProjectId, resolveUploadableFile, writeBinaryOutput, } from "../lib/command.js";
2
+ import { addCommonApiOptions, createBrowserbaseClient, fail, outputJson, parseOptionalJsonObjectArg, resolveUploadableFile, writeBinaryOutput, } from "../lib/command.js";
3
3
  export function attachSessionsCommand(program) {
4
4
  const sessions = program
5
5
  .command("sessions")
@@ -11,7 +11,7 @@ export function attachSessionsCommand(program) {
11
11
  addCommonApiOptions(sessions
12
12
  .command("list")
13
13
  .description("List sessions.")
14
- .option("--q <q>", "Session metadata query.")).action(async (options) => {
14
+ .option("--q <q>", `Session metadata query (e.g. "user_metadata['env']:'staging'").`)).action(async (options) => {
15
15
  const client = createBrowserbaseClient(options);
16
16
  outputJson(await client.sessions.list(options.q ? { q: options.q } : {}));
17
17
  });
@@ -26,7 +26,7 @@ export function attachSessionsCommand(program) {
26
26
  .description("Create a session.")
27
27
  .option("--body <body>", "Optional JSON request body.")).action(async (options) => {
28
28
  const client = createBrowserbaseClient(options);
29
- const body = mergeProjectIdIntoBody(resolveProjectId(options), parseOptionalJsonObjectArg(options.body, "body"));
29
+ const body = parseOptionalJsonObjectArg(options.body, "body");
30
30
  outputJson(await client.sessions.create(body));
31
31
  });
32
32
  addCommonApiOptions(sessions
@@ -38,10 +38,10 @@ export function attachSessionsCommand(program) {
38
38
  .option("--body <body>", "Optional JSON request body. Merged with --status when provided.")).action(async (id, options) => {
39
39
  const client = createBrowserbaseClient(options);
40
40
  const sessionId = id || fail("Session ID is required.");
41
- const body = mergeProjectIdIntoBody(resolveProjectId(options), {
41
+ const body = {
42
42
  ...parseOptionalJsonObjectArg(options.body, "body"),
43
43
  status: options.status ?? "REQUEST_RELEASE",
44
- });
44
+ };
45
45
  outputJson(await client.sessions.update(sessionId, body));
46
46
  });
47
47
  addCommonApiOptions(sessions
@@ -17,10 +17,7 @@ export function fail(message, exitCode = 1) {
17
17
  export function addCommonApiOptions(command) {
18
18
  return command
19
19
  .option("--api-key <apiKey>", "Override the Browserbase API key.")
20
- .option("--project-id <projectId>", "Override the Browserbase project ID.")
21
- .option("--base-url <baseUrl>", "Override the Browserbase API base URL.")
22
- .option("--json", "Print JSON output.")
23
- .option("--verbose", "Enable verbose logging.");
20
+ .option("--base-url <baseUrl>", "Override the Browserbase API base URL.");
24
21
  }
25
22
  export function addFunctionsApiOptions(command, options = {}) {
26
23
  const { includeProjectId = false, includeVerbose = false } = options;
@@ -91,12 +88,6 @@ export function parseOptionalJsonValueArg(rawValue, label) {
91
88
  fail(`Invalid JSON for ${label}: ${error.message}`);
92
89
  }
93
90
  }
94
- export function mergeProjectIdIntoBody(projectId, body) {
95
- if (projectId && body.projectId === undefined) {
96
- return { ...body, projectId };
97
- }
98
- return body;
99
- }
100
91
  export function outputJson(value) {
101
92
  console.log(JSON.stringify(value, null, 2));
102
93
  }
@@ -64,7 +64,7 @@ export async function initFunctionsProject({ projectName, packageManager, }) {
64
64
  type: "module",
65
65
  scripts: {
66
66
  dev: "bb functions dev index.ts",
67
- publish: "bb functions publish index.ts",
67
+ deploy: "bb functions publish index.ts",
68
68
  },
69
69
  };
70
70
  await writeFile(join(projectRoot, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
@@ -90,6 +90,7 @@ export async function initFunctionsProject({ projectName, packageManager, }) {
90
90
  console.log(` cd ${projectName}`);
91
91
  console.log(" Edit .env with your Browserbase credentials");
92
92
  console.log(` ${packageManager === "pnpm" ? "pnpm" : "npm run"} dev`);
93
+ console.log(` ${packageManager === "pnpm" ? "pnpm run deploy" : "npm run deploy"}`);
93
94
  }
94
95
  function runPackageManager(packageManager, args, cwd) {
95
96
  const result = spawnSync(packageManager, args, {
@@ -1,7 +1,8 @@
1
1
  import archiver from "archiver";
2
2
  import ignore from "ignore";
3
- import { createWriteStream, existsSync, readFileSync } from "node:fs";
3
+ import { copyFileSync, createWriteStream, existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
4
4
  import { readFile, readdir, stat } from "node:fs/promises";
5
+ import { spawnSync } from "node:child_process";
5
6
  import { tmpdir } from "node:os";
6
7
  import { join, relative } from "node:path";
7
8
  import { randomUUID } from "node:crypto";
@@ -25,21 +26,24 @@ const defaultIgnorePatterns = [
25
26
  export async function publishFunction(options) {
26
27
  const entrypoint = await resolveEntrypoint(options.entrypoint);
27
28
  const config = resolveFunctionsProjectConfig(options);
28
- const archivePath = await createArchive(process.cwd(), options.dryRun);
29
- const metadata = {
30
- entrypoint: relative(process.cwd(), entrypoint),
31
- projectId: config.projectId,
32
- };
33
29
  if (options.dryRun) {
30
+ const { archivePath, entries } = await createArchive(process.cwd());
34
31
  console.log(JSON.stringify({
35
32
  dryRun: true,
36
33
  apiUrl: config.apiUrl,
37
34
  projectId: config.projectId,
38
- entrypoint: metadata.entrypoint,
35
+ entrypoint: relative(process.cwd(), entrypoint),
39
36
  archivePath,
37
+ files: entries,
40
38
  }, null, 2));
41
39
  return;
42
40
  }
41
+ ensureNpmLockfile(process.cwd());
42
+ const { archivePath, entries } = await createArchive(process.cwd());
43
+ const metadata = {
44
+ entrypoint: relative(process.cwd(), entrypoint),
45
+ projectId: config.projectId,
46
+ };
43
47
  const formData = new FormData();
44
48
  formData.append("metadata", JSON.stringify(metadata));
45
49
  formData.append("archive", new Blob([await readFile(archivePath)], {
@@ -69,13 +73,10 @@ export async function publishFunction(options) {
69
73
  process.exitCode = 1;
70
74
  }
71
75
  }
72
- async function createArchive(root, dryRun) {
76
+ async function createArchive(root) {
73
77
  const archivePath = join(tmpdir(), `browserbase-functions-${randomUUID()}.tar.gz`);
74
78
  const ignoreMatcher = await loadIgnoreMatcher(root);
75
79
  const entries = await listArchiveEntries(root, root, ignoreMatcher);
76
- if (dryRun) {
77
- console.log(JSON.stringify({ files: entries }, null, 2));
78
- }
79
80
  await new Promise((resolve, reject) => {
80
81
  const output = createWriteStream(archivePath);
81
82
  const archive = archiver("tar", {
@@ -97,7 +98,27 @@ async function createArchive(root, dryRun) {
97
98
  }
98
99
  archive.finalize().catch(reject);
99
100
  });
100
- return archivePath;
101
+ return { archivePath, entries };
102
+ }
103
+ function ensureNpmLockfile(root) {
104
+ if (existsSync(join(root, "package-lock.json"))) {
105
+ return;
106
+ }
107
+ // Generate in a temp directory to avoid conflicts with pnpm's node_modules
108
+ // structure, then copy the lockfile back.
109
+ const tmpDir = join(tmpdir(), `bb-lockgen-${randomUUID()}`);
110
+ mkdirSync(tmpDir, { recursive: true });
111
+ copyFileSync(join(root, "package.json"), join(tmpDir, "package.json"));
112
+ const result = spawnSync("npm", ["install", "--package-lock-only"], {
113
+ cwd: tmpDir,
114
+ stdio: "pipe",
115
+ });
116
+ if (result.status !== 0) {
117
+ rmSync(tmpDir, { recursive: true, force: true });
118
+ fail("Failed to generate package-lock.json. The build server requires an npm lockfile.");
119
+ }
120
+ copyFileSync(join(tmpDir, "package-lock.json"), join(root, "package-lock.json"));
121
+ rmSync(tmpDir, { recursive: true, force: true });
101
122
  }
102
123
  async function loadIgnoreMatcher(root) {
103
124
  const matcher = ignore();
@@ -1,7 +1,7 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { stat } from "node:fs/promises";
3
3
  import { extname, resolve } from "node:path";
4
- import { fail, outputJson, resolveApiKey, resolveProjectId } from "../command.js";
4
+ import { fail, resolveApiKey, resolveProjectId } from "../command.js";
5
5
  const defaultFunctionsApiUrl = "https://api.browserbase.com";
6
6
  export function resolveFunctionsApiConfig(args) {
7
7
  return {
@@ -103,14 +103,3 @@ export function ensureCommand(command) {
103
103
  fail(`${command} is required but was not found on PATH.`);
104
104
  }
105
105
  }
106
- export function printFunctionsJsonOrMessage(value, options = {}) {
107
- if (options.json) {
108
- outputJson(value);
109
- return;
110
- }
111
- if (options.message) {
112
- console.log(options.message);
113
- return;
114
- }
115
- outputJson(value);
116
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserbasehq/cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Browserbase CLI for platform APIs, functions, and browse passthrough.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -1,11 +0,0 @@
1
- import { openUrl } from "../lib/open.js";
2
- export function attachDashboardCommand(program) {
3
- program
4
- .command("dashboard")
5
- .description("Open the Browserbase web dashboard for your project.")
6
- .action(async () => {
7
- const url = "http://browserbase.com/overview";
8
- await openUrl(url);
9
- console.log(`Opened ${url}`);
10
- });
11
- }