Skip to content

feat(cli): add browse watch command#2244

Open
optimusbuilder wants to merge 1 commit into
browserbase:mainfrom
optimusbuilder:feat/browse-watch
Open

feat(cli): add browse watch command#2244
optimusbuilder wants to merge 1 commit into
browserbase:mainfrom
optimusbuilder:feat/browse-watch

Conversation

@optimusbuilder

@optimusbuilder optimusbuilder commented Jun 11, 2026

Copy link
Copy Markdown

why

The browse CLI has wait, is, and get, but no single command to poll for state transitions (e.g. “wait until text appears”, “wait until URL matches”, “wait until selector becomes visible”). Users currently have to script loops manually.

what changed

  • Add new browse watch command supporting:
    • text <query>
    • url <query>
    • visible <selector>
    • checked <selector>
  • Add polling helper with configurable timeout/interval and regex matching for text/url.
  • Reuse existing driver commands (get/is) under the hood.
  • Add unit tests for matcher and polling behavior.
  • Add changeset for browse minor release.

test plan

  • pnpm --filter browse build
  • pnpm --filter browse exec vitest run tests/watch.test.ts tests/driver-commands.test.ts

Summary by cubic

Adds a new browse watch CLI command to wait for text, URL, visibility, or checked state changes with configurable interval, timeout, and optional regex. This removes the need for manual polling loops.

  • New Features
    • Command: browse watch <kind> <target> where kind is text, url, visible, or checked.
    • Flags: --interval <ms>, --timeout <ms>, --regex (text/url), --selector <css> (scope for text).
    • Reuses get/is under the hood; new polling helper with substring or regex matching.
    • Outputs JSON with attempts, elapsedMs, and last value.
    • Unit tests for matcher and polling; changeset for a browse minor release.

Written for commit 111deb7. Summary will update on new commits.

Review in cubic

Add a polling watch command for text, URL, visible, and checked
conditions with configurable interval and timeout, plus regex support
for text and URL queries.

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

changeset-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 111deb7

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 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant CLI as CLI Entry Point
    participant Watch as browse watch command
    participant Resolver as resolveTargetForCommand
    participant Runner as runDriverCommandWithTarget
    participant WatchLib as pollWatch / createStringMatcher
    participant Driver as Stagehand Driver (get/is)

    CLI->>Watch: parse(kind, target, flags)
    Watch->>Watch: validate flags (interval, regex+kind combo)
    Watch->>Resolver: resolveTargetForCommand(session, flags)
    Resolver-->>Watch: target object
    Watch->>WatchLib: createStringMatcher(query, regex)
    WatchLib-->>Watch: matcher function

    loop pollWatch (configurable interval/timeout)
        Watch->>WatchLib: check() (called by pollWatch)
        WatchLib->>Watch: checkCondition(kind, matcher, query, selector, session, target)

        alt kind == "visible" or "checked"
            Watch->>Runner: runDriverCommandWithTarget(session, target, "is", { check: kind, selector: query })
            Runner->>Driver: is({ check, selector })
            Driver-->>Runner: { visible/checked: boolean }
            Runner-->>Watch: { visible/checked: boolean }
            Watch-->>WatchLib: { matched: boolean(value), value: string(bool) }

        else kind == "url"
            Watch->>Runner: runDriverCommandWithTarget(session, target, "get", { what: "url" })
            Runner->>Driver: get({ what: "url" })
            Driver-->>Runner: { url: string }
            Runner-->>Watch: { url: string }
            Watch->>WatchLib: matcher(url) → boolean
            Watch-->>WatchLib: { matched, value: url }

        else kind == "text"
            Watch->>Runner: runDriverCommandWithTarget(session, target, "get", { selector (or body), what: "text" })
            Runner->>Driver: get({ selector, what: "text" })
            Driver-->>Runner: { text: string }
            Runner-->>Watch: { text: string }
            Watch->>WatchLib: matcher(text) → boolean
            Watch-->>WatchLib: { matched, value: text }
        end

        WatchLib-->>Watch: WatchAttempt

        alt matched == true
            WatchLib->>WatchLib: return { attempts, elapsedMs, value }
            Watch->>CLI: outputJson { attempts, elapsedMs, kind, matched: true, session, value }
        else timeout reached
            WatchLib->>WatchLib: throw Error("Watch condition not met...")
            Watch->>CLI: outputJson error message
        end
    end
Loading

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. external-contributor Tracks PRs mirrored from external contributor forks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant