gh-glance 0.13.3 → 0.14.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 (4) hide show
  1. package/CHANGELOG.md +100 -1
  2. package/README.md +46 -18
  3. package/index.mjs +963 -274
  4. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,103 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.14.1] - 2026-09-08
11
+
12
+ ### Fixed
13
+
14
+ - **A folder with no git remote opens in setup, not in a coordination wait.**
15
+ The onboarding prompt (`No GitHub remote found -- press Enter to create one`)
16
+ was only ever produced from a `gh` error, and with no remote there is no host
17
+ to verify an identity against, so no `gh` command ever ran: the dashboard sat
18
+ on "Can't coordinate API use -- retrying" and "waiting for API budget…" for a
19
+ repository that did not exist. The target is now decided before any
20
+ coordination -- no remote, no `--repo`, no `GH_REPO` means setup -- and
21
+ `--doctor` says so in the same words instead of reporting an unavailable
22
+ identity.
23
+ - **An upgrade no longer stalls on a ledger that never recorded a budget for a
24
+ resource it charged.** A 0.12-era file whose panes only ever observed GraphQL
25
+ holds core reservations with no core budget to date them by, so the migration
26
+ reported "older spend cannot be settled or waited out" -- a hold with no
27
+ deadline, on every launch, forever. Each reservation records the epoch it was
28
+ admitted against; that epoch's reset now serves as the deadline, and a window
29
+ that ended weeks ago clears at once.
30
+
31
+ ## [0.14.0] - 2026-09-07
32
+
33
+ ### Added
34
+
35
+ - **`--background all|off`.** `off` never requests data for a tab you are not
36
+ looking at. Its tab-bar count keeps the last known value and ages visibly, and
37
+ switching to the tab fetches it. `--doctor` reports the setting alongside the
38
+ projected demand it changes.
39
+ - **`R` resynchronizes the current tab.** One generation without cached
40
+ validators, and the only key that clears a negative capability backoff -- so
41
+ an endpoint that answered "not enabled" can be re-asked on demand. Still
42
+ subject to the budget and the secondary cooldown.
43
+
44
+ ### Changed
45
+
46
+ - **The refresh floor is a floor, not a frequency.** A tab whose content is
47
+ unchanged twice in a row slows to 30 seconds (60 for Security), Actions with a
48
+ running or queued job is checked every 5, and an inactive tab is considered
49
+ every `max(12 x floor, 120s)` -- 300s for Security. An error or an unreadable
50
+ payload never counts as an unchanged observation, so a tab that cannot be read
51
+ is never slowed down for looking quiet. The one shared active floor and
52
+ rotating four-floor background slot could not express any of that, and only
53
+ Security ever slowed at all -- after a single unchanged poll, on a rule that
54
+ applied to nothing else.
55
+ - **`r` sends cached validators instead of throwing them away.** It remains a
56
+ prioritized refresh that bypasses the scheduled deadline and the tab's failure
57
+ ladder, but an unchanged tab now answers `304` and spends nothing -- the case
58
+ where the key is most likely to be pressed. Dropping validators is `R`. A
59
+ press arriving while automatic work that predates it is running schedules
60
+ exactly one follow-up rather than being lost, and further presses coalesce
61
+ into it.
62
+ - **Actions asks for one request, not two.** The runs list carries each run's
63
+ workflow name, so the workflow catalog became a conditional fallback for runs
64
+ that have none, cached for 15 minutes and separately admitted. The request is
65
+ also a stable 60-row variant rather than one derived from the pane's height,
66
+ so two differently sized panes ask the same question and can reuse each
67
+ other's validators. A catalog that cannot be read leaves the run list intact
68
+ with a missing or last-known name rather than blocking CI status.
69
+ - **Issues and Pull Requests load one 50-row page and page on demand.** The
70
+ first paint used to walk to 150 rows -- three requests for a pane showing
71
+ about twenty. Scrolling within ten rows of the end acquires exactly one more
72
+ page, capped at 150 rows, and repeated scrolling coalesces into a single
73
+ request. Rows carry truthful `totalCount`/`hasNextPage` markers, duplicates
74
+ across pages are removed, and a page from a traversal whose first page changed
75
+ underneath it is rejected rather than joined onto the new one.
76
+ - **`--doctor` reports a projected demand range.** The old line printed one
77
+ fixed figure as "this config spends", which read as a measurement; the cadence
78
+ now depends on what the repository is doing, so the report gives the range and
79
+ labels it a projection. Actual charges remain in the API governor section.
80
+
81
+ ### Fixed
82
+
83
+ - **A separately admitted request was refused every single time.** Any second
84
+ request inside one tab fetch -- a later list page, the workflow catalog --
85
+ asks a moment after the tab's own grant advanced the shared lane, so the
86
+ governor answered with a slot a fraction of a second away. That answer was
87
+ treated as a refusal, which meant paged lists never paged and workflow names
88
+ never arrived. A named slot within a two-second bound is now waited out and
89
+ revalidated; a longer gap still declines, and a slot the request decides not
90
+ to take is released rather than left reserved against the budget.
91
+ - **Scrolling toward the end of a list re-fetched the same page.** The demanded
92
+ page count was computed and stored, then dropped by the Issues and Pull
93
+ requests tab definitions one call short of the fetcher, so a longer list could
94
+ never be paged into at all.
95
+ - **A refresh keypress arriving during a fetch was replayed as the stronger
96
+ key.** The queued handoff always resynchronized, so `r` dropped its validators
97
+ whenever it happened to land while an automatic poll was in flight. The queue
98
+ now carries which key was pressed.
99
+ - **A pane running an older build no longer makes the shared ledger
100
+ unreadable.** A pending request records exactly what its tab costs, so
101
+ changing that cost made every file written by a still-running older pane read
102
+ as corrupt -- discarding the leases and unsettled spend the restart boundary
103
+ depends on. Such a file is now recognized as older and adapted: its
104
+ differently priced pending requests are dropped, and every lease, budget and
105
+ unsettled charge is kept.
106
+
10
107
  ## [0.13.3] - 2026-09-07
