gh-glance 0.11.1 → 0.12.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 +67 -1
  2. package/README.md +36 -13
  3. package/index.mjs +1592 -232
  4. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,6 +7,70 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.12.0] - 2026-09-06
11
+
12
+ ### Added
13
+
14
+ - **Panes sharing a GitHub account now share one API budget.** Quota is keyed by
15
+ the verified principal and access by the effective credential, so two tokens
16
+ for the same account coordinate as one instead of splitting the budget in
17
+ half. A shared transport permit serializes HTTP starts across panes, and the
18
+ bootstrap allowance is persisted before a request starts, so a crash, restart
19
+ or manual refresh cannot replenish it.
20
+
21
+ ### Changed
22
+
23
+ - **Issues and Pull Requests use explicit, bounded GraphQL documents.**
24
+ `gh issue list` and `gh pr list` silently routed through GraphQL at a price
25
+ nothing in the codebase could name -- the budget was debited from a number
26
+ measured by hand once and written into a constant. Both now use fixed,
27
+ versioned documents with typed variables on stdin, so the query never reaches
28
+ argv and every page declares the cost it is held to.
29
+ - **`gh api rate_limit` is no longer a source of spendable GraphQL capacity.**
30
+ A claimed observer that selects only the meter supplies capacity and reports
31
+ what it cost. `/rate_limit` remains a diagnostic, is labelled as one in
32
+ `--doctor`, and is dropped on migration rather than kept as spendable
33
+ evidence.
34
+ - **Opening a row spends no API budget.** `gh <kind> view --web` paid a request
35
+ to be told a URL the app already held, and had to refuse the user the page
36
+ when the budget was tight. URLs are admitted -- https only, matching host --
37
+ before reaching the platform opener.
38
+
39
+ ### Fixed
40
+
41
+ - **Issues and Pull Requests worked only with an explicit `--repo`.** `gh`
42
+ infers the repository from the working directory and GraphQL cannot, so the
43
+ query variables went out half-filled without it.
44
+ - **Multi-page repositories leaked a tab reservation on every poll.** Settlement
45
+ summed all page costs even though later pages settle against their own
46
+ reservation, and the resulting over-settlement was rejected as corrupt --
47
+ discarding the budget observations from the only requests carrying real cost
48
+ evidence.
49
+ - **The budget observer's own spend was attributed to external consumers**, so
50
+ the governor progressively throttled real work to make room for its own
51
+ probing.
52
+ - **A contended registry lock could retract a verified identity**, blanking
53
+ every tab and discarding the ETags that make the next round cheap. Unknown
54
+ and changed are now distinct, and only a proven change discards rows.
55
+ - **Bootstrap attempts that never proved a principal were never retired**, so
56
+ the registry filled to its cap behind a captive portal and refused every
57
+ later bootstrap permanently, recoverable only by deleting state by hand.
58
+ - **Identity debt transfer wrote the ledger and registry non-atomically**, so a
59
+ crash could orphan a charged receipt or record a debt as transferred to a
60
+ ledger that never received it.
61
+ - **A stopped pane held the single machine-wide HTTP permit indefinitely**, as
62
+ it was reclaimed only on owner death.
63
+ - **The Open key hint was dead on every tab**, and opening a cache-hydrated row
64
+ did nothing because the cache dropped the row's URL.
65
+
66
+ ## [0.11.2] - 2026-08-31
67
+
68
+ ### Fixed
69
+
70
+ - **Unchanged Security checks no longer turn a known count red.** A conditional
71
+ alert-source response with no staged ETag write now contributes an empty
72
+ cache update instead of failing with `part.stagedEntities is not iterable`.
73
+
10
74
  ## [0.11.1] - 2026-08-31
11
75
 
12
76
  ### Fixed
@@ -787,7 +851,9 @@ engineering, security, QA and UX. What follows is what changed as a result.
787
851
  - The `main` field from `package.json`. It advertised the file as importable,
788
852
  but importing it took over the terminal or exited the host process.
789
853
 
