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 +41 -1
- package/README.md +11 -0
- package/index.mjs +22 -3
- package/package.json +8 -4
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.
|
|
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) /
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
27
|
+
"test:efficiency": "node scripts/test-select.mjs run efficiency",
|
|
25
28
|
"measure:efficiency": "node scripts/measure-efficiency.mjs",
|
|
26
|
-
"test:pty": "node
|
|
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",
|