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

@algorithmikos/bethink

v1.5.1

Published

Language-agnostic CLI for versioning, changelog, commit, and tag automation with LLM polish

Readme

bethink

A language-agnostic CLI for versioning, changelog authoring, and release tagging — with LLM polish and a resilient offline fallback.


Table of Contents


Overview

bethink is invoked from the root of any Git repository. It guides the user through three independently selectable atomic actions:

| Action | What it does | |--------|-------------| | Bump | Reads the current version from the detected manifest, calculates the next semver, writes CHANGELOG.md and RELEASE-NOTES.md, and updates the manifest. | | Commit | Stages all working-tree changes and creates a Git commit with an LLM-generated conventional commit message. | | Tag | Creates an annotated Git tag at HEAD with an LLM-generated annotation. |

Any combination of these three actions is valid. The tool operates on one repository, one project — there is no multi-package or monorepo mode.


Installation

npm install -g bethink

Node.js ≥ 18 is required.

On first run, bethink --config opens the provider wizard and writes ~/.bethink.json.


Quick Start

cd /path/to/your/project
bethink

The tool detects your manifest automatically, checks your configured LLM provider, and begins the interactive workflow.


CLI Flags

| Flag | Description | |------|-------------| | (none) | Run the interactive release workflow. | | --config | Open the provider configuration wizard. | | --state | Inspect the saved session state for the current branch. | | --help | Display usage information. |


Workflow

Action Selection

After provider and branch selection, a checkbox prompt allows any combination of Bump, Commit, and Tag to be toggled. Common combinations:

  • Bump + Commit + Tag — full release in one shot.
  • Bump + Commit — bump and commit now; tag after a build or QA step.
  • Tag only — cut a tag from a prior bump+commit session.
  • Commit only — commit without any version change.

Entry Collection

Changelog entries are collected interactively. Each entry has a type:

| Type | Semver impact | Default public inclusion | |------|--------------|--------------------------| | added | minor | likely | | changed | minor | unlikely | | deprecated | minor | unlikely | | removed | major | unlikely | | fixed | patch | likely | | security | patch | likely | | build | patch | never |

After each raw message is entered, the user may:

  1. Keep it as-is.
  2. Send it to the LLM for rephrasing.

The LLM then evaluates whether the entry belongs in the public-facing RELEASE-NOTES.md and offers a plain-language rewrite. The user confirms, edits, or excludes it.

The session may be saved at any point and resumed on the next run.

Version Bump

The bump level is auto-calculated from the entry types collected:

  • Any removed entry → major.
  • Any added, changed, or deprecated entry (no removed) → minor.
  • Only fixed, security, or build entries → patch.

The user may override this at the confirmation prompt. Pre-release channels (alpha, beta, rc, or a custom identifier) are supported.

If the version was already bumped in a prior session, the 📌 Already bumped option skips re-writing the manifest and uses the on-disk version.

LLM Features

All LLM interactions are powered by externally editable prompt templates in config/prompts/. The following tasks are LLM-assisted:

| Task | Prompt file | |------|------------| | Rephrase a changelog entry | rephrase-entry.txt | | Suggest public release note inclusion | public-entry-suggestion.txt | | Generate commit message and tag annotation | commit-and-tag.txt | | Clipboard fallback context aggregation | clipboard-fallback.txt |

Every LLM result is shown to the user before it is applied. The user may keep, edit, or retry with the same or a different provider.

Fail-Safe & Smart Copy

The process never terminates due to an LLM failure. When a provider is unreachable, the user chooses one of three paths:

  1. Continue with raw messages — proceed without LLM polish.
  2. Smart Copy — the full session context (entries, commits since the last tag, git diff --stat, branch, version) is aggregated using clipboard-fallback.txt and copied to the system clipboard. The user pastes this into any web-based LLM, then pastes the JSON result back into the CLI.
  3. Abort — exit cleanly without writing anything.

Session State & Post-Bump Gap

~/.bethink.state.json persists the following between sessions, scoped to projectRoot + branch:

  • pendingEntries — entries collected but not yet committed.
  • bumpedVersion — the version written to the manifest in a prior Bump action that has not yet been tagged.
  • commitHash — the hash of the last associated commit, used for rollback and post-bump gap detection.
  • status'pending' | 'bumped' | 'committed'.

Post-bump gap detection: if commits were added to the branch after a version was bumped but before a tag was created, those commits are detected (git log <bumpCommitHash>..HEAD) and surfaced as a warning. The user is expected to account for them in the current session's entries.

State is cleared automatically after a successful Tag action. It can also be manually cleared via the Rollback option (which performs either git revert or git reset --soft on the saved commit hash).


Manifest Support

The manifest is auto-detected by probing the project directory in the following order:

| File | Ecosystem | Version field | Write behaviour | |------|-----------|--------------|-----------------| | package.json | Node.js | version | JSON field updated in-place. | | pyproject.toml | Python | version = "..." | TOML scalar replaced via regex. | | composer.json | PHP | version | JSON field updated in-place. | | go.mod | Go | (none — Git tags only) | Write is a no-op; the Tag action is the version. |


