@d3lm/pr-stats 0.2.12 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +51 -45
- package/dist/tui-app.mjs +1988 -1854
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dominic Elm
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
# pr-stats
|
|
2
2
|
|
|
3
|
-
An interactive terminal UI, built with [OpenTUI](https://github.com/anomalyco/opentui) and React
|
|
3
|
+
An interactive terminal UI for GitHub PR statistics, built with [OpenTUI](https://github.com/anomalyco/opentui) and React. It shows time to review, PR size, and comment stats for any repository your GitHub login can see, plus a live queue of the PRs waiting on you.
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
|
-
The TUI renders through native FFI
|
|
10
|
-
|
|
11
|
-
- An authenticated gh CLI. Run `gh auth login` if you have not set that up yet.
|
|
12
|
-
- A GitHub access token, passed through `--token` or the `GITHUB_TOKEN` or `GH_TOKEN` environment variable. When a token is present, the tool calls the GitHub API directly and does not need the gh CLI at all. The token needs the `repo` scope to see private repositories.
|
|
9
|
+
- Node 26.4+ or Bun 1.3+. The TUI renders through native FFI. Node gates that behind `--experimental-ffi`, and the launcher re-executes itself with the flag, so a plain `pr-stats` works on both runtimes.
|
|
10
|
+
- Either an authenticated gh CLI (`gh auth login`) or a GitHub access token via `--token`, `GITHUB_TOKEN`, or `GH_TOKEN`. With a token, the tool calls the GitHub API directly and does not need the gh CLI. Private repositories need the `repo` scope.
|
|
13
11
|
|
|
14
12
|
## Install
|
|
15
13
|
|
|
@@ -17,7 +15,7 @@ The TUI renders through native FFI, so it needs either Node 26.4 or newer, or [B
|
|
|
17
15
|
npm install -g @d3lm/pr-stats
|
|
18
16
|
```
|
|
19
17
|
|
|
20
|
-
You can also run it without installing through `npx @d3lm/pr-stats
|
|
18
|
+
You can also run it without installing through `npx @d3lm/pr-stats` or `bunx --bun @d3lm/pr-stats`.
|
|
21
19
|
|
|
22
20
|
## Usage
|
|
23
21
|
|
|
@@ -25,19 +23,41 @@ You can also run it without installing through `npx @d3lm/pr-stats`. The bunx eq
|
|
|
25
23
|
pr-stats
|
|
26
24
|
```
|
|
27
25
|
|
|
28
|
-
Without flags, it
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
When the data spans multiple repos, every tab opens on a repo picker that drills into one repo or the aggregate
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
All flags pre-seed the options modal
|
|
26
|
+
Without flags, it covers PRs from the last 90 days across all repositories you can access.
|
|
27
|
+
|
|
28
|
+
- **Queue** lists the open PRs awaiting your review with their wait time, and below them the open PRs you already reviewed. A fresh review request moves a PR back into the awaiting list.
|
|
29
|
+
- **Your PRs** splits into your open PRs and a merged-and-closed report with merge-time, first-review, backlog, and outcome charts plus a reviewer leaderboard. The `t` key switches the sub-tabs.
|
|
30
|
+
- **Time to review** charts your review times as a histogram, trend, heatmap, and weekly volume, plus review cycles, verdicts, an off-hours gauge, and the requests still waiting on you.
|
|
31
|
+
- **PR size** carries the same charts for PR sizes and adds a weekly net-lines trend.
|
|
32
|
+
- **Comments** holds a histogram of comments per PR, a scatter against PR size, and the most commented PRs.
|
|
33
|
+
|
|
34
|
+
When the data spans multiple repos, every tab opens on a repo picker that drills into one repo or the aggregate. On the queue lists, `g` groups the aggregate by repo, and on stats tabs, `x` lifts the row cap on comparison cards.
|
|
35
|
+
|
|
36
|
+
## Options
|
|
37
|
+
|
|
38
|
+
All flags pre-seed the options modal. Run `pr-stats --help` for full details.
|
|
39
|
+
|
|
40
|
+
| Flag | Default | Description |
|
|
41
|
+
| ----------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `-s, --since <value>` | `90d` | Only include PRs created after this point. Accepts an ISO date or a relative value like `30d`, `8w`, `6m`, `1y`. |
|
|
43
|
+
| `-r, --repo <name>` | all repos | Restrict the search to a repository, repeatable. Accepts `owner/name` or a bare name. |
|
|
44
|
+
| `-u, --user <login>` | you | Compute stats for this user instead of the authenticated one. |
|
|
45
|
+
| `--token <token>` | | Authenticate with a GitHub access token instead of the gh CLI. |
|
|
46
|
+
| `-t, --target <value>` | | Report how many reviews finished within this time, like `24h`, `2d`, or `90m`. |
|
|
47
|
+
| `--target-percentile <value>` | `90` | Check the target against this percentile of your review times, like `90` or `p90`. |
|
|
48
|
+
| `--size-target <value>` | | Report how many authored PRs fit within this size, like `400`, `400l`, `20f`, or `400l,20f`. |
|
|
49
|
+
| `--tz <zone>` | system | Set the IANA timezone for the weekend and working-hours math. |
|
|
50
|
+
| `--work-days <days>` | `mon-fri` | Count only these days as working days, like `mon-fri`, `sun-thu`, or `mon,wed,fri`. |
|
|
51
|
+
| `-w, --work-hours <value>` | `0-24` | Count only these working hours, like `9-17`, `8:30-16:30`, or `9am-6pm`. |
|
|
52
|
+
| `--wall-clock` | off | Measure raw elapsed time, including weekends. |
|
|
53
|
+
| `--include-drafts` | off | Include PRs that are currently drafts. |
|
|
54
|
+
| `--review-types <list>` | all | Count only these review types. Takes a comma-separated list of `approve`, `comment`, and `request-changes`. |
|
|
55
|
+
| `--no-cache` | off | Refetch every PR instead of reading the disk cache. |
|
|
56
|
+
| `--json` | off | Print every stat as JSON to stdout instead of starting the TUI. |
|
|
57
|
+
| `--debug <path>` | | Serve canned data from a fake `gh` binary in a testdata directory. |
|
|
58
|
+
| `-h, --help` | | Show the help page. |
|
|
59
|
+
|
|
60
|
+
A few examples:
|
|
41
61
|
|
|
42
62
|
```bash
|
|
43
63
|
# Limit the search to one repository and a start date
|
|
@@ -46,49 +66,31 @@ pr-stats --repo owner/name --since 2026-01-01
|
|
|
46
66
|
# Report how many reviews finished within one working day
|
|
47
67
|
pr-stats --work-hours 9-17 --target 1d
|
|
48
68
|
|
|
49
|
-
# Report how many authored PRs stayed under 400 changed lines
|
|
50
|
-
pr-stats --size-target 400
|
|
51
|
-
|
|
52
69
|
# Count only approvals and change requests as reviews
|
|
53
70
|
pr-stats --review-types approve,request-changes
|
|
54
|
-
|
|
55
|
-
# Authenticate with an access token instead of the gh CLI
|
|
56
|
-
pr-stats --token your-access-token
|
|
57
71
|
```
|
|
58
72
|
|
|
59
|
-
Run `pr-stats --help` for the full list of options.
|
|
60
|
-
|
|
61
73
|
## JSON export
|
|
62
74
|
|
|
63
|
-
The `--json` flag prints
|
|
75
|
+
The `--json` flag prints the full report to stdout instead of starting the TUI. Every other flag applies the same way, and progress renders on stderr, so a piped stdout stays pure JSON.
|
|
64
76
|
|
|
65
77
|
```bash
|
|
66
78
|
pr-stats --json | jq '.review.reviewTimeHours'
|
|
67
79
|
```
|
|
68
80
|
|
|
69
|
-
The report
|
|
70
|
-
|
|
71
|
-
The settings dialog has an export row that writes the same report to `pr-stats.json` in the directory pr-stats was started from, built from the data currently on screen and the live options.
|
|
81
|
+
The report holds a `review`, `authored`, and `comments` object with one entry per PR. Summaries report the count, mean, p50, p90, min, and max, and every duration respects the configured time mode. The settings dialog has an export row that writes the same report to `pr-stats.json` in the current directory.
|
|
72
82
|
|
|
73
83
|
## Caching
|
|
74
84
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
The login of the authenticated user is cached for a day as well, which skips one round trip per run. A configured `--user` never touches that cache. The TUI additionally snapshots the last successful load, and a later start with the same data options renders the snapshot instantly while the real load refreshes it in the background. A narrower `--since` window also hits the snapshot, because the subset gets cut from it by PR creation date.
|
|
85
|
+
Closed and merged PRs are cached on disk per PR, because their timelines and sizes no longer change. Searches and open PRs are fetched fresh on each run. The TUI also snapshots the last successful load, so a later start with the same options renders instantly while the real load refreshes in the background.
|
|
78
86
|
|
|
79
|
-
The cache lives in `~/Library/Caches/pr-stats` on macOS and in `$XDG_CACHE_HOME/pr-stats` or `~/.cache/pr-stats` elsewhere. The `PR_STATS_CACHE_DIR` environment variable overrides the location.
|
|
87
|
+
The cache lives in `~/Library/Caches/pr-stats` on macOS and in `$XDG_CACHE_HOME/pr-stats` or `~/.cache/pr-stats` elsewhere. The `PR_STATS_CACHE_DIR` environment variable overrides the location. `--no-cache` skips every cache read for one run, and the settings dialog can disable the cache permanently.
|
|
80
88
|
|
|
81
|
-
The options modal
|
|
82
|
-
|
|
83
|
-
The settings dialog can also disable the cache permanently. The toggle persists to `settings.json` in the cache directory, so every later run refetches everything the way `--no-cache` does. An explicit `--no-cache` flag always wins over the saved setting. The same dialog switches the color theme, described under Theming below. The dialog can also reset the settings, which deletes `settings.json` together with a saved theme, so future runs start from the defaults.
|
|
89
|
+
The options modal saves the current options to the cache directory with the `s` key. Later runs start from the saved options wherever no flag was given, and flags always take precedence.
|
|
84
90
|
|
|
85
91
|
## Theming
|
|
86
92
|
|
|
87
|
-
The TUI ships five built-in themes, the warm amber default plus green, blue, purple, and yellow variants.
|
|
88
|
-
|
|
89
|
-
The Edit colors row below it opens a list of every theme color with its current hex value. Enter edits the selected color in place, and a committed value applies immediately. The first edit creates a custom theme that starts from the built-in theme on screen, and the Theme row switches to `custom`. Further edits refine the custom theme, and an empty value returns a color to the built-in the custom theme started from. Clearing the last custom color dissolves the custom theme back into that built-in.
|
|
90
|
-
|
|
91
|
-
The custom theme joins the Theme row cycle as a sixth entry and persists across switches, so picking a built-in theme renders it pure while the custom colors stay saved, and cycling back to `custom` restores them. Everything lands in a `theme` object in `settings.json` in the cache directory, which you can also edit by hand:
|
|
93
|
+
The TUI ships five built-in themes, the warm amber default plus green, blue, purple, and yellow variants. The Theme row in the settings dialog cycles through them, and the Edit colors row below it edits individual colors, which creates a custom theme that joins the cycle as a sixth entry. Everything persists in a `theme` object in `settings.json` in the cache directory, which you can also edit by hand.
|
|
92
94
|
|
|
93
95
|
```json
|
|
94
96
|
{
|
|
@@ -101,8 +103,12 @@ The custom theme joins the Theme row cycle as a sixth entry and persists across
|
|
|
101
103
|
}
|
|
102
104
|
```
|
|
103
105
|
|
|
104
|
-
The `preset` key names the active theme, one of `default`, `green`, `blue`, `purple`, `yellow`, and `custom`. The `base` key names the built-in theme the custom colors start from
|
|
106
|
+
The `preset` key names the active theme, one of `default`, `green`, `blue`, `purple`, `yellow`, and `custom`. The `base` key names the built-in theme the custom colors start from. The color keys are `bg`, `border`, `text`, `muted`, `dim`, `accent`, `selectedBg`, `inputBg`, `inputFocusedBg`, `warn`, `error`, `success`, `chartBar`, `chartLine`, `chartDim`, and `heat`, where `heat` takes four heatmap colors from cool to hot. An invalid key or color fails the start with a message naming the mistake.
|
|
105
107
|
|
|
106
108
|
## Development
|
|
107
109
|
|
|
108
|
-
The TUI runs with `bun tui/main.tsx
|
|
110
|
+
The TUI runs with `bun tui/main.tsx`, or under Node with `pnpm tui:node`. The `--debug tui/testdata` flag serves canned data from the fake `gh` binary in that directory instead of fetching from GitHub, and `bun test tui` drives the whole pipeline against it. `pnpm build` bundles everything into `dist/`, where `tui.mjs` is the launcher and `tui-app.mjs` is the app bundle it loads.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
OpenTUI is licensed under the [MIT License](LICENSE).
|