790
- [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.11.1...HEAD
854
+ [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.12.0...HEAD
855
+ [0.12.0]: https://github.com/juan294/gh-glance/compare/v0.11.2...v0.12.0
856
+ [0.11.2]: https://github.com/juan294/gh-glance/compare/v0.11.1...v0.11.2
791
857
  [0.11.1]: https://github.com/juan294/gh-glance/compare/v0.11.0...v0.11.1
792
858
  [0.11.0]: https://github.com/juan294/gh-glance/compare/v0.10.0...v0.11.0
793
859
  [0.10.0]: https://github.com/juan294/gh-glance/compare/v0.9.1...v0.10.0
package/README.md CHANGED
@@ -319,7 +319,7 @@ pane definition. Flags are there when you want them:
319
319
  | `-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
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
321
  | `--tab <name>` | Start on `actions`, `issues`, `prs` or `security`. |
322
- | `--verbose` | Log one line per `gh` call to stderr, with timing and outcome. stderr must be redirected: `gh-glance --verbose 2>gh-glance.log`. |
322
+ | `--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
323
  | `--doctor` | Print a diagnostic report and exit. See [Diagnostics](#diagnostics). |
324
324
 
325
325
  An unrecognised flag exits 2 rather than being ignored, so a typo fails loudly.
@@ -396,21 +396,39 @@ recovery state owned by the UI, not a configuration interface.
396
396
 
397
397
  ### Private API governor state
398
398
 
399
- API admission uses a separate file beside the cache:
399
+ API admission uses a separate directory beside the cache:
400
400
 
401
401
  ```text
402
- $XDG_CONFIG_HOME/gh-glance/rate-governor-v1-<scope hash>.json
403
- ~/Library/Application Support/gh-glance/rate-governor-v1-<scope hash>.json
404
- ~/.config/gh-glance/rate-governor-v1-<scope hash>.json
402
+ $XDG_CONFIG_HOME/gh-glance/coordination-v2/
403
+ ~/Library/Application Support/gh-glance/coordination-v2/
404
+ ~/.config/gh-glance/coordination-v2/
405
405
  ```
406
406
 
407
- The hash binds the effective GitHub host to the local `gh` account namespace
408
- without putting either raw value in the file name. The file records only the
409
- protocol needed to coordinate panes: REST and GraphQL budget observations and
410
- epochs, leases, intents, reservations, fair-lane cursors, probe ownership and
411
- outcomes, and temporary rate-limit blocks. It stores no token, raw host, login,
412
- repository, working directory, title, author, branch, alert, or other dashboard
413
- row. Ephemeral lock records contain only a PID and random nonce.
407
+ It holds `registry.json`, which maps credentials to verified accounts, and one
408
+ `quota-<hash>.json` ledger per account. The ledger hash binds the effective
409
+ GitHub host to the *verified principal* -- the account kind and numeric ID that
410
+ GitHub itself confirmed -- rather than to whichever local `gh` configuration
411
+ happened to select it, so two tokens for the same account coordinate as one
412
+ instead of splitting the budget in half.
413
+
414
+ A ledger records only the protocol needed to coordinate panes: REST and GraphQL
415
+ budget observations and epochs, leases, intents, reservations, fair-lane
416
+ cursors, probe ownership and outcomes, and temporary rate-limit blocks. It
417
+ stores no token, raw host, login, repository, working directory, title, author,
418
+ branch, alert, or other dashboard row.
419
+
420
+ `registry.json` is the one exception, and it is deliberate: to know that two
421
+ credentials are the same account it stores that account's numeric ID and its
422
+ sanitized login, alongside private digests of the credentials themselves. No
423
+ token is ever written, to it or anywhere else. Ephemeral lock records contain
424
+ only a PID and random nonce.
425
+
426
+ Panes from an older release coordinate through the previous
427
+ `rate-governor-v1-<scope hash>.json` files, which this version cannot join.
428
+ It preserves them as evidence, refuses to activate while any of their leases is
429
+ still live, and waits out any unsettled charge they left behind. Closing the
430
+ older panes is what completes the upgrade -- gh-glance will not close them for
431
+ you, and deleting the files instead discards quota that is still owed.
414
432
 
415
433
  This state has a stricter role than `dashboard-cache.json`. A missing cache can
416
434
  be ignored because it only supplies last-good rows. Missing governor state can
@@ -692,7 +710,12 @@ GH_GLANCE_ICONS=ascii gh-glance
692
710
  | 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. |
693
711
  | 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. |
694
712
  | It exits immediately when piped | Intentional. It is a full-screen dashboard, not a reporting command. |
695
- | It stopped updating and you cannot tell why | Run `gh-glance --verbose 2>gh-glance.log`, reproduce, then read the log: one line per `gh` call with its duration and outcome. It is redacted the same way `--doctor` is, so it is safe to attach to a bug report. `--doctor --verbose` logs the probes too. |
713
+ | `Restart required: close older gh-glance panes` | A pane from an older release still holds a live lease in the previous coordination format, which this version cannot join. Quit those panes; this one resumes on its own. Nothing is killed for you, and no state needs deleting. |
714
+ | `Upgrade waiting for legacy quota reset` | The older panes are gone, but left spend that cannot be proven settled. It waits for the affected rate-limit window to reset rather than assume the quota is free. |
715
+ | `Coordination state unavailable; evidence preserved` | Coordination state could not be read and was deliberately not overwritten, so nothing is lost. Run `gh-glance --doctor` and check the config directory's permissions. |
716
+ | `Shared HTTP request or cooldown in progress` | Panes share one outbound request slot and one cooldown. Another pane holds it, or a server-sent `Retry-After` is still running. Normal pacing, not an error. |
717
+ | `Verified identity unavailable; waiting to retry` | The account behind your credential has not been confirmed yet -- not signed in, a denied or malformed proof, or a slow credential helper. Check `gh auth status`. Retries are rate-limited, so this clears on its own rather than immediately. |
718
+ | It stopped updating and you cannot tell why | Run `gh-glance --verbose 2>gh-glance.log`, reproduce, then read the log: one line per dashboard `gh` call with its duration and outcome. Credential lookup and the identity proof are excluded by design. It is redacted the same way `--doctor` is, so it is safe to attach to a bug report. `--doctor --verbose` logs the probes too. |
696
719
  | `--verbose` refuses to start | stderr is still your terminal, where the log would draw over the dashboard. Redirect it to a file. |
697
720
 
698
721
  ## Contributing