gh-glance 0.10.0 → 0.11.0

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 (4) hide show
  1. package/CHANGELOG.md +58 -15
  2. package/README.md +31 -20
  3. package/index.mjs +1207 -240
  4. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,27 +7,68 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.0] - 2026-08-30
11
+
12
+ ### Fixed
13
+
14
+ - **Manual refresh now owns exactly one fresh Actions batch.** It replaces the
15
+ due active-poll deadline, queues once when an automatic batch is already in
16
+ flight, and coalesces repeated `r` presses while that forced batch runs. This
17
+ prevents both a lost manual refresh and an immediate duplicate automatic
18
+ request.
19
+ - **Reset recovery no longer strands a pane that lost shared probe ownership.**
20
+ When the winning pane publishes between a waiter's bounded inspection and
21
+ its final snapshot, the waiter now adopts that locked, fresh, claim-free
22
+ publication instead of sleeping until the next control interval. A data wake
23
+ that saw the old held epoch can no longer leave its active tab on that stale
24
+ deadline after the new safe epoch is published.
25
+
26
+ ### Changed
27
+
28
+ - **The shared governor now follows authoritative response counters.** Core
29
+ observations come from conditional endpoint headers and one shared `/user`
30
+ observer. The free `rate_limit` GraphQL counter is now documented as a known
31
+ open-loop input, not as an authority: live GraphQL response headers can move
32
+ while that endpoint remains unchanged.
33
+ Response accounting and reservation settlement now commit atomically, so
34
+ concurrent panes cannot double-charge, move an owner-established epoch, or
35
+ overwrite a newer budget sample.
36
+ - **Unchanged Actions and Security checks no longer consume REST quota.** The
37
+ dashboard now revalidates each REST endpoint with its cached ETag, while a
38
+ manual refresh still requests fresh data and new Actions runs still appear.
39
+ - **The footer stays calm while checks follow their safe schedule.** Scheduler
40
+ holds now remain Watching, grant and reset details use coarse relative
41
+ minutes, and a wait caused only by other local panes says `sharing N`.
42
+ Detail or stale text stays inside a fixed state region so key hints do not
43
+ move. Staleness also follows each tab's admitted request cadence.
44
+ - **GraphQL tolerates one unusable minute sample without a false hold.** Its
45
+ available observation remains probe-owned and fails closed after two missed
46
+ samples, but freshness does not make that counter accurate. The
47
+ response-header-backed core resource keeps its shorter freshness limit.
48
+
10
49
  ## [0.10.0] - 2026-08-19
11
50
 
12
51
  ### Fixed
13
52
 
14
- - **Concurrent panes preserve a hard reserve instead of slowing all the way to
15
- exhaustion.** Local panes on one GitHub host and account now share atomic
53
+ - **Concurrent panes preserve a core hard reserve instead of slowing all the way
54
+ to exhaustion.** Local panes on one GitHub host and account now share atomic
16
55
  grants, worst-case reservations, and one budget probe. gh-glance starts no
17
- request when its latest fresh, conservatively debited REST or GraphQL sample
18
- cannot pay for it outside the final 20% of that resource. Missing, corrupt,
19
- locked, or unwritable coordination fails closed. REST exhaustion does not
20
- stop healthy GraphQL tabs, and manual refresh cannot bypass the hold.
56
+ core request when its latest fresh, conservatively debited authoritative
57
+ sample cannot pay for it outside the final 20%. GraphQL work is locally paced
58
+ from its declared cost and the available `rate_limit` sample, but that sample
59
+ is not authoritative. Missing, corrupt, locked, or unwritable coordination
60
+ fails closed. REST exhaustion does not stop a GraphQL tab that its current
61
+ probe permits, and manual refresh cannot bypass the hold.
21
62
 
22
63
  ### Changed
23
64
 
24
65
  - **Startup, reset, polling, and status now reflect the shared safe schedule.**
25
66
  Stable pane phases spread startup and post-reset work, active checks precede
26
67
  one rotating background check, and the old 60-second pacing ceiling is gone.
