Skip to content

feat(cli): add browse clipboard commands#2240

Closed
optimusbuilder wants to merge 1 commit into
browserbase:mainfrom
optimusbuilder:feat/browse-clipboard-cli
Closed

feat(cli): add browse clipboard commands#2240
optimusbuilder wants to merge 1 commit into
browserbase:mainfrom
optimusbuilder:feat/browse-clipboard-cli

Conversation

@optimusbuilder

@optimusbuilder optimusbuilder commented Jun 11, 2026

Copy link
Copy Markdown

##why
The SDK exposes context.clipboard, but the browse CLI had no way to use it — users had to fall back to raw CDP.

##what changed
-Six driver commands: clipboard.read, write, paste, copy, cut, clear
-Matching oclif commands: browse clipboard read|write|paste|copy|cut|clear
-Wired through DriverSessionManager.browserContext() → context.clipboard (no core changes)
paste supports --shortcut Control+V|Meta+V|ControlOrMeta+V

  • Unit tests for handler wiring + command registration

##test plan

pnpm exec vitest run tests/clipboard.test.ts tests/driver-commands.test.ts

Manual: write → read → paste on a focused input


Summary by cubic

Add clipboard support to the browse CLI with commands to read, write, paste, copy, cut, and clear. Enables agents and terminal users to use the SDK clipboard without raw CDP.

  • New Features
    • Implemented driver handlers for clipboard.read|write|paste|copy|cut|clear, wired via DriverSessionManager.browserContext() to context.clipboard.
    • Exposed as oclif commands: browse clipboard read|write|paste|copy|cut|clear; paste supports --shortcut (Control+V, Meta+V, ControlOrMeta+V).
    • Added vitest tests for handler wiring and CLI registration.

Written for commit c372551. Summary will update on new commits.

Review in cubic

Expose the SDK clipboard API through the browse driver and oclif so
terminal and agent workflows can read, write, paste, copy, and clear
the browser clipboard without raw CDP calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot

changeset-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c372551

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run.
Approving the latest commit mirrors it into an internal PR owned by the approver.
If new commits are pushed later, the internal PR stays open but is marked stale until someone approves the latest external commit and refreshes it.

@github-actions github-actions Bot added external-contributor Tracks PRs mirrored from external contributor forks. external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. labels Jun 11, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 12 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant User as CLI User
    participant Oclif as oclif Command
    participant CLI as Driver Command CLI
    participant Handlers as Clipboard Handlers
    participant Manager as DriverSessionManager
    participant Context as BrowserContext
    participant Clipboard as Clipboard API

    Note over User,Clipboard: NEW: Browse Clipboard Commands

    User->>Oclif: browse clipboard read|write|paste|copy|cut|clear [--session] [args]
    Oclif->>Oclif: Parse flags/args

    alt clipboard.write
        Oclif->>CLI: runDriverCommandFromFlags("clipboard.write", {text})
    else clipboard.paste
        Oclif->>CLI: runDriverCommandFromFlags("clipboard.paste", {shortcut})
    else other commands
        Oclif->>CLI: runDriverCommandFromFlags("clipboard.<cmd>", {})
    end

    CLI->>Handlers: Dispatch to clipboard.<cmd> handler
    Handlers->>Manager: browserContext()
    Manager-->>Handlers: BrowserContext instance

    alt clipboard.read
        Handlers->>Clipboard: readText()
        Clipboard-->>Handlers: clipboard text
        Handlers-->>CLI: { text }
    else clipboard.write
        Handlers->>Clipboard: writeText(text)
        Clipboard-->>Handlers: void
        Handlers-->>CLI: { ok: true }
    else clipboard.paste
        Handlers->>Clipboard: paste({ shortcut } | undefined)
        Clipboard-->>Handlers: void
        Handlers-->>CLI: { ok: true }
    else clipboard.copy|cut|clear
        Handlers->>Clipboard: copy() | cut() | clear()
        Clipboard-->>Handlers: void
        Handlers-->>CLI: { ok: true }
    end

    CLI-->>Oclif: Result
    Oclif-->>User: Display result
