gh-glance 0.6.0 → 0.7.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 -0
  2. package/README.md +106 -26
  3. package/index.mjs +1579 -150
  4. package/package.json +1 -1
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.7.0] - 2026-08-10
11
+
12
+ ### Added
13
+
14
+ - **Full-table columns can be resized with a mouse or keyboard.** Visible header
15
+ grips support left-button dragging, while `w` opens a keyboard width mode for
16
+ one- and five-cell adjustments and selected-column or active-tab resets.
17
+ - **Width choices persist automatically per user and per tab.** Only deviations
18
+ from the built-in defaults are stored, so resetting a column or tab cleanly
19
+ returns it to the source-controlled layout.
20
+ - **`gh-glance` now widens its own poll interval when the API budget is
21
+ draining.** The rate limit is per token, not per process, so several panes
22
+ spent one budget while each throttled as though it were alone: seven panes
23
+ exhausted a 5,000/hour REST limit in under half an hour (measured 8,500
24
+ calls/hour). Each pane now reads `gh api rate_limit` once a minute -- a probe
25
+ that does not itself count against the limit -- infers how much of the budget
26
+ is its own by comparing its spend against the token's total, and slows down to
27
+ fit, up to a 60-second ceiling. A single pane is unaffected and stays at 5
28
+ seconds. The status bar shows `throttled 18s` whenever the interval has
29
+ widened, and `r` still refreshes immediately.
30
+ - **`GH_GLANCE_REFRESH` sets the poll interval for every pane in a shell.** Same
31
+ 2-3600 second range as `--refresh`, which still takes precedence.
32
+
33
+ ### Changed
34
+
35
+ - **Oversized saved widths fit safely in narrower panes.** They are temporarily
36
+ reduced toward the defaults when the stock full table fits, without changing
37
+ the saved preference; widening the pane restores the preferred widths.
38
+ - **Terminal mouse reporting is released on every cleanup path.** Clean quit,
39
+ signals, crashes, and the interactive remote-setup handoff disable button and
40
+ SGR reporting before the primary screen is restored.
41
+
42
+ ### Fixed
43
+
44
+ - **The cost model understated the Actions tab by half.** `gh run list` issues
45
+ two REST requests, not one -- `GET /actions/runs` and
46
+ `GET /actions/workflows` -- so a pane on Actions costs about 1,620 requests an
47
+ hour rather than the 900 `--doctor` reported, and roughly three panes fill an
48
+ hourly budget rather than five. The figure was wrong in `--doctor`, in the
49
+ README's per-tab table, and in ADR 0001's request count. Measured with
50
+ `GH_DEBUG=api`; the projection and the new throttle now read one shared table.
51
+ - **`--doctor` reads the API budget from the right server.** `gh api rate_limit`
52
+ was the one `gh api` call sent without `--hostname`, so with
53
+ `--repo host/owner/name` the reported budget came from github.com while every
54
+ other call went to the tenant. A rate limit is per token *per server*, so the
55
+ two figures belong to unrelated limits.
56
+
57
+ ## [0.6.1] - 2026-08-06
58
+
59
+ ### Security
60
+
61
+ - **The GraphQL repository-resolution check no longer risks catastrophic
62
+ backtracking.** CodeQL flagged `isUnavailable()`'s `.*`-joined pattern as
63
+ worst-case superlinear over the repository name `gh` echoes back verbatim in
64
+ its error text -- attacker-influenced input reaching a vulnerable regex. It
65
+ is now two fixed-substring checks with the same matching behaviour and no
66
+ backtracking risk.
67
+
68
+ ### Added
69
+
70
+ - **The status bar shows gh-glance's own version**, right-aligned in the
71
+ lower-right corner the way lazygit's footer does. It is dropped on narrow
72
+ terminals rather than left to compete with the `Quit` hint for space.
73
+
10
74
  ## [0.6.0] - 2026-08-06
11
75
 
12
76
  ### Added
@@ -557,6 +621,9 @@ engineering, security, QA and UX. What follows is what changed as a result.
557
621
  - The `main` field from `package.json`. It advertised the file as importable,
558
622
  but importing it took over the terminal or exited the host process.
559
623
 
