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

@kirchdev/gitignore-sync

v0.5.0

Published

CLI that keeps a repo's .gitignore maintained — curated blocks inside a managed region, re-rendered idempotently, nothing outside it touched.

Readme

🧰 gitignore-sync

Keeps your .gitignore maintained, not generated — curated blocks in a region the tool owns, everything else untouched

npm Version Downloads Tests Node Version License: MIT


npx @kirchdev/gitignore-sync init     # fingerprint the repo, confirm, write the region
npx @kirchdev/gitignore-sync sync     # re-render it, any time, as often as you like

That's it. The blocks the tool owns stay current; every line you wrote yourself survives verbatim.

🤔 Why

gitignore.io, gig and ignr all fetch and dump: you pull a template once, paste it, and drift from there. None of them re-syncs, so a .gitignore grows into a few hundred lines of ballast nobody dares touch.

gitignore-sync keeps a managed region inside the file and re-renders it on demand. The rest of the file is a free zone the tool never writes to — which is what makes running it a second time safe, and a hundredth time boring.

📦 Installation

pnpm add -g @kirchdev/gitignore-sync   # npm i -g / yarn global add / bun add -g all work

Or run it without installing: npx @kirchdev/gitignore-sync <command>. The binary is also available as gis.

🚀 Quick start

gitignore-sync init             # detect, confirm in a prompt, write the region
gitignore-sync edit             # tick stacks on and off later
gitignore-sync add nuxt tauri   # or name them — for scripts and CI
gitignore-sync remove intellij  # drop one; your own lines are kept
gitignore-sync sync             # re-render from the header
gitignore-sync check            # CI gate: non-zero on drift
gitignore-sync list             # what this binary ships, and what you declare
gitignore-sync info             # which build is running, and what it sees
gitignore-sync audit ../*/      # how much of a whole estate the stacks cover
gitignore-sync check -r         # every managed region in the tree, not just the root

Every command takes --help and a directory (--dir for add/remove, positional elsewhere), and every writing command takes --dry-run.

[!TIP] init shows everything it found — your editor and platform included — and asks once:

ℹ Found 8 stacks: core, git, node, nuxt, tauri, dotenv, vscode, linux
? Use them? › Yes / No

In CI it asks nothing — --yes or no terminal takes the committed fingerprints alone, says what it skipped, and writes. Your platform must not end up in a committed header because a pipeline ran.

✨ Features

  • 🔁 Re-syncs, never re-dumpssync is idempotent, so it belongs in a habit, a hook or a cron, not in a one-off ritual.
  • 🛡️ Your lines are never lost — a hand-written line found inside a managed block is moved to the free zone, not deleted. That rule is what makes the second run safe.
  • 🔍 Dedup that knows git — exact duplicates go; .idea, .idea/, /.idea and .idea/* are four different patterns to git, so they are reported, never silently merged.
  • 🧹 Orphaned headings swept — when a managed block absorbs every pattern under a # Comment, the heading goes with them. A block that was only ever a note stays.
  • ⚠️ Catches the mistake that breaks ! — a stray .vscode beside a !.vscode/extensions.json block silently disables it, because git never looks inside an ignored directory. That gets its own warning.
  • 🧭 No surprise rewritesinit detects, sync does not. Adding a package.json never quietly rewrites your .gitignore; sync --detect proposes and stops there.
  • 🗂️ Folds in your editor — the region uses # region / # endregion, so VSCode collapses a 40-line managed block to a single line, at both nesting levels.
  • 📋 A real CI gatecheck reports drift and duplicates and exits non-zero, so a stale block fails the build instead of rotting.

🗂️ The shape

# region gitignore-sync
# stacks: core, node, vscode, intellij
# ─────────────────────────────────────────

# region core@v1
.DS_Store
.claude/settings.local.json
# endregion

# region node@v1
node_modules
dist
coverage
# endregion

# endregion

# ─── your rules, never touched ───
frankenphp
/bootstrap/ssr

Everything below the closing # endregion is the free zone: yours, preserved line for line.

🧩 Stacks

Twenty-one curated blocks, each derived from what the estate actually ignores rather than from a public template site.

| Stack | What it covers | Proposed by init when | | :--------- | :----------------------------------- | :---------------------------- | | core | .DS_Store | always | | agents | agent working files, not their config| .claude/, .codex/, … | | git | merge and backup droppings | always (it is a git repo) | | node | modules, build output, logs, caches | package.json | | dotenv | .env*, minus the committed example | .env.example or .env | | php | /vendor, PHPUnit caches | composer.json | | laravel | build output, storage keys, SSR | artisan | | go | test and build droppings | go.mod | | tofu | state, tfvars, local overrides | *.tf / *.tofu | | nuxt | .nuxt, .output, .nitro | nuxt.config.* | | tauri | src-tauri/target, generated schemas| src-tauri/ | | rust | /target | a root Cargo.toml | | turborepo| .turbo | turbo.json | | playwright | test-results, reports | playwright.config.* | | storybook| storybook-static | .storybook/ | | vscode | .vscode/* + the shared files | you have a .vscode/ | | intellij | .idea/* | you have a .idea/ | | vim | swap and session files | your $EDITOR is vim | | macos | AppleDouble, Spotlight, Trashes | you are on a Mac | | windows | Thumbs.db, desktop.ini, Recycle Bin | you are on Windows | | linux | *~, trash and NFS droppings | you are on Linux |

gitignore-sync list prints this for the binary you have installed, marking the ones your repo declares.

⚙️ Configuration

There is no config file. The configuration is the # stacks: line in the .gitignore itself — the header is input, the blocks below it are output.

| Edit | Effect after sync | | :-------------------------------- | :--------------------------------------------- | | Add a name to # stacks: | Its block is rendered into the region | | Remove a name from # stacks: | Its block disappears; your own lines are kept | | Nothing | Nothing — sync is a no-op on a synced file |

[!IMPORTANT] Nothing in a repository can tell you what the other contributors use — .vscode/ and .idea/ are themselves ignored. So those stacks are proposed from your own machine and written down once, rather than re-guessed on every run. Only repository fingerprints reach the non-interactive path; a CI runner's platform must not end up in a committed header.

🧪 Use in CI

- run: npx @kirchdev/gitignore-sync check

check writes nothing. It exits non-zero when the file has drifted from its header, and prints what it would have changed.

There is also an action, for a job summary on failure and a status output:

- uses: kirchDev/[email protected]
  with:
    version: '0.1.0'   # pin it, so a release cannot turn a green pipeline red

[!NOTE] --recursive on audit and check walks the whole tree, skipping build output, dependencies, nested repositories, and anything the repo's own .gitignore names. Laravel's storage/ stubs and other directory keepers (* plus !.gitignore) are listed as skipped rather than measured — the framework owns them.

[!TIP] Repos whose CI derives its task list from package.json need neither — add gitignore-sync check to your check script and it comes along.

🤝 Contributing

PRs welcome. Conventional Commits required (enforced via commitlint). Husky runs the project's linters/formatters on git commit.

[!TIP] Run pnpm check:fix before pushing — CI will catch what husky missed.

See CONTRIBUTING.md for the full workflow.

🛣️ Versioning

Semantic Versioning via release-please — see CHANGELOG.md.

📄 License

MIT © Titus Kirch / IT-Dienstleistungen Titus Kirch