npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vinciworks-devs/bitbucket-pr

v0.13.2

Published

Deterministic Bitbucket PR CLI for coding agents — one JSON object on stdout, secure token storage via the git credential store.

Readme

@vinciworks-devs/bitbucket-pr

Deterministic Bitbucket PR CLI for coding agents. Zero dependencies (Node >= 18).

Every command prints exactly one JSON object to stdout — callers branch on status / code, never on prose. Exit 0 on success or benign no-op (PR_ALREADY_EXISTS), exit 1 with {"status":"ERROR","code":...} otherwise. Everything human-readable goes to stderr.

Install

npm i -g @vinciworks-devs/bitbucket-pr

Auth (once, in YOUR terminal — never through an agent)

bitbucket-pr setup

Stores a scoped Bitbucket API token (read:pullrequest:bitbucket + write:pullrequest:bitbucket) in your OS keychain via the git credential store, under host api.bitbucket.org. The token is validated against Bitbucket before and after storing, and setup refuses plaintext credential helpers. App passwords are EOL (2026-07-28) — use API tokens.

CI / agents can instead set BITBUCKET_EMAIL + BITBUCKET_API_TOKEN env vars.

Usage

REMOTE = [email protected]:ws/repo.git (or [email protected]:…) | https://bitbucket.org/ws/repo | ws/repo | a git remote name of the current repo (origin, upstream, …). Omit it to use the origin remote of the current directory. A bare repo name (mod-editagent) is not accepted — the workspace can't be guessed. Flags take --flag value or --flag=value.

bitbucket-pr create $REMOTE --from=$FROM --to=$TO --title "feat: thing" --body "..."
# → {"status":"CREATED","id":42,"url":"https://bitbucket.org/...","from":"...","to":"..."}
# re-run → {"status":"PR_ALREADY_EXISTS",...} exit 0 — idempotent
  • create is pure API: it does not push — push the branch first.
  • Cut the branch from the PR target (or rebase onto it) before create: the PR diff shows every commit not on the target, so a branch cut from master targeting development drags foreign trunk commits into the diff.
  • --to omitted → the repo's main branch, from the remote's HEAD symref.
  • --to-dev → the repo's dev branch: develop or development (develop wins if both exist).
  • Both resolve via git ls-remote — your git transport auth, no extra API token scope — and cache 24h per remote in the user cache dir (BITBUCKET_PR_CACHE_DIR overrides the location). Reading either from the API would need read:repository:bitbucket, which the token below deliberately does not carry. If ls-remote cannot reach the remote, --to omitted falls back to the API lookup, which 403s without that scope — pass --to <branch> to skip resolution entirely.
  • --title-file / --body-file / --text-file read the value from a file.
  • Refuses to open a PR from main/master/develop (PROTECTED_BRANCH).
bitbucket-pr comment $REMOTE --pr 42 --text "Paired KB PR: ..."
bitbucket-pr comments $REMOTE --pr 42   # every comment, oldest first, all pages
# → {"status":"LISTED","pr":42,"comments":[{"id":7,"author":"Ann","created":...,
#    "file":"src/a.js","line":12,"replyTo":null,"resolved":false,"text":"..."}]}
#   file/line null for a general comment; deleted comments left out
bitbucket-pr decline $REMOTE --pr 42 --text "Replaced by #57"   # --text optional
# → {"status":"DECLINED","id":42,"url":...,"commentId":7}
#   the text is posted as a comment after the decline (a refused decline posts none); ALREADY_DECLINED (exit 0)
#   writes nothing; NOT_OPEN refuses a merged or superseded PR, writing nothing
bitbucket-pr edit $REMOTE --pr 42 --body-file DESCRIPTION.md   # and/or --title
# → {"status":"EDITED","id":42,"url":...,"fields":["description"]}
#   markdown in; the field you don't pass is kept, reviewers are preserved
bitbucket-pr reviewers $REMOTE --pr 42 --add "Roi Avram,Jonah" --remove Rafi
# → {"status":"REVIEWERS_SET","id":42,"url":...,"reviewers":["Roi Avram","Jonah Eisenberg"]}
#   names: full name, a unique first name, or {uuid}; looked up among recent PRs' people
#   UNCHANGED when the list would not change; UNKNOWN_USER / AMBIGUOUS_USER (+ "candidates")
#   / AUTHOR_CANNOT_REVIEW change nothing
bitbucket-pr pr $REMOTE --pr 42          # merge status by PR id
bitbucket-pr pr $REMOTE --pr 42 --full   # + "description" (raw markdown, to edit and send back),
                                         #   "heads" (source commits pushed, newest first)
                                         #   and "commentTexts" (each comment's raw text)
bitbucket-pr pr $REMOTE --from=$FROM     # newest PR from that branch, any state
bitbucket-pr pr $REMOTE --from=$FROM --all   # → {"status":"LISTED","prs":[{"id":42,"state":"OPEN"},...]}
# → {"status":"MERGED","id":42,"title":...,"from":...,"to":...,"url":...,"mergeCommit":"abc1234",
#    "approvedBy":["Ann"],"changesRequestedBy":[],"comments":3,"openTasks":0,
#    "builds":[{"name":"UI build","state":"SUCCESSFUL"}]}
#   status = OPEN | MERGED | DECLINED | SUPERSEDED; NO_PR if the branch has none
#   builds = the PR's commit statuses; [] when CI doesn't report back to Bitbucket
bitbucket-pr merge $REMOTE --pr 42 --to development --head $(git rev-parse HEAD)
# → {"status":"MERGED","id":42,"url":...,"mergeCommit":"abc1234"}
#   merge commit. Deletes the source branch unless it's main, master, develop,
#   development or staging (create ticks "close source branch" the same way).
#   Refuses first, merging nothing:
#   WRONG_DESTINATION (not --to), HEAD_MOVED (PR not at --head),
#   CHANGES_REQUESTED (someone asked for changes).
#   A project with its own merge policy enforces it in front of this command.
#   A slow merge (HTTP 202) is polled for up to a minute, then MERGE_PENDING:
#   the merge may still finish. A Bitbucket refusal (conflict, failed merge
#   check, no permission) is an ERROR with its reason
#   MERGED_UNCHECKED_HEAD (exit 1): merged, but at a commit other than --head,
#   pushed between the check and the merge; review it and revert if needed
bitbucket-pr status            # local check, no network: READY | SETUP_REQUIRED
bitbucket-pr doctor $REMOTE    # end-to-end: credential → API auth → repo access
bitbucket-pr help

Error codes

BAD_ARGS, NO_REMOTE, NO_PR, PROTECTED_BRANCH, AUTH_REQUIRED, TOKEN_REJECTED, REPO_ACCESS, API_ERROR, NO_DEST, NOT_A_TTY, INSECURE_CREDENTIAL_HELPER, NO_CREDENTIAL_HELPER, STORE_FAILED, MERGE_PENDING, WRONG_DESTINATION, HEAD_MOVED, CHANGES_REQUESTED, MERGED_UNCHECKED_HEAD, NOT_OPEN, UNEXPECTED.

Development

npm test