624
+ [Unreleased]: https://github.com/juan294/gh-glance/compare/v0.7.0...HEAD
625
+ [0.7.0]: https://github.com/juan294/gh-glance/compare/v0.6.1...v0.7.0
626
+ [0.6.1]: https://github.com/juan294/gh-glance/releases/tag/v0.6.1
560
627
  [0.6.0]: https://github.com/juan294/gh-glance/releases/tag/v0.6.0
561
628
  [0.5.1]: https://github.com/juan294/gh-glance/releases/tag/v0.5.1
562
629
  [0.5.0]: https://github.com/juan294/gh-glance/releases/tag/v0.5.0
package/README.md CHANGED
@@ -21,16 +21,16 @@ without switching to the browser.
21
21
  [1:Actions (4)] 2:Issues (3) 3:PRs (2) 4:Security (0)
22
22
  ────────────────────────────────────────────────────────────────────────────
23
23
  ╭─ Actions ────────────────────────────────────────────────────────────────╮
24
- │ TITLE WORKFLOW BRANCH TIME UPDATED │
24
+ │ TITLE │WORKFLOW │BRANCH │TIME │UPDATED │
25
25
  │ ──────────────────────────────────────────────────────────────────────── │
26
- │ >+ ci: pin actions to comm… #443 CI develop 1m20s 2d ago │
27
- │ x fix: restore the primar… #442 Code… develop 1m28s 2d ago │
28
- │ ! chore: bump dependencies #441 CI dependa…int-10 56h49m 2d ago │
29
- │ - docs: update the readme #440 CI develop 15s 3d ago │
26
+ │ >+ ci: pin actions to comm… #443 CI develop 1m20s 9d ago │
27
+ │ x fix: restore the primar… #442 Code… develop 1m28s 9d ago │
28
+ │ ! chore: bump dependencies #441 CI dependa…int-10 222h8m 9d ago │
29
+ │ - docs: update the readme #440 CI develop 15s 10d ago │
30
30
  │ │
31
31
  │ │
32
32
  ╰───────────────────────────────────────────────────────────────── 4 of 4 ─╯
33
- ⣾ Fetching Move: ↑↓ | Open: Ent | Refresh: r | Quit: q
33
+ ⣾ Fetching Move: ↑↓ | Open: Ent | Refresh: r | Width: w | Quit: q 0.7.0
34
34
  ```
35
35
 
36
36
  > Captured from a real run at 76 columns with `GH_GLANCE_ICONS=unicode`, so the
@@ -73,6 +73,8 @@ current.
73
73
  that have GitHub Advanced Security enabled -- see [Limitations](#limitations).
74
74
  - Tab bar with live counts, pinned to the top of the pane above a divider,
75
75
  switchable via `1`-`4`, arrow keys, or `Tab`/`Shift+Tab`
76
+ - Adjustable full-table columns, with visible header grips, a keyboard width
77
+ mode, and preferences kept separately for each tab
76
78
  - `lazygit`-style panel frame: the tab name sits in the top border, the
77
79
  visible-of-total row count in the bottom
78
80
  - A `Fetching` indicator that brightens on every refresh and animates during the
@@ -230,8 +232,42 @@ stdout isn't a terminal rather than streaming redraw frames into a pipe.
230
232
  | `PgUp` / `PgDn` | Move a page at a time |
231
233
  | `Enter` | Open the selected item, or accept an onboarding prompt |
232
234
  | `r` | Refresh the current tab now |
235
+ | `w` | Adjust table column widths |
233
236
  | `?` | Show the keys without leaving the dashboard (any key closes it) |
234
- | `q` / `Esc` / `Ctrl+C` | Quit |
237
+ | `q` / `Esc` / `Ctrl+C` | Quit (`Esc` leaves width mode) |
238
+
239
+ ### Adjusting column widths
240
+
241
+ Press `w` to adjust the named fixed-width columns in the visible full table.
242
+ The flexible **TITLE** or **SUMMARY** column, status and severity cells, and
243
+ compact layouts are not adjustable. Outside width mode, the normal arrow,
244
+ `Tab`, `Enter`, and refresh meanings above are unchanged.
245
+
246
+ | Key | In width mode |
247
+ |---|---|
248
+ | `Tab` / `Shift+Tab` | Select the next / previous adjustable column |
249
+ | `←` / `→` | Resize the selected column by one cell |
250
+ | `Shift+←` / `Shift+→` | Resize the selected column by five cells |
251
+ | `r` | Reset the selected column to its default |
252
+ | `R` | Reset every width on the active tab |
253
+ | `Enter` / `Esc` / `w` | Finish and leave width mode |
254
+ | `q` / `Ctrl+C` | Quit globally |
255
+
256
+ While the mode is active, the ordinary status hints are replaced by a bounded
257
+ line such as:
258
+
259
+ ```text
260
+ Width: BRANCH 14 Tab select <- -> resize r reset Esc done
261
+ ```
262
+
263
+ In an interactive terminal, you can also left-drag a visible `│` header grip.
264
+ Pressing a grip selects its column and enters width mode; releasing the button,
265
+ including outside the header, ends the drag. Row clicking, hover behavior, and
266
+ pointer-shape changes are not supported. Mouse resizing has the same interactive
267
+ terminal requirement as keyboard input.
268
+
269
+ While gh-glance is running, terminal-native text selection may require your
270
+ terminal's mouse-reporting bypass modifier, commonly `Shift`.
235
271
 
236
272
  The cursor tracks the *item*, not the row position, so it stays on what you
237
273
  selected as new rows arrive above it. `Enter` works on Actions, Issues and Pull
@@ -278,11 +314,36 @@ Environment variables work too, and the flags take precedence:
278
314
  | `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 |
