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

repoq

v1.3.1

Published

Query Git, GitHub, and Forgejo repository state with structured, machine-readable output.

Readme

repoq

Query Git repository state without parsing command output.

Each repoq command replaces multiple git/gh/fgj commands, handling edge cases (detached HEAD, unborn branches, missing remotes) and returning validated JSON. It detects the forge from your origin remote and routes queries to GitHub (via gh) or Forgejo (via the Forgejo REST API). Works offline, degrading gracefully when the forge CLI is unavailable.

Why repoq?

Getting reliable repository state from git and gh is harder than it looks:

  • Parsing is fragile. git status --porcelain uses two-character codes. git log output varies by format string. Worktree listings are multi-line records.
  • Edge cases break scripts. Detached HEAD, unborn branches, missing upstream tracking, and offline mode all need special handling.
  • GitHub data requires multiple calls. PR checks/reviews come from gh pr view. Unresolved review threads require GraphQL. Combining them takes orchestration.
  • Fallbacks are tedious. Finding the default branch might need gh repo view, or git symbolic-ref, or probing for main/master—depending on what's available.

repoq handles all of this internally and returns typed, validated JSON.

What it does

repoq can query:

  1. status: one-shot repository snapshot
    • Runs multiple git commands plus optional gh/Forgejo queries
    • Returns branch state, working tree breakdown, worktree summary, and last commit
    • Handles detached HEAD, unborn branches, and missing forge auth gracefully
  2. branch: branch lifecycle and tracking
    • Runs multiple git commands plus optional gh/Forgejo queries
    • Reports local/remote existence, upstream tracking, worktree location, PR status
    • Detects detached HEAD and unborn state without cryptic errors
  3. diff-range: merge-base diff summary
    • Runs multiple git commands, with optional gh default-branch lookup
    • Returns commit count, conventional commit metadata, file changes, line stats
    • Tries remote branch first, falls back to local; handles unborn HEAD
  4. worktrees: worktree inventory with status
    • Runs 1 + N git commands (status per worktree)
    • Returns cleanliness, uncommitted counts, issue IDs from branch names
    • Filters by --issue-id or --uncommitted-only
  5. pr: pull request with derived summaries
    • GitHub: gh pr view plus GraphQL for unresolved thread summaries
    • Forgejo: the Forgejo REST API for PR metadata, reviews, and commit-status checks
    • Returns checks (passing/failing/pending), reviews, unresolved thread counts
    • Works without error if PR doesn't exist
  6. default-branch: resilient resolution
    • Fallback order: GitHub API → symref → remote set-head --auto retry → probe main/master → fallback main
    • Works offline, without gh, and on fresh clones
  7. forge: forge detection from origin
    • Classifies the provider: github.com is GitHub, any other host is a candidate Forgejo (self-hostable on any domain), unknown only when the origin has no parseable host
    • Derives the slug, CLI (gh/fgj), API host, and connection coordinates

Requirements

  • Node.js >= 24.0.0
  • Git

Optional:

  • GitHub CLI (gh) — PR queries and GitHub-backed default-branch detection on GitHub origins.
  • Forgejo CLI (fgj) — authenticates Forgejo REST queries (PR metadata, reviews, checks) on Forgejo origins.

Without the matching CLI, commands degrade gracefully—git-only data still works.

Install / run

# one-off
npx -y repoq status --json

# global
pnpm add -g repoq
repoq status --json

Run it from inside a Git repository.

Usage

repoq <command> [options]

Common examples:

# Get current branch name
repoq status --json | jq -r '.branch.current'

# Check if working tree is clean
repoq status --json | jq '.workingTree.isClean'

# Check upstream tracking
repoq status --json | jq '.branch.tracking | {ahead, behind}'

# Check if PR exists for current branch
repoq status --json | jq '.branch.pr.exists'

# Count commits since main
repoq diff-range --json | jq '.commits.count'

# List worktrees with uncommitted changes
repoq worktrees --uncommitted-only --json | jq '.[].path'

# Check if PR is approved
repoq pr --json | jq '.reviews.approved > 0'

