gh-glance 0.16.0 → 0.16.2

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/CHANGELOG.md CHANGED
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.16.2] - 2026-10-03
11
+
12
+ No change to the dashboard itself: `index.mjs` is identical to 0.16.1. This
13
+ release changes how gh-glance is tested and published.
14
+
15
+ ### Changed
16
+
17
+ - The published npm package is now the exact tarball the release pull request
18
+ tested: CI packs it once, the package and terminal smoke checks run those
19
+ bytes, and the release workflow verifies the tested tree, run, archive digest and
20
+ tarball digests before publishing it with lifecycle scripts disabled and
21
+ pinned Node 22.22.2 / npm 11.21.0. A version collision or an unclear
22
+ registry answer stops publication instead of skipping it.
23
+ - Release delivery is checked automatically: registry integrity, npm
24
+ provenance bound to this release workflow, tag and merge commit, and a fresh
25
+ install run on Node 22 and 24.
26
+ - CI runs the full suites once, on the release pull request; pushes to
27
+ `develop` and `main` run quick checks or a promotion identity check, and
28
+ coverage runs on a schedule instead of on every push.
29
+ - README: the live freshness monitor section explains how to observe the
30
+ default on-demand mode (continuously active Actions only).
31
+
32
+ ## [0.16.1] - 2026-10-02
33
+
34
+ ### Fixed
35
+
36
+ - When external API use pushes every pane's next request slot past the quota
37
+ reset, panes now show "GitHub quota pacing; retry automatically after reset"
38
+ instead of "Local coordination unavailable ... retry when storage works".
39
+ Deferred background refreshes also get their own notice.
40
+ - Heavy API use by other tools on the same account no longer starves every
41
+ pane until the quota resets. Pacing now divides by at most 4 times the
42
+ measured external pressure, while the reserve still stops gh-glance before
43
+ the account runs out.
44
+ - Uncertain charges left by dead panes are released one quota window after
45
+ their newest charge, instead of reducing every hour's budget until the next
46
+ reboot.
47
+
10
48
  ## [0.16.0] - 2026-10-01
11
49
 
12
50
  ### Changed
@@ -1216,7 +1254,9 @@ engineering, security, QA and UX. What follows is what changed as a result.
1216
1254
  - The `main` field from `package.json`. It advertised the file as importable,
1217
1255
  but importing it took over the terminal or exited the host process.
1218
1256
 