279
315
  | `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 |
280
316
  | `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) |
317
+ | `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) |
281
318
  | `GH_GLANCE_ICONS=unicode` | Plain ASCII status icons, for terminals without a Nerd Font |
282
319
  | `GH_GLANCE_NO_ANIMATION=1` | Freeze the spinner — no motion at all |
283
320
  | `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 |
284
321
  | `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. |
285
322
 
323
+ ### Saved column widths
324
+
325
+ Width choices are saved automatically, globally for the current user and
326
+ separately for each tab. They are not repository-specific. Only deviations from
327
+ the built-in defaults are stored: `r` removes the selected column's deviation,
328
+ and `R` removes every deviation for the active tab.
329
+
330
+ The versioned preference file is resolved in this order:
331
+
332
+ ```text
333
+ $XDG_CONFIG_HOME/gh-glance/preferences.json absolute XDG root
334
+ ~/Library/Application Support/gh-glance/preferences.json macOS fallback
335
+ ~/.config/gh-glance/preferences.json Linux fallback
336
+ ```
337
+
338
+ `XDG_CONFIG_HOME` is used only when it is a non-empty absolute path. An unknown
339
+ file version or a corrupt, malformed, or unreadable document falls back to the
340
+ built-in defaults rather than preventing the dashboard from starting. Within an
341
+ otherwise valid document, unknown or invalid entries are ignored individually
342
+ while valid deviations still load. If a write fails, resizing still works for
343
+ the live session and width mode reports `Widths not saved`; a later successful
344
+ write clears the warning. The UI owns this file, so direct editing is not the
345
+ primary configuration workflow.
346
+
286
347
  ## GitHub Enterprise and EMU
287
348
 
288
349
  **The common case needs no configuration.** Authenticate once --
@@ -363,15 +424,17 @@ through GraphQL instead — a separate 5,000/hour allowance. With the default
363
424
 
364
425
  | Visible tab | REST / hour | GraphQL / hour |
365
426
  |---|---|---|
366
- | Actions | ~900 | ~240 |
367
- | Issues or Pull Requests | ~240 | ~1,560 |
368
- | Security | ~2,220 | ~240 |
369
-
370
- Security is the expensive one because it is three endpoints rather than one,
371
- and watching it costs just under half the REST budget. You do not have to take
372
- these figures on trust: `gh-glance --doctor` reports your actual remaining
373
- budget alongside what your configuration projects, which matters on a GitHub
374
- Enterprise tenant where the ceiling may not be 5,000 at all.
427
+ | Actions | ~1,620 | ~240 |
428
+ | Issues or Pull Requests | ~300 | ~1,560 |
429
+ | Security | ~2,280 | ~240 |
430
+
431
+ Security is the most expensive, because it is three endpoints rather than one,
432
+ and watching it costs just under half the REST budget. But Actions is not cheap
433
+ either -- it is a third of the budget, and it is the tab every pane opens on,
434
+ because one `gh run list` issues two REST requests rather than one. You do not
435
+ have to take these figures on trust: `gh-glance --doctor` reports your actual
436
+ remaining budget alongside what your configuration projects, which matters on a
437
+ GitHub Enterprise tenant where the ceiling may not be 5,000 at all.
375
438
 
376
439
  Two things pull the real number down. Any endpoint that fails in a way
377
440
  `gh-glance` recognises backs off instead of being re-asked every tick — a
@@ -380,9 +443,18 @@ hour, an authorization failure every 30 seconds, a rate limit every minute.
380
443
  Pressing `r` clears that backoff and retries immediately. And `--refresh`
381
444
  scales the whole figure: doubling the interval halves it.
382
445
 
383
- So a pane left open all day shares the budget with your other `gh` commands
384
- rather than exhausting it, but it is not free, and parking it on the Security
385
- tab is the case worth knowing about.
446
+ One pane on Actions costs about a third of an hourly REST budget, so roughly
447
+ three panes fill it. Past that, `gh-glance` widens its own poll interval: it
448
+ reads your remaining budget once a minute, works out how much of it belongs to
449
+ this pane by comparing its own spend against the token's total, and slows down
450
+ to fit -- up to a 60-second ceiling. The status bar says `throttled 18s` while
451
+ that is in effect, and `r` still refreshes immediately. Nothing is shared
452
+ between panes: the token's own counter is what they all read, so it also notices
453
+ a `gh pr checks --watch` or anything else spending on the same token.
454
+
455
+ `GH_GLANCE_REFRESH=30` sets a wider floor for every pane in a shell; `--refresh`
456
+ still wins per pane. The adaptive interval only ever widens from that floor, so
457
+ a single pane on a healthy budget stays at 5 seconds and shows no badge.
386
458
 
387
459
  ## Limitations
388
460
 
@@ -406,13 +478,21 @@ tab is the case worth knowing about.
406
478
  runs requested -- so scrolling that tab has little to move through. The count
407
479
  in the bottom edge always says how much you are seeing out of how much was
408
480
  fetched.
409
- - **Minimum width.** Each tab drops to a compact layout (icon, title, and one
410
- other column) at its own threshold, so a narrow pane keeps as much as that
411
- particular tab can fit: Security holds its full set down to 44 columns,
412
- Issues to 50, Actions to 56, Pull Requests to 61. Below 24 columns nothing
413
- useful fits, so the pane says `too narrow` and keeps the frame, tab bar and
414
- quit hint; widening it recovers immediately. The status bar has its own
415
- breakpoint and drops to bare keys (`↑↓ Ent r q`) rather than truncating.
481
+ - **Minimum width and compact layout.** Compact descriptors remain fixed and
482
+ non-adjustable. With the built-in full widths, Security fits down to 44
483
+ columns, Issues to 50, Actions to 56, and Pull Requests to 61. A narrower
484
+ preference can lower the active tab's full-layout floor. An oversized
485
+ preference is fitted temporarily toward the defaults as the pane narrows, so
486
+ it never forces compact while the stock full table still fits. The saved width
487
+ itself is not changed, and widening restores it. When no eligible full layout
488
+ fits, the active tab uses its fixed compact layout. Below 24 columns the pane
489
+ says `too narrow` and keeps the frame, tab bar and quit hint. The status bar
490
+ has its own breakpoint and drops to bare keys (`↑↓ Ent r q`) rather than
491
+ truncating.
492
+ - **Mouse reporting lifecycle.** Interactive sessions enable terminal mouse
493
+ reporting for header drags and disable it before handing the terminal back.
494
+ See [Adjusting column widths](#adjusting-column-widths) for text-selection
495
+ behavior while it is active.
416
496
  - Issues and pull requests are fetched 150 at a time and alerts 100 at a time.
417
497
  A count is shown as `n+` when it was truncated, so the number is never
418
498
  presented as exact when it is not.