feat(cli): add --stagehand flag to browse cloud extensions upload

Merged
SH
10h ago
+111-10

Upload the bundled Stagehand extension directly without requiring a file path. Uses getExtensionArchive() from @browserbasehq/stagehand and passes the bytes via toFile() to the Browserbase API.

why

what changed

test plan


Summary by cubic

Adds a --stagehand flag to browse cloud extensions upload so the bundled Stagehand extension can be uploaded without a file path; the archive bytes come from getExtensionArchive() and are sent to the Browserbase API without writing a temp file.

  • The file argument is now optional; you must provide either a file path or --stagehand.
  • Passing both --stagehand and a file path errors out.

why

Sean added a public getExtensionArchive() helper to the Stagehand SDK (packages/sdk-ts/src/extensionAssets.ts, #3267) so users can get the bundled extension ZIP without reaching into node_modules/@browserbasehq/stagehand/dist/assets/stagehand-extension.zip—a path that may change across releases. He asked for the CLI and docs to use it.

The existing browse cloud extensions upload <file> command only accepts a filesystem path, so users had to pass that brittle internal path directly. This adds a --stagehand flag that handles the export and upload in one step.

what changed

  • Add --stagehand boolean flag to browse cloud extensions upload
  • With --stagehand: call getExtensionArchive() from @browserbasehq/stagehand to get the Uint8Array, wrap it with the Browserbase SDK's toFile(bytes, "stagehand-extension.zip", { type: "application/zip" }), and pass that to client.extensions.create(). No temp file is written.
  • Make the file positional arg optional (was required)
  • Validation: --stagehand and file are mutually exclusive; providing both exits 1 with "Cannot specify both --stagehand and a file path.". Providing neither exits 1 with "Provide a file path or use --stagehand to upload the Stagehand extension."
  • Existing <file> path behavior unchanged—still uses resolveUploadableFile() to stream from disk
  • Output unchanged: prints the JSON response from extensions.create (includes id)
  • Update command description and examples in help
  • Add Browse patch changeset
  • Add 3 tests in packages/cli/tests/cli-cloud-contract.test.ts:
    • extensions upload --stagehand uploads the bundled Stagehand extension: verifies multipart POST to /v1/extensions with filename="stagehand-extension.zip"
    • extensions upload rejects both --stagehand and a file path: verifies exit 1 and error message
    • extensions upload requires --stagehand or a file path: verifies exit 1 and error message when neither provided

Before:

browse cloud extensions upload node_modules/@browserbasehq/stagehand/dist/assets/stagehand-extension.zip

After:

browse cloud extensions upload --stagehand

test plan

  • 505 CLI tests pass (38 test files), including the 3 new tests
  • pnpm format:check passes
  • pnpm eslint passes
  • pnpm turbo run build --filter=browse succeeds (TypeScript compiles, oclif manifest generates)

PR 1 of 2. #3275 is stacked on this and updates the user-facing instructions (functions init, deployment docs, CLI skill) to use --stagehand.


Summary by cubic

Adds a --stagehand flag to browse cloud extensions upload so the bundled Stagehand extension can be uploaded without a file path.

  • The file argument is now optional; you must provide either a file path or --stagehand.
  • Passing both --stagehand and a file path errors out.
Open in Web Open in Cursor