@davidcjw/questlog
v0.1.1
Published
A zero-dependency CLI that scans a folder of git repos and reports which ones need attention: uncommitted changes, unpushed commits, stale repos, and missing README/AGENTS.md/tests.
Maintainers
Readme
questlog
A zero-dependency CLI that scans a folder of git repos and tells you, at a glance, which ones need attention — uncommitted changes, unpushed commits, stale repos, and missing README / AGENTS.md / tests.
Built for people who keep dozens of side projects in one folder and lose track of which ones have local work that never got committed or pushed.
$ questlog ~/code
REPO BRANCH DIRTY UNPUSHED STALE GAPS
────────────────────────────────────────────────────────────────
miles-wallet main ●3 ↑2 12d —
timesync main — — 3d tests
osrs-hours-to-max main ●1 — 48d ⚠ README
41 repos · 7 dirty · 3 unpushed · 5 stale (>30d) · 4 with gapsThe demo above was recorded with vhs against a sample folder — regenerate with vhs docs/demo.tape.
Table of Contents
- Why
- Install
- Usage
- What each column means
- JSON output
- How it works
- Development
- Contributing
- Code of Conduct
- License
- Roadmap
- Acknowledgements
Why
If ~/code holds 40 repos, "which ones have work I forgot to push?" is a real question. questlog answers it in one command, with no config and no runtime dependencies — it just shells out to the git you already have.
Install
Requires Node.js >= 18 and git on your PATH.
# run without installing
npx @davidcjw/questlog ~/code
# or install globally
npm install -g @davidcjw/questlog
questlog ~/code
# or clone and link for development
git clone <repo-url> questlog && cd questlog
npm install
npm linkUsage
questlog [path] [options]path defaults to the current directory. If path is itself a git repo, only that repo is shown; otherwise its immediate subdirectories are scanned for repos.
Options
| Option | Description |
| --- | --- |
| --stale-days <n> | Days since last commit before a repo is "stale" (default 30). |
| --depth <n> | How many folder levels deep to search (default 1). |
| --dirty-only | Show only repos with uncommitted changes. |
| --unpushed-only | Show only repos with unpushed commits. |
| --stale-only | Show only stale repos. |
| --gaps-only | Show only repos missing README / AGENTS.md / tests. |
| --attention | Show only repos that need attention (any of the above). |
| --json | Output machine-readable JSON. |
| --no-color | Disable ANSI colors (also respects NO_COLOR). |
| --ci | Exit with code 1 if any repo is dirty, unpushed, or stale. |
| -h, --help | Show help. |
| -v, --version | Show version. |
Examples
# everything in ~/code
questlog ~/code
# only repos that need attention, with a tighter staleness window
questlog ~/code --stale-days 14 --attention
# dump JSON for scripting
questlog ~/code --json > status.json
# fail a pre-push hook / CI step if the current repo is dirty or unpushed
questlog . --ciWhat each column means
- DIRTY —
●N: N changed or untracked entries in the working tree. - UNPUSHED —
↑N: N commits on the current branch not yet on its upstream.?means no upstream is configured. - STALE — days since the last commit;
⚠once it crosses--stale-days. - GAPS — which of
README,AGENTS.md, or tests are missing. (Tests are detected via atest/tests/__tests__/specdirectory or a realpackage.jsontestscript.)
JSON output
--json prints { root, summary, repos[] }, where each repo has name, path, branch, dirty, unpushed, ageDays, stale, gaps, and error. Useful for piping into jq or a dashboard.
How it works
questlog is intentionally small and layered so it's easy to reason about and test:
src/git.js— thin, best-effort wrappers around thegitbinary.src/scan.js— repo discovery + filesystem heuristics (the only other I/O layer).src/analyze.js— pure functions: facts → report rows + summary (clock injected).src/format.js— pure presentation: rows → table or JSON.src/cli.js— argument parsing and orchestration, written so it can be tested without spawning a process.
Development
npm install
npm test # run the vitest suite
npm run coverage # with coverage
npm start -- ~/codeContributing
Contributions are welcome! Please open an issue first to discuss what you'd like to change.
- Fork the repo
- Create a feature branch (
git checkout -b feature/your-feature) - Commit your changes (
git commit -m 'feat: describe change') - Push and open a pull request
Please keep analyze.js / format.js pure (no I/O, clock injected) and make sure npm test passes before submitting a PR.
Code of Conduct
This project follows the Contributor Covenant v2.1. By participating you agree to uphold a welcoming, harassment-free environment.
License
Distributed under the MIT License. See LICENSE for details.
© David Chong
Roadmap
- [ ]
--fetchto compare against remotes before counting unpushed/behind commits - [ ] Show "behind upstream" counts alongside unpushed
- [ ] Configurable columns and a
--sortflag - [ ] Optional config file (
.questlogrc) for default root, stale window, and ignores - [ ] Watch mode for a live dashboard
Acknowledgements
Built to tame a ~/code folder with dozens of side projects. Powered by the git you already have — no runtime dependencies.