27
- The active footer says Watching, Checking, Waiting, Paused, Failed, or Limited.
28
- Startup and manual Checking animate while admitted; adapted automatic checks
29
- and non-working states stay static. `next HH:MM` names one current grant, not
30
- a recurring interval.
68
+ The active footer reports an explicit semantic state. Startup and manual
69
+ Checking animate while admitted; adapted automatic checks and non-working
70
+ states stay static. The next-grant detail names one current grant, not a
71
+ recurring interval.
31
72
 
32
73
  ## [0.9.1] - 2026-08-11
33
74
 
@@ -47,10 +88,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
47
88
  open alerts fill the base page, then merge and de-duplicate the result. A `+`
48
89
  marker stays explicit when any lane fills; the app never claims an unbounded
49
90
  repository is complete.
50
- - **Adaptive polling now protects both GitHub budgets.** REST and GraphQL spend
51
- are measured separately, including failed calls, and the safer interval wins
52
- without lowering the configured refresh floor. `--doctor` reports the same
53
- conservative model.
91
+ - **Adaptive polling models both GitHub budgets separately.** Declared REST and
92
+ GraphQL costs, including failed calls, feed the safer interval without
93
+ lowering the configured refresh floor. `--doctor` reports the same model.
94
+ Later validation established that only REST now has an authoritative
95
+ response-counter feedback loop.
54
96
  - **Terminal state has explicit non-colour and linear-rendering channels.** A
55
97
  stable ASCII `x` marks fetch failure, selected rows include `selected` in
56
98
  their accessibility label, narrow errors begin with the recovery action, and
@@ -734,7 +776,8 @@ engineering, security, QA and UX. What follows is what changed as a result.
734
776
  - The `main` field from `package.json`. It advertised the file as importable,
735
777
  but importing it took over the terminal or exited the host process.
736
778
 
