gh-glance 0.8.0 → 0.9.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 +68 -1
  2. package/README.md +65 -51
  3. package/index.mjs +759 -186
  4. package/package.json +3 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,71 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.1] - 2026-08-11
11
+
12
+ ### Fixed
13
+
14
+ - **Package-boundary verification supports npm 12.** The release test accepts
15
+ both npm 11's array-shaped `npm pack --json` result and npm 12's
16
+ package-name-keyed result, so the existing OIDC publication workflow can
17
+ verify the CLI-only package boundary before publishing.
18
+
19
+ ## [0.9.0] - 2026-08-11
20
+
21
+ ### Added
22
+
23
+ - **Security keeps a bounded priority view when newest pages fill.** Dependabot
24
+ and code-scanning sources add critical/high lanes only when their newest 100
25
+ open alerts fill the base page, then merge and de-duplicate the result. A `+`
26
+ marker stays explicit when any lane fills; the app never claims an unbounded
27
+ repository is complete.
28
+ - **Adaptive polling now protects both GitHub budgets.** REST and GraphQL spend
29
+ are measured separately, including failed calls, and the safer interval wins
30
+ without lowering the configured refresh floor. `--doctor` reports the same
31
+ conservative model.
32
+ - **Terminal state has explicit non-colour and linear-rendering channels.** A
33
+ stable ASCII `x` marks fetch failure, selected rows include `selected` in
34
+ their accessibility label, narrow errors begin with the recovery action, and
35
+ short help always retains Quit, Refresh, and the full-help command.
36
+ - **PTY child-process coverage is available as an informational signal.**
37
+ `npm run test:coverage:runtime` summarizes observed `index.mjs` functions on
38
+ scheduled/manual coverage runs without adding a threshold or release gate.
39
+
40
+ ### Changed
41
+
42
+ - **Dashboard recovery state is account-scoped and safe across panes.** Cache
43
+ version 2 includes `GH_CONFIG_DIR`/`hosts.yml` identity and one-way digests of
44
+ supported token variables, rejects the old unscoped cache, and uses bounded
45
+ locked three-way merges so simultaneous panes preserve unrelated targets,
46
+ tabs, and width choices. Successful quiet polls checkpoint freshness on a
47
+ bounded cadence.
48
+ - **Settled automatic polling is visually quiet.** `Fetching` is reserved for
49
+ startup/manual work, unchanged Security observations slow to a 60-second
50
+ cadence, and cache-hydrated tabs clear their initial loading state.
51
+ - **Mouse reporting is opt-in through Width mode.** Press `w` before dragging a
52
+ header divider; outside that mode the terminal keeps ordinary mouse behavior.
53
+ - **The npm package is explicitly CLI-only.** The executable remains supported,
54
+ while package-root and deep JavaScript imports now fail through `exports: {}`.
55
+
56
+ ### Fixed
57
+
58
+ - **Manual Security refresh now clears every source backoff after the in-flight
59
+ guard admits the request.** Re-authenticating and pressing `r` cannot leave a
60
+ previously failed source silently asleep.
61
+ - **Concurrent persistence no longer loses a later update.** Same-target tabs
62
+ merge independently, and both cache and width writers adopt the merged disk
63
+ snapshot before their next save.
64
+ - **Selections stay attached to visible items as lists change.** Insertions
65
+ above a row reconcile the viewport without opening a different item; a missing
66
+ item clears selection instead of selecting a replacement.
67
+ - **Quitting aborts in-flight `gh ... view --web` children.** The app no longer
68
+ waits for a stalled browser-open command after terminal teardown begins.
69
+ - **Row failures reset only when row content changes.** Unchanged parent renders
70
+ no longer clear an error boundary, while corrected data can recover in place.
71
+ - **Status hints now describe only controls that can act.** Empty lists do not
72
+ advertise movement or opening, compact layouts do not advertise width mode,
73
+ and Security does not advertise an unsupported open action.
74
+
10
75
  ## [0.8.0] - 2026-08-11
11
76
 