11
108
 
12
109
  ### Changed
@@ -953,7 +1050,9 @@ engineering, security, QA and UX. What follows is what changed as a result.
953
1050
  - The `main` field from `package.json`. It advertised the file as importable,
954
1051
  but importing it took over the terminal or exited the host process.
955
1052
 
956
- [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.13.3...HEAD
1053
+ [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.14.1...HEAD
1054
+ [0.14.1]: https://github.com/juan294/gh-glance/compare/v0.14.0...v0.14.1
1055
+ [0.14.0]: https://github.com/juan294/gh-glance/compare/v0.13.3...v0.14.0
957
1056
  [0.13.3]: https://github.com/juan294/gh-glance/compare/v0.13.2...v0.13.3
958
1057
  [0.13.2]: https://github.com/juan294/gh-glance/compare/v0.13.1...v0.13.2
959
1058
  [0.13.1]: https://github.com/juan294/gh-glance/compare/v0.13.0...v0.13.1
package/README.md CHANGED
@@ -247,7 +247,8 @@ stdout isn't a terminal rather than streaming redraw frames into a pipe.
247
247
  | `↑` / `↓` or `j` / `k` | Move the cursor between rows |
248
248
  | `PgUp` / `PgDn` | Move a page at a time |
249
249
  | `Enter` | Open the selected item, or accept an onboarding prompt |
250
- | `r` | Request a current-tab refresh; a safe grant is still required. |
250
+ | `r` | Request a current-tab refresh. It sends the cached validators, so an unchanged tab answers `304` and spends nothing. A safe grant is still required. |
251
+ | `R` | Resynchronize the current tab: one generation without validators, and the only key that clears a negative capability backoff. Still subject to the budget and the secondary cooldown. |
251
252
  | `w` | Adjust table column widths |
252
253
  | `?` | Show the keys without leaving the dashboard (any key closes it) |
253
254
  | `q` / `Esc` / `Ctrl+C` | Quit (`Esc` leaves width mode) |
@@ -317,8 +318,9 @@ pane definition. Flags are there when you want them:
317
318
  | Flag | Effect |
318
319
  |---|---|
319
320
  | `-R`, `--repo [host/]owner/name` | Watch a specific repository instead of the current directory's. Works from anywhere -- you do not need a local clone. The optional host targets a GitHub Enterprise or EMU data-residency tenant, e.g. `tenant.ghe.com/acme/widget`. |
320
- | `--refresh <seconds>` | Minimum active-tab poll interval, 2-3600, default 5. Safe shared grants can make a check later; each background tab is considered about every 12 floors. |
321
+ | `--refresh <seconds>` | Minimum active-tab poll interval, 2-3600, default 5. A floor, never a ceiling: a tab whose content is unchanged twice in a row slows to 30 seconds (60 for Security), and Actions with a running or queued job is checked every 5. Safe shared grants can make any check later. |
321
322
  | `--tab <name>` | Start on `actions`, `issues`, `prs` or `security`. |
323
+ | `--background <mode>` | `all` (default) or `off`. `off` never requests data for a tab you are not looking at. Its count keeps the last known value and ages visibly, and switching to the tab fetches it. |
322
324
  | `--verbose` | Log one line per dashboard `gh` call to stderr, with timing and outcome. Credential lookup and the account-identity proof are deliberately excluded, so that they cannot log anything derived from a token. stderr must be redirected: `gh-glance --verbose 2>gh-glance.log`. |
323
325
  | `--doctor` | Print a diagnostic report and exit. See [Diagnostics](#diagnostics). |
324
326
 
@@ -528,9 +530,23 @@ printed if `gh-glance` crashes.
528
530
  The default five seconds is a healthy single-pane floor, not an unconditional
529
531
  request frequency. Each check first needs an atomic grant from the private
530
532
  governor shared by local panes using the same effective host and account
531
- namespace. The active tab is considered at its floor. One rotating inactive tab
532
- is considered every four floors, so each of the three background tabs is
533
- considered about every 12 floors without starting them together.
533
+ namespace. Beyond that floor, the cadence follows what the repository is
534
+ actually doing:
535
+
536
+ | State | Earliest normal check |
537
+ |---|---|
538
+ | New subscription, or active data that just changed | Immediately once, then the floor |
539
+ | Actions with a running or queued run | `max(floor, 5s)` |
540
+ | Active Actions, Issues or Pull Requests unchanged twice | `max(floor, 30s)` |
541
+ | Active Security unchanged twice | `max(floor, 60s)` |
542
+ | Inactive Actions, Issues or Pull Requests | `max(12 x floor, 120s)` |
543
+ | Inactive Security | `max(12 x floor, 300s)` |
544
+ | `--background off`, any inactive tab | Never |
545
+
546
+ Two unchanged observations are required, not one, and an error or an unreadable
547
+ payload never counts as one: a tab that cannot be read is not a quiet tab. One
548
+ inactive tab is considered per wake, in rotation, so three of them falling due
549
+ together do not start together.
534
550
 
535
551
  The resources are independent. Actions and Security spend REST `core` calls;
536
552
  Issues and Pull Requests are sorted with `--search`, which routes them through
@@ -540,9 +556,14 @@ floor:
540
556
 
541
557
  | Visible tab | REST / hour | GraphQL / hour |
542
558
  |---|---|---|
543
- | Actions | up to ~1,800 | ~240 |
544
- | Issues or Pull Requests | up to ~480 | ~1,560 |
545
- | Security | ~2,280 normally; up to ~4,440 | ~240 |
559
+ | Actions | ~192 quiet, up to ~792 | ~120 |
560
+ | Issues or Pull Requests | ~102 | ~300 quiet, up to ~1,500 |
561
+ | Security | ~390 quiet, up to ~4,350 | ~120 |
562
+
563
+ The lower figure in each range is every tab at its quiet cadence; the upper is
564
+ the active tab at its floor with Actions busy. `--doctor` prints the same range
565
+ for the configuration you actually run, labelled `projected demand` to keep it
566
+ distinct from the charges the governor section reports.
546
567
 
547
568
  Security is the most expensive. A repository whose newest alert pages are not
548
569
  full uses the three base endpoint calls and lands near 2,280 REST requests per
@@ -577,10 +598,11 @@ probe, but it cannot yet prove the account-wide GraphQL reserve.
577
598
 
578
599
  One pane owns the free `rate_limit` probe for a control window and publishes it
579
600
  for the others. Manual and diagnostic work is considered before tab-switch,
580
- active, and background work; equal-priority panes rotate fairly. Manual `r`
581
- coalesces repeated presses, gives immediate Watching or Paused feedback, and
582
- clears an endpoint backoff only after admission. It cannot bypass a held budget
583
- or force a request into the reserve.
601
+ active, and background work; equal-priority panes rotate fairly. Both refresh
602
+ keys coalesce repeated presses -- a press during work that predates it schedules
603
+ exactly one follow-up -- and give immediate Watching or Paused feedback. Only
604
+ `R` clears validators and an endpoint backoff, and only after admission. Neither
605
+ can bypass a held budget or force a request into the reserve.
584
606
 
585
607
  The shared lane uses spendable capacity, time to reset, outstanding
586
608
  reservations, and observed external spend. Startup and each new reset epoch add
@@ -645,10 +667,16 @@ floor and shows Watching between checks.
645
667
  reporting only after `w` enters width mode, and disable it when that mode or
646
668
  the app exits. See [Adjusting column widths](#adjusting-column-widths) for
647
669
  text-selection behavior while it is active.
648
- - Issues and pull requests are fetched 150 at a time. Each Security source has
649
- a newest-100 lane; full Dependabot and code-scanning pages activate bounded
650
- priority lanes. A count is shown as `n+` when any lane fills, so the number is
651
- never presented as exact when it is not.
670
+ - Issues and pull requests are fetched 50 at a time, up to 150 rows. Scrolling
671
+ within ten rows of what is loaded acquires the next page; a tab nobody scrolls
672
+ never asks for one. Each Security source has a newest-100 lane; full
673
+ Dependabot and code-scanning pages activate bounded priority lanes. A count is
674
+ shown as `n+` when any lane fills, so the number is never presented as exact
675
+ when it is not.
676
+ - Actions asks for the newest 60 runs, whatever the pane's height. Each run
677
+ carries its own workflow name; when a run has none, the workflow catalog is
678
+ fetched once and reused for 15 minutes, and a catalog that cannot be read
679
+ leaves the run's other columns intact.
652
680
  - The Actions **TIME** column measures from the run's start to its last update.
653
681
  `gh` exposes no completion timestamp, so a workflow that was re-run later
654
682
  reports the span up to the re-run rather than its original duration.
@@ -690,7 +718,7 @@ GH_GLANCE_ICONS=ascii gh-glance
690
718
  | `the gh CLI is not installed` | Install it from [cli.github.com](https://cli.github.com), then `gh auth login`. |
691
719
  | `not inside a git repository` | Run it from a cloned GitHub repository, or set `GH_REPO=owner/name`. |
692
720
  | `No GitHub remote found` | Press `Enter` to start `gh repo create`, then choose **Push an existing local repository**. Or press `q` and run `gh-glance --repo owner/name` to watch an existing repository without attaching this folder. |
693
- | `GitHub login or authorization required` | Run `gh auth status`. With no account, run `gh auth login`; with an expired authorization, run `gh auth refresh`; then press `r`. |
721
+ | `GitHub login or authorization required` | Run `gh auth status`. With no account, run `gh auth login`; with an expired authorization, run `gh auth refresh`; then press `R`, which also clears the endpoint backoff the failures accrued. |
694
722
  | `Repository not found or inaccessible to the active gh account` | The active identity cannot resolve the target. Check `gh auth status`, `git remote -v` or the explicit `--repo`, and use `gh auth switch` only if the wrong account is active. |
695
723
  | `GraphQL: Could not resolve to a Repository...` in older gh-glance versions | The response has the same ambiguity: a missing or renamed target, or a private repository not visible to the active account. Run `gh-glance --doctor`. |
696
724
  | Actions says `not available for this repository` while Repository access is `ok` | The repository resolved, but that endpoint is unavailable; inspect the corresponding doctor block. |
@@ -705,7 +733,7 @@ GH_GLANCE_ICONS=ascii gh-glance
705
733
  | `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. |
706
734
  | `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. |
707
735
  | `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. |
708
- | 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. |
736
+ | 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, or `R` to also clear the endpoint backoff; either way the retry waits for a safe grant, so the tab remains Watching or Paused. |
709
737
  | `unknown argument: -v` | `-v` used to mean `--version` and no longer does, because this CLI also has `--verbose`. Use `--version` or `--verbose` explicitly. |
710
738
  | 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. |
711
739
  | 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. |