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

gogitter

v0.1.3

Published

An append-only issue tracker stored in Git, built with TypeScript and Effect.

Readme

gogitter

An append-only issue tracker stored in Git, built with TypeScript and Effect. This is a proof of concept. Issues contain an ID, author, creation date, title, description, and an open or closed state.

Getting started

Requires Git, Node.js 22.13 or newer, and pnpm 10.9.0. The included nix-shell supplies the development tools. Node's built-in SQLite module may print an experimental-feature warning on some Node versions.

pnpm install
pnpm build
node dist/cli.js --help

Run the CLI inside a Git repository with user.name and user.email configured. No initialization command or existing branch commit is needed.

pnpm start create --title "Fix login" --description "Login fails after a refresh."
# Prints the new issue's full ID. Use that ID or an unambiguous prefix below.
pnpm start list
pnpm start show <id>
pnpm start edit <id> --title "Fix login after refresh"
pnpm start edit <id> --description "Updated details"
pnpm start close <id>
pnpm start reopen <id>
pnpm start history <id>
pnpm start list --state closed
pnpm start list --state all

An edit can change both title and description in one event. Passing --description "" clears the description. Commands that return issue data or sync results support --json. Listing defaults to open issues.

When running from another repository, use node /absolute/path/to/gogitter/dist/cli.js. The packaged executable is named gogitter; --version reads the packaged package.json, so there is no second version string to maintain.

Terminal UI

Run gogitter tui inside your repository (or pnpm start tui from this checkout) to open the TUI, or gogitter tui --remote upstream to choose a remote at startup. It follows lazygit's conventions: a ticket list on the left, details on the right, the keys for the current context along the bottom, and ? for a menu of every keybinding (press Enter on an entry to run it). It needs an interactive terminal of at least 56 columns and 12 rows.

| Keys | Action | | --- | --- | | j / k, arrows | Next / previous ticket, or scroll the details | | h / l, Tab | Focus the tickets or details panel | | 1 / 2 / 3 | Show open, closed or all tickets | | [ / ] | Previous / next tab of the focused panel | | < / >, , / . | Top / bottom, previous / next page | | / | Search; Enter keeps the filter, Esc clears it | | n / e | New ticket / edit the selected ticket | | Space | Close or reopen the selected ticket | | y / Y | Copy the description / choose what to copy (title, ID, …) | | p / P | Pull / push | | u | Choose the remote | | R | Refresh | | ? | Keybindings menu | | q | Close the current popup, or quit | | Ctrl+c | Quit |

The ticket form opens over the panels, like lazygit's commit message popup. There are no modes: just type. In the title, Enter saves and Tab (or ↓) moves to the description. In the description, Enter adds a line and Ctrl+s or Alt+Enter saves. Esc closes the form, asking before discarding changes. Shell-style editing keys work in both fields: Ctrl+a / Ctrl+e for the line start and end, Alt+b / Alt+f (or Ctrl/Alt with arrows) to move by word, and Ctrl+w, Ctrl+u and Ctrl+k to delete a word, back to the line start, or to the line end. Pasted text is inserted as text and never runs commands.

Errors, such as a save that conflicts with a newer change, appear in a popup. Your draft stays open so you can recover. Pull and push are explicit, and nothing synchronizes automatically. Push uses the same fetch, validation, merge, and atomic push as the CLI. Local ticket changes leave your working files and branch untouched.

Web UI

pnpm build
pnpm start webui
# With an installed package, run: gogitter webui

webui starts an Effect HTTP server on 127.0.0.1, chooses an available port, and opens your browser. Keep the command running; Ctrl+C stops the server. Use webui --port 3000 to choose a port or webui --no-open to print the URL without opening a browser. Run the command in the repository you want to use.

The React interface includes a searchable, paginated issue list, open/closed filters, issue details, a plain-text editor, close/reopen actions, and event history. Choose a configured remote and use Pull or Push explicitly. Refreshing the list reads local changes made by CLI commands; it does not pull. An edit based on an outdated issue revision is rejected while keeping the draft visible, so you can review newer changes before saving again.

The frontend assets are bundled in the package and served locally; users do not need a development server or additional frontend dependencies. This is a local, single-user UI, with same-origin requests and a per-process session token. The server does not bind to public network interfaces. Descriptions are always plain text, including HTML or Markdown characters.

Sharing issues

pnpm start pull            # Defaults to origin
pnpm start push
pnpm start pull upstream   # Or another configured Git remote