12
77
  ### Added
@@ -647,7 +712,9 @@ engineering, security, QA and UX. What follows is what changed as a result.
647
712
  - The `main` field from `package.json`. It advertised the file as importable,
648
713
  but importing it took over the terminal or exited the host process.
649
714
 
650
- [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.8.0...HEAD
715
+ [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.9.1...HEAD
716
+ [0.9.1]: https://github.com/juan294/gh-glance/compare/v0.9.0...v0.9.1
717
+ [0.9.0]: https://github.com/juan294/gh-glance/compare/v0.8.0...v0.9.0
651
718
  [0.8.0]: https://github.com/juan294/gh-glance/compare/v0.7.0...v0.8.0
652
719
  [0.7.0]: https://github.com/juan294/gh-glance/compare/v0.6.1...v0.7.0
653
720
  [0.6.1]: https://github.com/juan294/gh-glance/releases/tag/v0.6.1
package/README.md CHANGED
@@ -30,19 +30,20 @@ without switching to the browser.
30
30
  │ │
31
31
  │ │
32
32
  ╰───────────────────────────────────────────────────────────────── 4 of 4 ─╯
33
- ⣾ Fetching Move: ↑↓ | Open: Ent | Refresh: r | Width: w | Quit: q 0.8.0
33
+ ⣾ Fetching Move: ↑↓ | Open: Ent | Refresh: r | Width: w | Quit: q 0.9.1
34
34
  ```
35
35
 
36
36
  > Captured from a real run at 76 columns with `GH_GLANCE_ICONS=unicode`, so the
37
37
  > status icons render in a browser. With a Nerd Font (the default) they are
38
38
  > Octicon glyphs instead.
39
39
  >
40
- > The `>` on the first row is the cursor. Three more markers appear when they
40
+ > The `>` on the first row is the cursor. Four more markers appear when they
41
41
  > apply: a `+` after a tab's count means the list was truncated by the fetch
42
42
  > limit, a `!` after the Actions count means the newest run failed — so "is CI
43
- > red" is answerable without switching to that tab — and a `?` in place of the
44
- > Security count means its endpoints could not be read, which is not the same
45
- > as there being nothing to report.
43
+ > red" is answerable without switching to that tab — an `x` means the tab's
44
+ > latest fetch failed, and a `?` in place of the Security count means its
45
+ > endpoints could not be read, which is not the same as there being nothing to
46
+ > report.
46
47
 
47
48
  <!-- contract:allow-emoji -- the check/cross above stand in for Nerd Font
48
49
  Octicons the app actually draws; they are literal examples, not decoration. -->
@@ -64,22 +65,23 @@ current.
64
65
  - **Issues** -- open issues: title, author, first label, age
65
66
  - **Pull Requests** -- open PRs: title, author, branch, review status
66
67
  (approved / changes requested / pending), age
67
- - **Security** -- open Dependabot alerts: package, summary, age, sorted with the
68
- most severe first and with severity spelled out in its own column, not carried
69
- by colour alone. One page of 100 newest alerts is fetched and ranked, so on a
70
- repository with more open alerts than that the ranking covers the newest 100
71
- rather than everything -- the `+` marker on the count is what tells you.
72
- Code scanning and secret scanning alerts are included too, on repos/plans
73
- that have GitHub Advanced Security enabled -- see [Limitations](#limitations).
68
+ - **Security** -- open Dependabot, code-scanning, and secret-scanning alerts,
69
+ sorted with the most severe first and with severity spelled out rather than
70
+ carried by colour alone. Each source starts with its newest 100 open alerts.
71
+ When that page is full, Dependabot and code scanning also fetch bounded
72
+ critical/high priority lanes before merging and de-duplicating the result.
73
+ The `+` marker means at least one bounded lane filled, so the visible priority
74
+ set may still be incomplete. Code and secret scanning require GitHub Advanced
75
+ Security -- see [Limitations](#limitations).
74
76
  - Tab bar with live counts, pinned to the top of the pane above a divider,
75
77
  switchable via `1`-`4`, arrow keys, or `Tab`/`Shift+Tab`
76
78
  - Adjustable full-table columns, with visible header grips, a keyboard width
77
79
  mode, and preferences kept separately for each tab
78
80
  - `lazygit`-style panel frame: the tab name sits in the top border, the
79
81
  visible-of-total row count in the bottom
80
- - A `Fetching` indicator that brightens on every refresh and animates during the
81
- first load or while a workflow run is executing, so the pane says when it's
82
- working without spending a line on it
82
+ - A `Fetching` indicator that brightens while a tab's first request is settling
83
+ or during a manual refresh. Settled automatic polls do not flash it; the
84
+ spinner still animates during first load or while a workflow run is executing
83
85
  - Status icons are real GitHub Octicons (via the Nerd Font glyph set), not emoji
84
86
  -- with a plain-ASCII fallback for terminals without one
85
87
  - Readable without colour: severity has its own column, a failing newest run puts
@@ -119,6 +121,10 @@ That is the whole install. `gh-glance` ships as a single `index.mjs` with no
119
121
  build step, so there is nothing to compile and nothing to configure -- the
120
122
  package is the source you can read in this repository.
121
123
 
124
+ The installed package is a CLI, not a JavaScript library. The `gh-glance`
125
+ executable is supported; package-root and deep imports are intentionally
126
+ blocked so an internal test seam cannot become an accidental public API.
127
+
122
128
  Every published version is built and signed by GitHub Actions from a tagged
123
129
  commit on `main`, never from a maintainer's laptop, and carries [npm
124
130
  provenance](https://docs.npmjs.com/generating-provenance-statements) linking
@@ -263,14 +269,15 @@ line such as:
263
269
  Width: BRANCH 14 Tab select <- -> resize r reset Esc done
264
270
  ```
265
271
 
266
- In an interactive terminal, you can also left-drag a visible `│` header grip.
267
- Pressing a grip selects its column and enters width mode; releasing the button,
268
- including outside the header, ends the drag. Row clicking, hover behavior, and
269
- pointer-shape changes are not supported. Mouse resizing has the same interactive
270
- terminal requirement as keyboard input.
272
+ After pressing `w`, you can also left-drag a visible `│` header grip. Mouse
273
+ reporting is enabled only while width mode owns the input, so a click outside
274
+ that mode does not enter it. Releasing the button, including outside the header,
275
+ ends the drag. Row clicking, hover behavior, and pointer-shape changes are not
276
+ supported.
271
277
 
272
- While gh-glance is running, terminal-native text selection may require your
273
- terminal's mouse-reporting bypass modifier, commonly `Shift`.
278
+ While width mode is active, terminal-native text selection may require your
279
+ terminal's mouse-reporting bypass modifier, commonly `Shift`. Outside width
280
+ mode, gh-glance leaves mouse reporting disabled.
274
281
 
275
282
  The cursor tracks the *item*, not the row position, so it stays on what you
276
283
  selected as new rows arrive above it. `Enter` works on Actions, Issues and Pull
@@ -316,12 +323,13 @@ Environment variables work too, and the flags take precedence:
316
323
  |---|---|
317
324
  | `GH_REPO=owner/name` | Watch a specific repository instead of the current directory's. A host-qualified `GH_REPO` does **not** route the security-alert endpoints -- use `GH_HOST` or `--repo host/owner/name` for that |
318
325
  | `GH_HOST=<host>` | Send every call to a GitHub Enterprise or EMU host instead of `github.com`. Routes both the list commands and the alert endpoints |
319
- | `GH_TOKEN`, `GH_ENTERPRISE_TOKEN`, `GH_CONFIG_DIR` | Not read by `gh-glance` -- passed through to `gh` untouched, along with the proxy variables. `gh-glance` handles no credentials of its own. Separate `GH_CONFIG_DIR` values can isolate simultaneous panes on different accounts; see [No account pinning](#limitations) |
326
+ | `GH_TOKEN`, `GITHUB_TOKEN`, `GH_ENTERPRISE_TOKEN`, `GITHUB_ENTERPRISE_TOKEN` | Used by `gh`. gh-glance never logs or stores these values, but hashes each set value locally as part of the account-scoped cache namespace so panes with different credentials cannot hydrate each other's rows. The raw values are not written to disk. |
327
+ | `GH_CONFIG_DIR` | Selects `gh`'s account configuration and contributes its normalized identity to the cache namespace. Separate values can isolate simultaneous panes on different accounts; see [No account pinning](#limitations). |
320
328
  | `GH_GLANCE_REFRESH=<seconds>` | Active-tab poll interval, 2-3600. Sets it once for every pane in a shell; `--refresh` takes precedence. This is a floor -- see [Rate limit](#rate-limit) |
321
329
  | `GH_GLANCE_ICONS=unicode` | Plain ASCII status icons, for terminals without a Nerd Font |
322
330
  | `GH_GLANCE_NO_ANIMATION=1` | Freeze the spinner — no motion at all |
323
331
  | `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 |
324
- | `INK_SCREEN_READER=true` | Switch the renderer to a linear, unthrottled mode. The status icons carry text labels for it, but this path has not been tested against a real screen reader — treat it as unverified rather than supported. |
332
+ | `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. |
325
333
 
326
334
  ### Saved column widths
327
335
 
@@ -358,11 +366,13 @@ $XDG_CONFIG_HOME/gh-glance/dashboard-cache.json
358
366
  ~/.config/gh-glance/dashboard-cache.json
359
367
  ```
360
368
 
361
- The cache is scoped to the repository and host being watched. In inferred mode,
362
- the host and current working directory form the identity, so rows from one
363
- checkout cannot appear in another. It retains at most five recent targets and
364
- 60 rows per tab; a shortened cached tab keeps its `+` marker rather than
365
- presenting the saved count as complete.
369
+ The cache is scoped to the repository, host, and effective `gh` account
370
+ namespace. In inferred mode, the host and current working directory also form
371
+ the identity, so rows from one checkout or credential context cannot appear in
372
+ another. The namespace uses `GH_CONFIG_DIR`/`hosts.yml` identity plus one-way
373
+ digests of supported token environment variables; raw credentials are never
374
+ stored. It retains at most five recent targets and 60 rows per tab; a shortened
375
+ cached tab keeps its `+` marker rather than presenting the saved count as exact.
366
376
 
367
377
  Only successfully parsed, non-blind observations replace saved rows. A failed
368
378
  request can add a live error or `?` marker, but it cannot turn known Security
@@ -371,7 +381,10 @@ unknown-version, or unwritable cache state is ignored rather than blocking the
371
381
  dashboard. On POSIX systems, gh-glance restricts its config directory to `0700`
372
382
  and the cache file to `0600`. The file contains repository data, including
373
383
  titles, authors, branches, and Security findings, but never GitHub credentials.
374
- It is recovery state owned by the UI, not a configuration interface.
384
+ Both persistence files use a bounded advisory lock before atomic replacement.
385
+ The cache merges independent targets and tabs, while preferences merge columns,
386
+ so simultaneous panes do not overwrite one another's unrelated state. It is
387
+ recovery state owned by the UI, not a configuration interface.
375
388
 
376
389
  ## GitHub Enterprise and EMU
377
390
 
@@ -416,9 +429,9 @@ Collects, in one plain-text block: the `gh-glance`, Node and `gh` versions;
416
429
  which hosts `gh` is authenticated for; how the repository target resolved and
417
430
  from where; your remaining REST and GraphQL budget plus what this configuration
418
431
  will spend per hour; the relevant environment variables; a read-only
419
- `Repository access` probe; and one probe per dashboard endpoint with the exact
420
- argv it sent, its outcome, and how any error was classified (`unavailable`,
421
- `rate-limited`, `auth-problem` or `other`).
432
+ `Repository access` probe; and each bounded dashboard probe, including the
433
+ Security priority lanes, with the exact argv it sent, its outcome, and how any
434
+ error was classified (`unavailable`, `rate-limited`, `auth-problem` or `other`).
422
435
 
423
436
  The `Repository access` probe shows whether the target resolves for the active
424
437
  `gh` credentials. A failed GitHub resolution response cannot distinguish a
@@ -453,17 +466,18 @@ through GraphQL instead — a separate 5,000/hour allowance. With the default
453
466
 
454
467
  | Visible tab | REST / hour | GraphQL / hour |
455
468
  |---|---|---|
456
- | Actions | ~1,620 | ~240 |
457
- | Issues or Pull Requests | ~300 | ~1,560 |
458
- | Security | ~2,280 | ~240 |
459
-
460
- Security is the most expensive, because it is three endpoints rather than one,
461
- and watching it costs just under half the REST budget. But Actions is not cheap
462
- either -- it is a third of the budget, and it is the tab every pane opens on,
463
- because one `gh run list` issues two REST requests rather than one. You do not
464
- have to take these figures on trust: `gh-glance --doctor` reports your actual
465
- remaining budget alongside what your configuration projects, which matters on a
466
- GitHub Enterprise tenant where the ceiling may not be 5,000 at all.
469
+ | Actions | up to ~1,800 | ~240 |
470
+ | Issues or Pull Requests | up to ~480 | ~1,560 |
471
+ | Security | ~2,280 normally; up to ~4,440 | ~240 |
472
+
473
+ Security is the most expensive. A repository whose newest alert pages are not
474
+ full uses the three base endpoint calls and lands near 2,280 REST requests per
475
+ hour. A full page activates bounded critical/high lanes for Dependabot and code
476
+ scanning, raising the safe projection to about 4,440. Actions is not cheap
477
+ either: one `gh run list` issues two REST requests. `gh-glance --doctor` reports
478
+ the conservative projection beside the server's actual REST and GraphQL
479
+ budgets, which matters on a GitHub Enterprise tenant where the ceilings may not
480
+ be 5,000.
467
481
 
468
482
  Two things pull the real number down. Any endpoint that fails in a way
469
483
  `gh-glance` recognises backs off instead of being re-asked every tick — a
@@ -494,7 +508,6 @@ a single pane on a healthy budget stays at 5 seconds and shows no badge.
494
508
 
495
509
  ## Limitations
496
510
 
497
-
498
511
  - **Security tab**: code scanning and secret scanning alerts require [GitHub
499
512
  Advanced Security](https://docs.github.com/en/code-security/getting-started/github-security-features).
500
513
  On repos/plans without it, `gh-glance` doesn't crash or spam errors -- it
@@ -526,12 +539,13 @@ a single pane on a healthy budget stays at 5 seconds and shows no badge.
526
539
  has its own breakpoint and drops to bare keys (`↑↓ Ent r q`) rather than
527
540
  truncating.
528
541
  - **Mouse reporting lifecycle.** Interactive sessions enable terminal mouse
529
- reporting for header drags and disable it before handing the terminal back.
530
- See [Adjusting column widths](#adjusting-column-widths) for text-selection
531
- behavior while it is active.
532
- - Issues and pull requests are fetched 150 at a time and alerts 100 at a time.
533
- A count is shown as `n+` when it was truncated, so the number is never
534
- presented as exact when it is not.
542
+ reporting only after `w` enters width mode, and disable it when that mode or
543
+ the app exits. See [Adjusting column widths](#adjusting-column-widths) for
544
+ text-selection behavior while it is active.
545
+ - Issues and pull requests are fetched 150 at a time. Each Security source has
546
+ a newest-100 lane; full Dependabot and code-scanning pages activate bounded
547
+ priority lanes. A count is shown as `n+` when any lane fills, so the number is
548
+ never presented as exact when it is not.
535
549
  - The Actions **TIME** column measures from the run's start to its last update.
536
550
  `gh` exposes no completion timestamp, so a workflow that was re-run later
537
551
  reports the span up to the re-run rather than its original duration.