1219
- [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.16.0...HEAD
1257
+ [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.16.2...HEAD
1258
+ [0.16.2]: https://github.com/juan294/gh-glance/compare/v0.16.1...v0.16.2
1259
+ [0.16.1]: https://github.com/juan294/gh-glance/compare/v0.16.0...v0.16.1
1220
1260
  [0.16.0]: https://github.com/juan294/gh-glance/compare/v0.15.2...v0.16.0
1221
1261
  [0.15.2]: https://github.com/juan294/gh-glance/compare/v0.15.1...v0.15.2
1222
1262
  [0.15.1]: https://github.com/juan294/gh-glance/compare/v0.15.0...v0.15.1
package/README.md CHANGED
@@ -946,6 +946,17 @@ SIGINT, or a sample gap over 15 seconds makes the report nonqualifying. A sleep
946
946
  gap requires a new uninterrupted window. A schema 1 manifest supports a
947
947
  diagnostic `--once` read only; it cannot qualify a run.
948
948
 
949
+ Under the default `--background on-demand`, only the active Actions tab is
950
+ watched continuously; Issues, Pull Requests and Security are fetched when
951
+ opened or on `r`. Declare only those continuously active Actions panes in a
952
+ monitored window, and check secondary views with separate one-shot assertions:
953
+ a perpetual cadence oracle over an intentionally idle tab would report a false
954
+ stall. A bounded release canary (one already running Actions pane, at most five
955
+ minutes and 20 extra admissions per resource above the quota floor) is planned
956
+ offline by `planCanary` in `scripts/release-policy.mjs`, which emits exactly
957
+ such a schema 2 manifest and the stop rule; it cannot qualify the 24-hour
958
+ windows.
959
+
949
960
  Provider-limit exclusions require `--external-evidence` pointing to an
950
961
  append-only JSON trace with `schema: 1` and an `events` array. Each `raw-http`
951
962
  event records the independently captured issue and finish timestamps, host,
package/index.mjs CHANGED
@@ -2289,6 +2289,12 @@ function sharedLaneEvidence(value) {
2289
2289
  // Below this many completed shared calls in a probe window, external-spend
2290
2290
  // inference is noise. Under the threshold the loop retains the previous factor.
2291
2291
  const MIN_SAMPLE_CALLS = 5;
2292
+ // Pacing divides the spendable share by the external factor, so a large factor
2293
+ // compounds: gh-glance's own paid calls shrink, the next sample's ratio grows,
2294
+ // and the lane is pushed past the reset while quota sits unused. The reserve,
2295
+ // not this divisor, is what keeps gh-glance off the floor, so the divisor can
2296
+ // be bounded without letting external load exhaust the account.
2297
+ const MAX_PACING_EXTERNAL_FACTOR = 4;
2292
2298
 
2293
2299
  const REQUEST_PRIORITIES = Object.freeze({
2294
2300
  manual: 0,
@@ -2517,7 +2523,8 @@ function resourceDecision({
2517
2523
  epoch: capacity.epoch,
2518
2524
  };
2519
2525
  }
2520
- const callsPerMs = capacity.spendable / (capacity.resetMs - nowMs) / externalFactor;
2526
+ const callsPerMs = capacity.spendable / (capacity.resetMs - nowMs) /
2527
+ Math.min(externalFactor, MAX_PACING_EXTERNAL_FACTOR);
2521
2528
  if (!Number.isFinite(callsPerMs) || callsPerMs <= 0) {
2522
2529
  return {
2523
2530
  mode: "paused",
@@ -4564,6 +4571,9 @@ function transferReceiptToDebt(state, receipt, nowMs, groupId = null) {
4564
4571
  group.units[resource] += amount;
4565
4572
  group.counts[resource] += amount > 0 ? 1 : 0;
4566
4573
  }
4574
+ // The newest charge, not the group's creation, starts the window after
4575
+ // which reconcileBootDebt may treat the group as settled.
4576
+ group.at = Math.max(group.at, nowMs);
4567
4577
  state.debtGroups[id] = group;
4568
4578
  return true;
4569
4579
  }
@@ -4611,12 +4621,17 @@ function retireControlReceiptToDebt(state, resource, at) {
4611
4621
  return true;
4612
4622
  }
4613
4623
 
4624
+ // A reboot proves an unknown owner's children are gone. So does age: a group's
4625
+ // `at` is its newest charge, and once a full window has elapsed since then
4626
+ // GitHub has charged every covered request to a window that is already over.
4614
4627
  function reconcileBootDebt(state, at) {
4615
4628
  const bootId = coordinationBootId();
4616
- if (bootId === null) return { ok: true, changed: false };
4617
4629
  let changed = false;
4618
4630
  for (const group of Object.values(state.debtGroups)) {
4619
- if (group.quiescent || group.bootId === null || group.bootId === bootId) continue;
4631
+ if (group.quiescent) continue;
4632
+ const priorBoot = bootId !== null && group.bootId !== null && group.bootId !== bootId;
4633
+ const outlivedWindow = group.sealed && at - group.at >= IDENTITY_UNCERTAIN_MAX_MS;
4634
+ if (!priorBoot && !outlivedWindow) continue;
4620
4635
  if (!makeDebtGroupQuiescent(state, group, at)) {
4621
4636
  return { ok: false, reason: "accounting-overflow" };
4622
4637
  }
@@ -15633,6 +15648,8 @@ const RECOVERY_COPY = Object.freeze({
15633
15648
  "probe-failed": ["GitHub budget check failed", "Retry automatically at the shown time", "Budget check; retry"],
15634
15649
  "block-unpublished": ["Saving GitHub request limit", "Retry sharing the hold automatically", "Saving hold; retry"],
15635
15650
  "budget-reset": ["GitHub quota pacing", "Retry automatically after reset", "Quota; retry"],
15651
+ reset: ["GitHub quota pacing", "Retry automatically after reset", "Quota; retry"],
15652
+ priority: ["Background refresh waiting its turn", "Retry automatically at the next slot", "Queued; retry"],
15636
15653
  "rate-limit": ["GitHub quota pacing", "Retry automatically after reset", "Quota; retry"],
15637
15654
  "rate-limited": ["GitHub request limit", "Retry automatically after the shared hold", "Limit; retry"],
15638
15655
  "local-reserve": ["Local quota reserve pacing", "Retry automatically at the next grant", "Reserve; retry"],
@@ -20338,6 +20355,8 @@ export {
20338
20355
  GOVERNOR_PHASE_WINDOW_MS,
20339
20356
  BUDGET_PROBE_MS,
20340
20357
  MIN_SAMPLE_CALLS,
20358
+ MAX_PACING_EXTERNAL_FACTOR,
20359
+ IDENTITY_UNCERTAIN_MAX_MS,
20341
20360
  REQUEST_PRIORITIES,
20342
20361
  normalizeBudgetResource,
20343
20362
  budgetEpoch,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gh-glance",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "description": "A live-refreshing GitHub dashboard for your terminal: Actions, Issues, Pull Requests, and Security alerts in one narrow pane",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,16 +14,20 @@
14
14
  "LICENSE"
15
15
  ],
16
16
  "scripts": {
17
- "lint": "eslint . --max-warnings 0",
17
+ "lint": "eslint --max-warnings 0 index.mjs eslint.config.js scripts test",
18
18
  "prepare": "node -e \"process.exit(require('fs').existsSync('.git')?0:1)\" && husky || true",
19
19
  "prepublishOnly": "npm run lint && node --check index.mjs && npm test",
20
20
  "start": "node index.mjs",
21
21
  "test": "node --test --test-skip-pattern='E2E-' test/*.test.mjs",
22
+ "test:fast": "node scripts/test-select.mjs run fast",
23
+ "test:recovery": "node scripts/test-select.mjs run recovery",
24
+ "test:package": "node scripts/test-select.mjs run package",
22
25
  "test:coverage": "node --test --test-concurrency=1 --test-skip-pattern='E2E-' --experimental-test-coverage --test-coverage-include=index.mjs test/*.test.mjs",
23
26
  "test:coverage:runtime": "node test/runtime-coverage.mjs",
24
- "test:efficiency": "node --test test/efficiency.test.mjs",
27
+ "test:efficiency": "node scripts/test-select.mjs run efficiency",
25
28
  "measure:efficiency": "node scripts/measure-efficiency.mjs",
26
- "test:pty": "node --test --test-concurrency=1 --test-timeout=900000 test/pty/*.test.mjs"
29
+ "test:pty": "node scripts/test-select.mjs run pty",
30
+ "test:pty:smoke": "node scripts/test-select.mjs run pty:smoke"
27
31
  },
28
32
  "keywords": [
29
33
  "github",