Loading

Re-trigger cubic


static override examples = [
"browse clipboard clear",
"browse clipboard clear --session research",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is clipboard siloed by browser / tab like this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it’s not tab-siloed.
browse clipboard * runs against the active page (for focus + permission grant), but the clipboard value is shared across tabs in that browser session.
so when you write in tab 0 and switch to tab 1, read returns the same value.
So --session here selects which browse daemon/browser session to target, not per-tab clipboard isolation.

@github-actions github-actions Bot removed the external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. label Jun 11, 2026
@github-actions github-actions Bot added the external-contributor:mirrored An internal mirrored PR currently exists for this external contributor PR. label Jun 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR was approved by @shrey150 and mirrored to #2241. All further discussion should happen on that PR.

@github-actions github-actions Bot closed this Jun 11, 2026
shrey150 added a commit that referenced this pull request Jun 12, 2026
## Summary

Fork-triggered `pull_request` workflow runs don't receive repo
configuration variables or secrets, so
`STAINLESS_ORG`/`STAINLESS_PROJECT` arrive empty and the Stainless
action dies immediately with `Input required and not supplied: project`
on every external-contributor PR. Seen on #2241 (claimed copy of #2240):
the fork PR's failing `preview` check attached to the shared head SHA,
leaving the claimed PR red through no fault of its own.

This guards both jobs on `github.event.pull_request.head.repo.full_name
== github.repository`:

- `preview` — skips on fork PRs instead of failing. Claimed copies of
external PRs run in-repo, so SDK preview coverage is preserved.
- `merge` — same defect: a directly-merged fork PR would trigger a
guaranteed-failing merge build (still no vars/secrets on the `closed`
event). Skipping is strictly better than failing; the claim flow means
merged external work is always in-repo anyway.

The `full_name` comparison is used instead of `!head.repo.fork` so a
deleted fork repo (`head.repo == null`) skips rather than
runs-and-fails.

Linear:
[STG-2257](https://linear.app/browserbase/issue/STG-2257/fixci-skip-stainless-sdk-jobs-for-fork-prs)

## E2E Test Matrix

| Command / flow | Observed output | Confidence / sufficiency |
| --- | --- | --- |
| Failing fork run:
[actions/runs/27375420406](https://github.com/browserbase/stagehand/actions/runs/27375420406/job/80903332001)
(triggered by fork PR #2240) | Env dump shows `STAINLESS_ORG:` and
`STAINLESS_PROJECT:` empty; action exits with `Error: Input required and
not supplied: project` | Proves the root cause is withheld vars on fork
runs, not the spec or config — exactly the case the new guard skips |
| `actionlint .github/workflows/stainless.yml` on this branch | Exit 0,
no findings | Validates workflow schema and the new `if:` expression
syntax |
| `preview` check on **this PR** (in-repo branch) | See checks below —
job runs (guard evaluates true for same-repo PRs) and builds SDK
previews | Live proof the guard doesn't skip in-repo PRs; the fork-skip
path can only be exercised by the next real fork PR |

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Skip Stainless CI jobs for fork-origin PRs to avoid failures from
missing repo vars/secrets. Keeps external PRs green while coverage runs
on in-repo “claimed” copies. Addresses Linear STG-2257.

- **Bug Fixes**
- Skip `preview` and `merge` unless
`github.event.pull_request.head.repo.full_name == github.repository`;
`merge` still requires closed+merged into `main`.
- Use the `full_name` check to safely skip deleted forks (`head.repo`
can be null).

<sup>Written for commit 58c5891.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2243?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor:mirrored An internal mirrored PR currently exists for this external contributor PR. external-contributor Tracks PRs mirrored from external contributor forks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants