@yaroslavhaidash/gitstats-cli 0.2.0 → 0.2.1

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +30 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Counts commits and lines in the git repos on your computer and sends **only the numbers** (per repo, per week) to your [gitstats](https://gitstats-three-zeta.vercel.app) profile. No file contents, no diffs, no GitHub tokens, no permissions on GitHub.
4
4
 
5
5
  ```bash
6
- npx --yes github:yaroslavhaidash/gitstats-cli link
6
+ npx @yaroslavhaidash/gitstats-cli@latest link
7
7
  ```
8
8
 
9
9
  That pairs this computer (you confirm in the browser), scans your home folder for repos, uploads the last year, and installs a daily background sync (launchd on macOS, Task Scheduler on Windows, systemd user timer on Linux). Nothing else to remember.
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * gitstats CLI — counts commits and lines in the git repos on this machine and sends ONLY the
4
4
  * numbers (per repo, per week) to your gitstats profile. No file contents, no diffs, no GitHub tokens.
5
5
  *
6
- * npx --yes github:yaroslavhaidash/gitstats-cli link
6
+ * npx @yaroslavhaidash/gitstats-cli@latest link
7
7
  * pair this computer, scan for repos, sync, install a daily sync
8
8
  * gitstats sync fetch each repo's default branch, recount the last year, upload (idempotent; --no-fetch to skip)
9
9
  * gitstats status show what is linked and when it last ran
@@ -29,6 +29,7 @@ const DIR = join(HOME, ".gitstats");
29
29
  const CONFIG = join(DIR, "config.json");
30
30
  const SELF = join(DIR, "cli");
31
31
  const DAYS = 365;
32
+ const PENDING_DAYS = 30;
32
33
  const SKIP_DIRS = new Set(["node_modules", "Library", "Applications", ".Trash", "vendor", "target", "build", "dist", ".venv", "venv", "__pycache__", "Pods", "DerivedData", "go", ".cargo", ".rustup", ".npm", ".cache", ".local", "snap", "AppData"]);
33
34
  const args = process.argv.slice(2);
34
35
  const cmd = args[0] ?? "help";
@@ -127,6 +128,30 @@ function defaultRef(repo) {
127
128
  }
128
129
  return "HEAD";
129
130
  }
131
+ /**
132
+ * Remote branches whose work has not landed on the default branch yet. Only `refs/remotes/origin`
133
+ * counts, and only tips touched in the last 30 days: local branches left behind by squash-merged
134
+ * worktrees are the same commits over again, and they inflated pending by 14x.
135
+ */
136
+ function pendingRefs(repo, ref) {
137
+ const out = git(repo, "for-each-ref", "--format=%(refname) %(committerdate:unix)", "refs/remotes/origin");
138
+ if (out === null)
139
+ return [];
140
+ const cutoff = Date.now() / 1000 - PENDING_DAYS * 86_400;
141
+ const refs = [];
142
+ for (const line of out.split("\n")) {
143
+ const [name, when] = line.split(" ");
144
+ if (!name || !when)
145
+ continue;
146
+ const short = name.slice("refs/remotes/".length);
147
+ if (short === ref || short === "origin/HEAD")
148
+ continue;
149
+ if (Number(when) < cutoff)
150
+ continue;
151
+ refs.push(name);
152
+ }
153
+ return refs;
154
+ }
130
155
  // ---------- counting ----------
131
156
  const LANG = {
132
157
  ts: "TypeScript", tsx: "TypeScript", js: "JavaScript", jsx: "JavaScript", mjs: "JavaScript", cjs: "JavaScript",
@@ -199,8 +224,8 @@ function countRepo(repo, emails, since, salt, sendNames, fetch) {
199
224
  const out = git(repo, "log", ref, ...common, ...authors);
200
225
  if (out === null)
201
226
  return null;
202
- // Everything on any other local or remote branch that the default branch has not taken in yet.
203
- const pendingOut = git(repo, "log", "--all", "--not", ref, ...common, ...authors);
227
+ const unmerged = pendingRefs(repo, ref);
228
+ const pendingOut = unmerged.length > 0 ? git(repo, "log", ...unmerged, "--not", ref, ...common, ...authors) : null;
204
229
  const merged = tally(out, all);
205
230
  const pending = pendingOut === null ? EMPTY_TALLY() : tally(pendingOut, all);
206
231
  if (merged.weeks.size === 0 && pending.weeks.size === 0)
@@ -493,14 +518,14 @@ async function link() {
493
518
  log(`\n scheduled: ${how}`);
494
519
  log(` config: ${CONFIG}`);
495
520
  log(`\n done. It re-syncs on its own. To run commands by hand, either use`);
496
- log(` npx --yes github:yaroslavhaidash/gitstats-cli <command>`);
521
+ log(` npx @yaroslavhaidash/gitstats-cli@latest <command>`);
497
522
  log(` or add ${BIN} to your PATH and use \`gitstats <command>\`.`);
498
523
  log(` Commands and how to stop: ${server}/docs\n`);
499
524
  }
500
525
  function requireConfig() {
501
526
  const c = loadConfig();
502
527
  if (!c)
503
- throw new Error("not linked yet; run: npx --yes github:yaroslavhaidash/gitstats-cli link");
528
+ throw new Error("not linked yet; run: npx @yaroslavhaidash/gitstats-cli@latest link");
504
529
  return c;
505
530
  }
506
531
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaroslavhaidash/gitstats-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Counts your commits and lines locally and sends only the numbers to your gitstats board.",
5
5
  "license": "MIT",
6
6
  "type": "module",