737
- [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.10.0...HEAD
779
+ [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.11.0...HEAD
780
+ [0.11.0]: https://github.com/juan294/gh-glance/compare/v0.10.0...v0.11.0
738
781
  [0.10.0]: https://github.com/juan294/gh-glance/compare/v0.9.1...v0.10.0
739
782
  [0.9.1]: https://github.com/juan294/gh-glance/compare/v0.9.0...v0.9.1
740
783
  [0.9.0]: https://github.com/juan294/gh-glance/compare/v0.8.0...v0.9.0
package/README.md CHANGED
@@ -25,14 +25,14 @@ without switching to the browser.
25
25
  ╭─ Actions · owner/repo ──────────────────────────────────────────────────╮
26
26
  │ TITLE │WORKFLOW │BRANCH │TIME │UPDATED │
27
27
  │ ─────────────────────────────────────────────────────────────────────── │
28
- │ >+ ci: pin actions to com… #443 CI develop 1m20s 17d ago │
29
- │ x fix: restore the prima… #442 Code… develop 1m28s 17d ago │
30
- │ + chore: bump dependenci… #441 CI dependa…int-10 30s 18d ago │
31
- │ - docs: update the readme #440 CI develop 15s 18d ago │
28
+ │ >+ ci: pin actions to com… #443 CI develop 1m20s 28d ago │
29
+ │ x fix: restore the prima… #442 Code… develop 1m28s 28d ago │
30
+ │ + chore: bump dependenci… #441 CI dependa…int-10 30s 28d ago │
31
+ │ - docs: update the readme #440 CI develop 15s 29d ago │
32
32
  │ │
33
33
  │ │
34
34
  ╰──────────────────────────────────────────────────────────────── 4 of 4 ─╯
35
- · Watching Refresh: r Quit: q Move: ↑↓ Open: Ent Width: w 0.10.0
35
+ · Watching Refresh: r Quit: q Move: ↑↓ Open: Ent Width: w
36
36
  ```
37
37
 
38
38
  > Generated from this candidate's real binary under the repository PTY harness
@@ -83,12 +83,12 @@ current.
83
83
  mode, and preferences kept separately for each tab
84
84
  - `lazygit`-style panel frame: the tab name sits in the top border, the
85
85
  visible-of-total row count in the bottom
86
- - A semantic footer for the active tab: **Watching** is settled; **Checking**
87
- means admitted work is live; **Waiting** means a probe or future grant;
88
- **Paused** protects a held or unavailable budget; **Failed** names a normal
89
- fetch error; and **Limited** means Security visibility is incomplete. Startup
90
- and manual Checking can animate. Adapted automatic checks, Waiting, Paused,
91
- Failed, Limited, and Watching are static
86
+ - A semantic footer for the active tab: **Watching** is settled or scheduled;
87
+ **Checking** means admitted work is live; **Paused** protects a held or
88
+ unavailable budget; **Failed** names a normal fetch error; and **Limited**
89
+ means Security visibility is incomplete. Startup and manual Checking can
90
+ animate. Adapted automatic checks, Watching, Paused, Failed, and Limited are
91
+ static. A pure shared-lane wait adds `sharing N` without moving the key hints
92
92
  - Row state icons are real GitHub Octicons (via the Nerd Font glyph set), not emoji
93
93
  -- with a plain-ASCII fallback for terminals without one
94
94
  - Readable without colour: severity has its own column, a failing newest run puts
@@ -335,7 +335,7 @@ Environment variables work too, and the flags take precedence:
335
335
  | `GH_GLANCE_REFRESH=<seconds>` | Minimum active-tab poll interval, 2-3600. Sets the floor for every pane in a shell; `--refresh` takes precedence. See [Rate limit](#rate-limit). |
336
336
  | `GH_GLANCE_ICONS=unicode` | Unicode status glyphs and single-cell text substitutes for Nerd Font row icons |
337
337
  | `GH_GLANCE_ICONS=ascii` | ASCII-only status and row icons |
338
- | `GH_GLANCE_NO_ANIMATION=1` | Stop status and run-state motion. Semantic words such as Checking, Waiting, and Paused still report what is happening. |
338
+ | `GH_GLANCE_NO_ANIMATION=1` | Stop status and run-state motion. Semantic words such as Watching, Checking, and Paused still report what is happening. |
339
339
  | `NO_COLOR=1` | Disable colour. Status stays readable: severity has its own column, a failing newest run puts a `!` on the Actions tab, and the active tab is bracketed. Note that run-state glyphs are not all distinct -- see the feature list above |
340
340
  | `INK_SCREEN_READER=true` | Switch the renderer to a linear, unthrottled mode. Automated PTY coverage checks that status and selection labels reach this Ink path, but it has not been validated with real assistive technology — treat it as automated rendering coverage, not claimed screen-reader support. |
341
341
 
@@ -534,7 +534,7 @@ either: one `gh run list` issues two REST requests. `gh-glance --doctor` reports
534
534
  this projection beside the server's actual REST and GraphQL budgets. Enterprise
535
535
  ceilings can differ from 5,000.
536
536
 
537
- For each resource, gh-glance reserves 20% of the reported limit for other work:
537
+ For each resource, gh-glance calculates 20% of the reported limit for other work:
538
538
 
539
539
  ```text
540
540
  reserve = ceil(limit * 0.2)
@@ -543,16 +543,24 @@ spendable = max(0, remaining - reserve - charged reservations)
543
543
 
544
544
  That is 1,000 calls for a normal 5,000-call resource. Before any quota-consuming
545
545
  `gh` process starts, its declared worst-case REST/GraphQL cost must fit inside
546
- the latest fresh observation without entering the reserve. A grant is charged
547
- immediately, then reconciled only when completion evidence proves a lower cost.
546
+ the latest fresh local observation without entering the calculated reserve. A
547
+ grant is charged immediately, then reconciled only when completion evidence
548
+ proves a lower cost.
548
549
  Started, interrupted, or process-lost work stays conservative until a later
549
550
  clean probe can account for it. Missing, stale, corrupt, locked, or unwritable
550
551
  coordination denies the call instead of returning to five-second polling.
551
552
 
553
+ Core observations come from real response headers, so the core reserve has a
554
+ closed feedback loop. GraphQL is currently weaker: `gh issue` and `gh pr` do
555
+ not expose response headers in their normal output, and the free `rate_limit`
556
+ endpoint can remain unchanged while real GraphQL use rises. gh-glance therefore
557
+ paces its declared local GraphQL work and fails closed on a missing or stale
558
+ probe, but it cannot yet prove the account-wide GraphQL reserve.
559
+
552
560
  One pane owns the free `rate_limit` probe for a control window and publishes it
553
561
  for the others. Manual and diagnostic work is considered before tab-switch,
554
562
  active, and background work; equal-priority panes rotate fairly. Manual `r`
555
- coalesces repeated presses, gives immediate Waiting or Paused feedback, and
563
+ coalesces repeated presses, gives immediate Watching or Paused feedback, and
556
564
  clears an endpoint backoff only after admission. It cannot bypass a held budget
557
565
  or force a request into the reserve.
558
566
 
@@ -560,8 +568,10 @@ The shared lane uses spendable capacity, time to reset, outstanding
560
568
  reservations, and observed external spend. Startup and each new reset epoch add
561
569
  a stable per-pane phase, so panes do not resume as a herd. There is no
562
570
  60-second maximum: if the next safe slot is farther away, the pane waits that
563
- long. `next HH:MM` is the time of one current grant, not a promise of a recurring
564
- poll at that time or interval.
571
+ long. `next 2m` is the coarse time until one current grant, not a promise of a
572
+ recurring polling interval. When another live local pane alone owns the lane
573
+ ahead of this pane, the detail says `sharing N` instead. The detail is capped
574
+ at `99m+`.
565
575
 
566
576
  When a refresh fails, the last successful rows stay visible below the live
567
577
  error instead of disappearing. If gh-glance is restarted while GitHub is still
@@ -673,10 +683,11 @@ GH_GLANCE_ICONS=ascii gh-glance
673
683
  | Tabs start failing after working for a while | The enterprise SAML session lapsed. Re-authorize in the browser; the dashboard recovers within about 30 seconds. Run `gh-glance --doctor` to confirm. |
674
684
  | A tab's count is red | That tab's last fetch failed. The error itself is shown when you switch to it, translated into what to do about it where `gh-glance` recognises the failure. |
675
685
  | Security tab shows `?` instead of a number | The alert endpoints could not be read at all -- an expired SAML session, a token without `security_events`, or an org OAuth restriction. `?` means "unknown", not "zero"; run `gh-glance --doctor` to see which probe failed and how it was classified. |
676
- | `Waiting` or `next HH:MM` | The active tab is waiting for a shared budget probe or for its current safe grant. The time names this grant only; it is not a recurring polling interval. Pressing `r` raises safe priority but cannot bypass the lane or reserve. |
686
+ | `Watching` with `next 2m` | The active tab has a shared budget probe or safe grant scheduled. The interval names this grant only; it is not a recurring polling interval. Pressing `r` raises safe priority but cannot bypass the lane or reserve. |
687
+ | `Watching` with `sharing 4` | Four local panes share this account governor, and another pane owns the lane immediately ahead of this grant. This is pacing, not quota scarcity. |
677
688
  | `Paused` with a reset time | The active tab's REST or GraphQL resource is at its reserve, exhausted, or under a shared rate-limit block. Wait for the stated reset/probe. Other tabs can continue when they use the healthy resource. |
678
689
  | `Paused` without a reset time | Budget or coordinator evidence is unknown, corrupt, locked, or unwritable. No data call is started. Run `gh-glance --doctor`; also check the config directory permissions and whether another live process owns its private lock. |
679
- | A failing tab seems to have stopped retrying | Recognized endpoint failures back off rather than re-spawning `gh` at the floor. Press `r` to request a higher-priority retry; the backoff clears only after a safe grant, so a held budget remains Waiting or Paused. |
690
+ | A failing tab seems to have stopped retrying | Recognized endpoint failures back off rather than re-spawning `gh` at the floor. Press `r` to request a higher-priority retry; the backoff clears only after a safe grant, so the tab remains Watching or Paused. |
680
691
  | `unknown argument: -v` | `-v` used to mean `--version` and no longer does, because this CLI also has `--verbose`. Use `--version` or `--verbose` explicitly. |
681
692
  | Cached rows plus `Paused` and `stale 2m` | The rows came from the separate last-known-good dashboard cache, while the live request is blocked or unsafe. Stale age is not extended by a pause. The error and footer describe current coordination; cached data never means the live check succeeded. |
682
693
  | Repeated GitHub rate-limit messages | A classified rate-limit response is published as one shared resource block. Local panes make no data retry before that block's probe/reset deadline. Use `--doctor` to inspect the resource and reset; repeated manual refresh cannot override it. |