Configuration

~/.bethink.json is written by bethink --config. The current schema:

{
  "providers": [
    { "type": "ollama", "model": "qwen2.5:14b" },
    { "type": "gemini", "model": "gemini-1.5-flash", "apiKey": "AIza..." }
  ]
}

The first provider in the array is the default. Multiple providers are supported; the user can switch between them during a retry cycle.

Supported provider types:

| Type | Required fields | Notes | |------|----------------|-------| | ollama | model | Ollama must be running locally on port 11434. | | gemini | model, apiKey | Google Generative Language API. |


Prompt Customisation

All LLM prompts are plain .txt files in config/prompts/. Variables are interpolated with {{VARIABLE_NAME}} syntax at runtime. Editing these files changes the LLM's linguistic behaviour without touching source code.

| File | Variables | |------|-----------| | rephrase-entry.txt | {{VERBS}}, {{TYPE_LABEL}}, {{EXAMPLE}}, {{RAW_MESSAGE}} | | public-entry-suggestion.txt | {{TYPE}}, {{RAW_MESSAGE}}, {{DEV_REPHRASED}}, {{LIKELINESS}} | | commit-and-tag.txt | {{ENTRIES_LIST}}, {{TAG_NOTE}} | | clipboard-fallback.txt | {{PROJECT_ROOT}}, {{BRANCH}}, {{CURRENT_VERSION}}, {{COMMITS_SINCE_TAG}}, {{ENTRIES_LIST}}, {{DIFF_STAT}}, {{TASKS}} |


Architecture

bethink/
├── bin/
│   ├── cli.js                     Entry point. Linear state machine (PROVIDER → … → DONE).
│   └── config-wizard.js           Interactive provider setup wizard.
├── config/
│   └── prompts/
│       ├── rephrase-entry.txt
│       ├── public-entry-suggestion.txt
│       ├── commit-and-tag.txt
│       └── clipboard-fallback.txt
└── src/
    ├── core/
    │   ├── git-engine.js          All Git subprocess calls. Single responsibility.
    │   ├── changelog-writer.js    Writes CHANGELOG.md and RELEASE-NOTES.md.
    │   ├── version-engine.js      Pure semver calculation. Stateless.
    │   ├── config-manager.js      ~/.bethink.json loading and schema migration.
    │   ├── state-store.js         ~/.bethink.state.json persistence (bump→tag bridge).
    │   ├── workflow-orchestrator.js  Entry collection loop, LLM enrichment, fallback routing.
    │   └── action-executor.js     executeBump / executeCommit / executeTag — one each.
    ├── adapters/
    │   └── manifest-adapter.js    Strategy Pattern: package.json, pyproject.toml,
    │                              composer.json, go.mod.
    ├── llm/
    │   └── llm-client.js          Provider-agnostic completion layer. Prompt file loading.
    │                              All functions return { fromLLM: bool } — never throw.
    └── ui/
        ├── ui-renderer.js         Barrel re-export of display-renderer + prompt-handler.
        ├── display-renderer.js    Spinner, printInfo/Success/Warning/Error. No inquirer.
        └── prompt-handler.js      All inquirer interactive prompts. No business logic.

Separation of concerns:

  • cli.js owns the state machine and ctx object. It calls executors and renders nothing itself except the banner, entry list, and summary.
  • workflow-orchestrator.js owns the entry collection loop and LLM enrichment per entry. It does not know about versioning or Git tags.
  • action-executor.js owns write operations (manifest, changelog, git). It does not prompt.
  • llm-client.js owns all network I/O to LLM providers. It does not know about Git or the UI.
  • ui/ owns all terminal output and prompting. It does not perform any I/O except stdout and stdin.

File Reference

| File | Lines | Purpose | |------|-------|---------| | bin/cli.js | ~490 | State machine entry point (justified exception to 300-line limit — shared ctx across states makes splitting harmful) | | bin/config-wizard.js | ~205 | Provider wizard | | src/core/git-engine.js | ~221 | Git operations | | src/core/changelog-writer.js | ~142 | Changelog file writer | | src/core/version-engine.js | ~81 | Semver calculation | | src/core/config-manager.js | ~90 | Config file management | | src/core/state-store.js | ~117 | Session state persistence | | src/core/workflow-orchestrator.js | ~265 | Entry collection + LLM routing | | src/core/action-executor.js | ~175 | Bump / Commit / Tag execution | | src/adapters/manifest-adapter.js | ~200 | Manifest strategy pattern | | src/llm/llm-client.js | ~316 | LLM provider abstraction | | src/ui/display-renderer.js | ~103 | Chalk output, spinner | | src/ui/prompt-handler.js | ~472 | Inquirer prompts (justified exception — 16 uniform independent functions) | | src/ui/ui-renderer.js | ~14 | Barrel re-export |