# Check CI status
repoq pr --json | jq '.checks.failing == 0'

# Verify all commits are conventional
repoq diff-range --json | jq '[.commits.messages[].isConventional] | all'

# List changed files
repoq diff-range --json | jq '.files.added + .files.modified | .[]'

# Inspect a specific branch
repoq branch feature/login --json | jq '.tracking'

# Detect which forge and CLI back the current repo
repoq forge --json | jq -r '.cli'

Before and after

Getting PR approval status without repoq:

# Check if PR is approved (fragile, verbose)
pr_json=$(gh pr view --json reviews)
approved=$(echo "$pr_json" | jq '[.reviews[] | select(.state == "APPROVED")] | length')
if [ "$approved" -gt 0 ]; then echo "Approved"; fi

With repoq:

repoq pr --json | jq '.reviews.approved > 0'

The difference grows with complexity. Checking if a branch is ready for merge (clean working tree + CI passing + approved + no unresolved threads) takes 50+ lines of shell. With repoq:

repoq status --json | jq '.workingTree.isClean' && \
repoq pr --json | jq '.checks.failing == 0 and .reviews.approved > 0 and .unresolved.threads == 0'

Command reference

| Command | Purpose | | ----------------------------------------------------------- | -------------------------------------------------------------------------- | | status [--json] | One-shot repo snapshot with full branch info, working tree, last commit | | branch <branch> [--json] [--issue-id <id>] | Branch lifecycle/tracking/worktree/PR status with unborn detection | | diff-range [base] [--json] [--head <branch>] | Merge-base diff summary, commit metadata, file/stats, fast-forwardability | | worktrees [--json] [--issue-id <id>] [--uncommitted-only] | Enumerate worktrees with cleanliness/unborn state and filters | | pr [branch] [--json] | PR metadata plus checks/reviews/unresolved summaries | | default-branch [--json] | Resolve default branch with GitHub + git fallbacks | | forge [--json] | Detect the forge from origin: provider, slug, CLI, API host, coordinates |

For detailed command help:

repoq --help
repoq <command> --help

Library API

repoq exports its forge detection for programmatic use, so other tools can share one implementation instead of re-deriving the provider from origin:

import { detectForge, FORGEJO_API_HOST, type ForgeInfo } from "repoq";

const forge: ForgeInfo = detectForge("ssh://[email protected]:2222/j4k/cluster.git");
// → { provider: "forgejo", slug: "j4k/cluster", cli: "fgj",
//     apiHost: "code.j4k.dev", apiBase: "https://code.j4k.dev/api/v1",
//     hostnameFlag: "--hostname code.j4k.dev", ... }

detectForge(originUrl) is pure: it parses any remote URL shape (scp-like, ssh://, https://), matches the host case-insensitively, and never touches the filesystem. github.com resolves to GitHub; any other host resolves to a candidate Forgejo whose API host is the origin host (preserving a custom HTTPS port; an alias map covers asymmetric deployments like the Forge, whose API host differs from its clone host). Actual Forgejo support is gated at request time by whether fgj auth token --hostname <host> succeeds, so an unrelated host fails gracefully. Pass null for "no origin". The returned ForgeInfo matches repoq forge --json.

Environment variables

| Variable | Description | | ---------------- | ----------------------------------------------- | | REPOQ_GIT_PATH | Path to git binary (default: git from PATH) | | REPOQ_GH_PATH | Path to gh binary (default: gh from PATH) | | REPOQ_FGJ_PATH | Path to fgj binary (default: fgj from PATH) |

Agent rule

Add to your CLAUDE.md or AGENTS.md:

# Rule: Use `repoq` for Repository Queries

Run `npx -y repoq --help` to learn available options.

Use `repoq` instead of piping `git`/`gh` commands through `awk`/`jq`/`grep`.
Each command handles edge cases (detached HEAD, unborn branches, missing auth)
and returns validated JSON. Prefer `repoq` for reading state; use raw `git`/`gh`
for mutations (commit, push, merge).

License

MIT