@d3lm/pr-stats 0.2.23 → 0.2.24
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/README.md
CHANGED
|
@@ -99,7 +99,7 @@ The report holds a `review`, `authored`, and `comments` object with one entry pe
|
|
|
99
99
|
|
|
100
100
|
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.
|
|
101
101
|
|
|
102
|
-
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.
|
|
102
|
+
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. The Clear cache row in the settings dialog shows the path next to the size of the directory on disk, and deletes the cached PR data while keeping the saved options and settings.
|
|
103
103
|
|
|
104
104
|
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.
|
|
105
105
|
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
<key>CFBundlePackageType</key>
|
|
20
20
|
<string>APPL</string>
|
|
21
21
|
<key>CFBundleShortVersionString</key>
|
|
22
|
-
<string>0.2.
|
|
22
|
+
<string>0.2.24</string>
|
|
23
23
|
<key>CFBundleVersion</key>
|
|
24
|
-
<string>0.2.
|
|
24
|
+
<string>0.2.24</string>
|
|
25
25
|
<key>LSMinimumSystemVersion</key>
|
|
26
26
|
<string>13.0</string>
|
|
27
27
|
<key>LSUIElement</key>
|
|
Binary file
|
package/dist/tui-app.mjs
CHANGED
|
@@ -143,7 +143,7 @@ import { readFileSync as readFileSync3 } from "node:fs";
|
|
|
143
143
|
import { join as join3 } from "node:path";
|
|
144
144
|
|
|
145
145
|
// src/cache.ts
|
|
146
|
-
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
146
|
+
import { mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
147
147
|
import { homedir } from "node:os";
|
|
148
148
|
import { dirname, join } from "node:path";
|
|
149
149
|
var VERSION = 5;
|
|
@@ -163,6 +163,24 @@ function cacheDir() {
|
|
|
163
163
|
}
|
|
164
164
|
return join(process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "pr-stats");
|
|
165
165
|
}
|
|
166
|
+
function cacheSize() {
|
|
167
|
+
const dir = cacheDir();
|
|
168
|
+
let total = 0;
|
|
169
|
+
try {
|
|
170
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
171
|
+
for (const entry of entries) {
|
|
172
|
+
if (!entry.isFile()) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
total += statSync(join(dir, entry.name)).size;
|
|
177
|
+
} catch {
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
} catch {
|
|
181
|
+
}
|
|
182
|
+
return total;
|
|
183
|
+
}
|
|
166
184
|
function prKey(repo, number) {
|
|
167
185
|
return `${repo}#${number}`;
|
|
168
186
|
}
|
|
@@ -277,6 +295,19 @@ function fail(message) {
|
|
|
277
295
|
function formatMinutesOfDay(minutes) {
|
|
278
296
|
return `${Math.floor(minutes / 60)}:${String(minutes % 60).padStart(2, "0")}`;
|
|
279
297
|
}
|
|
298
|
+
function formatBytes(bytes) {
|
|
299
|
+
const units = ["B", "KiB", "MiB", "GiB", "TiB"];
|
|
300
|
+
let value2 = bytes;
|
|
301
|
+
let unit = 0;
|
|
302
|
+
while (value2 >= 1023.5 && unit < units.length - 1) {
|
|
303
|
+
value2 /= 1024;
|
|
304
|
+
unit += 1;
|
|
305
|
+
}
|
|
306
|
+
if (unit === 0) {
|
|
307
|
+
return `${value2} ${units[unit]}`;
|
|
308
|
+
}
|
|
309
|
+
return `${value2 < 10 ? value2.toFixed(1) : Math.round(value2)} ${units[unit]}`;
|
|
310
|
+
}
|
|
280
311
|
function percentile(sorted, percent) {
|
|
281
312
|
const index = Math.min(sorted.length - 1, Math.ceil(percent / 100 * sorted.length) - 1);
|
|
282
313
|
return sorted[Math.max(0, index)];
|
|
@@ -3794,7 +3825,7 @@ import { join as join6 } from "node:path";
|
|
|
3794
3825
|
// src/github.ts
|
|
3795
3826
|
import { execFile } from "node:child_process";
|
|
3796
3827
|
import { createHash } from "node:crypto";
|
|
3797
|
-
import { statSync } from "node:fs";
|
|
3828
|
+
import { statSync as statSync2 } from "node:fs";
|
|
3798
3829
|
import { join as join5, resolve } from "node:path";
|
|
3799
3830
|
import { promisify } from "node:util";
|
|
3800
3831
|
var execFileAsync = promisify(execFile);
|
|
@@ -3804,10 +3835,10 @@ var token;
|
|
|
3804
3835
|
var ghBinary = "gh";
|
|
3805
3836
|
function resolveDebugBinary(input) {
|
|
3806
3837
|
const resolved = resolve(input);
|
|
3807
|
-
const stats =
|
|
3838
|
+
const stats = statSync2(resolved, { throwIfNoEntry: false });
|
|
3808
3839
|
if (stats?.isDirectory()) {
|
|
3809
3840
|
const binary = join5(resolved, "gh");
|
|
3810
|
-
if (!
|
|
3841
|
+
if (!statSync2(binary, { throwIfNoEntry: false })?.isFile()) {
|
|
3811
3842
|
throw new CliError(`--debug directory "${input}" does not contain a gh executable`);
|
|
3812
3843
|
}
|
|
3813
3844
|
return binary;
|
|
@@ -5350,7 +5381,15 @@ function SettingValue({
|
|
|
5350
5381
|
return /* @__PURE__ */ jsx12(ToggleValue, { value: noCache2 ? "yes" : "no", isSelected });
|
|
5351
5382
|
}
|
|
5352
5383
|
case "clearCache": {
|
|
5353
|
-
return /* @__PURE__ */ jsx12(
|
|
5384
|
+
return /* @__PURE__ */ jsx12(
|
|
5385
|
+
PathValue,
|
|
5386
|
+
{
|
|
5387
|
+
path: cacheDir(),
|
|
5388
|
+
detail: formatBytes(cacheSize()),
|
|
5389
|
+
confirming: cacheAction === "confirm",
|
|
5390
|
+
isSelected
|
|
5391
|
+
}
|
|
5392
|
+
);
|
|
5354
5393
|
}
|
|
5355
5394
|
case "autoReload": {
|
|
5356
5395
|
return /* @__PURE__ */ jsx12(ToggleValue, { value: autoReload2 ? "yes" : "no", isSelected });
|
|
@@ -5428,11 +5467,22 @@ function IntervalValue({ value: value2, active, isSelected }) {
|
|
|
5428
5467
|
}
|
|
5429
5468
|
return /* @__PURE__ */ jsx12("text", { wrapMode: "none", fg: theme.muted, children: value2 });
|
|
5430
5469
|
}
|
|
5431
|
-
function PathValue({
|
|
5470
|
+
function PathValue({
|
|
5471
|
+
path,
|
|
5472
|
+
detail,
|
|
5473
|
+
confirming,
|
|
5474
|
+
isSelected
|
|
5475
|
+
}) {
|
|
5432
5476
|
if (confirming) {
|
|
5433
5477
|
return /* @__PURE__ */ jsx12("text", { wrapMode: "none", children: /* @__PURE__ */ jsx12("b", { fg: theme.warn, children: "enter to confirm" }) });
|
|
5434
5478
|
}
|
|
5435
|
-
return /* @__PURE__ */
|
|
5479
|
+
return /* @__PURE__ */ jsxs11("text", { wrapMode: "none", children: [
|
|
5480
|
+
/* @__PURE__ */ jsx12("span", { fg: isSelected ? theme.text : theme.muted, children: path.replace(homedir2(), "~") }),
|
|
5481
|
+
detail === void 0 ? null : /* @__PURE__ */ jsxs11("span", { fg: isSelected ? theme.muted : theme.dim, children: [
|
|
5482
|
+
" \xB7 ",
|
|
5483
|
+
detail
|
|
5484
|
+
] })
|
|
5485
|
+
] });
|
|
5436
5486
|
}
|
|
5437
5487
|
|
|
5438
5488
|
// src/tui/components/SnoozeModal.tsx
|