The remote must allow custom refs and atomic pushes. A local bare repository is enough; no separate service is required. The POC requires a single identical fetch/push URL for the selected remote.

Each sync transfers all issue refs in one fetch or push. push first fetches, validates, and merges remote changes. Concurrent edits are replayed in a deterministic order: parents first, then lexicographically smallest eligible event ID. The last replayed change to a field wins. Changes to different fields are retained. There is no interactive merge-conflict resolution.

Normal git clone, git pull, and git push do not synchronize these custom refs by default. Run gogitter pull in a new clone. Issue operations do not check out files or modify the index, current branch, or its history.

Storage and integrity

  • refs/gogitter/issues/<creation-commit-id> points to each issue's latest commit.
  • Every user change creates a new commit with one event.json blob and a tree. Commits are never amended. Creating the root commit first makes its hash available before creating the issue ref.
  • Divergent histories get a two-parent synchronization commit. It carries no user change and does not affect event ordering.
  • refs/gogitter/checkpoints/<remote-key>/<issue-id> remembers accepted remote history. A remote rollback, deletion, or rewrite that drops accepted history makes both pull and push fail. Validation finishes before local refs change.
  • .git/gogitter/cache.sqlite is a disposable projection, indexed by issue state. Every pull invalidates the whole cache, including the pull performed by push. The next query rebuilds it. Local edits also invalidate it, and cached ref tips are checked on every query to recover from interrupted writes.

gogitter rebuild-cache explicitly rebuilds the cache. Deleting the SQLite file is also safe: rewrite detection lives in Git refs. Linked Git worktrees share the same issue refs and cache through their common Git directory.

Rewrite detection protects history this clone has already accepted for that remote. A first pull has no previous checkpoint to compare against. This is client-side validation, not a server policy or a signature system: direct Git commands can still rewrite refs, and Git author information is self-reported. Retain the checkpoint refs when backing up the repository.

See the storage format for the event schema and sync protocol.

Removing local gogitter data

gogitter wipe
# From this project's checkout: pnpm start wipe

wipe immediately deletes all local refs/gogitter/* refs (issues, sync checkpoints, and temporary refs), their reflogs, and the entire gogitter cache directory. It supports --json, which reports the number of refs removed. This command is available only in the CLI, with no web UI or HTTP API action.

Linked worktrees share this data, so wiping from one clears it for all of them. Stop other gogitter commands and web UI servers in this repository before wiping. Branches, tags, Git configuration, the index, and working files are preserved. Unreachable issue commits, trees, and blobs are left for Git's normal garbage collection; wipe does not prune the repository's shared object database.

Remotes and other clones are unchanged. A later pull restores remote issues with fresh checkpoints; unpublished local changes are lost. Wiping also resets this clone's record of previously accepted remote history.

Development and tests

pnpm dev          # Restart the CLI when source files change
pnpm typecheck    # Check implementation and tests
pnpm test         # Build, property tests, real Git/SQLite tests, packaged CLI test
pnpm test:stress  # Exercise 3,000 issues, including push and pull
pnpm test:browser # Run Chromium tests against real CLI-launched web servers
pnpm pack         # Build and create a distributable tarball; does not publish

All test repositories, SQLite databases, remotes, and working copies live in temporary directories and are removed afterward. Tests set their own Git identity/configuration and use local filesystem remotes. They require no Git hosting account or network connection after dependencies are installed.

Install the browser test runtime once with pnpm exec playwright install chromium (on Linux, use pnpm exec playwright install --with-deps chromium). HTTP tests run as part of pnpm test; browser tests run separately with pnpm test:browser. Both use temporary repositories and loopback ports. pnpm build rebuilds the browser bundle after changes under web/.

The suite covers generated event DAGs, concurrent edits from three clones, simultaneous local writers, fetch/push races, remote rewrites/deletions, atomic rejection, cache corruption/rebuild, Git worktrees, SHA-256 repositories, garbage collection, and preservation of ordinary branch/worktree state. The packaging test extracts a real pnpm tarball and runs its compiled CLI with only production dependencies linked in, including the packaged web server and assets. Web tests cover API validation, stale edits, search and pagination, explicit synchronization, rewrite errors, plain-text rendering, desktop/mobile workflows, and server shutdown. CI runs browser tests on Linux with Node 24.

The stress test prints timings without imposing machine-specific speed limits. Use GOGITTER_STRESS_ISSUES=10000 pnpm test:stress to change its size. Cached queries still enumerate refs to check freshness, but do not read event history. Full validation and rebuilding are deliberately exhaustive in this POC.