gh-glance 0.3.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 (5) hide show
  1. package/CHANGELOG.md +200 -0
  2. package/LICENSE +21 -0
  3. package/README.md +277 -0
  4. package/index.mjs +2071 -0
  5. package/package.json +57 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,200 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.0] - 2026-08-03
9
+
10
+ The dashboard stops being read-only: you can now move through the table and open
11
+ what you are looking at. The rest of the release is the audit backlog `0.2.0`
12
+ deferred — a configuration surface, structural refactors, and the first tests
13
+ that drive the real binary under a terminal.
14
+
15
+ ### Added
16
+
17
+ - **Row selection, scrolling, and opening items in a browser.** `↑`/`↓` or
18
+ `j`/`k` move a cursor, `PgUp`/`PgDn` move a page, and `Enter` opens the
19
+ selected run, issue or pull request. The cursor tracks the item rather than
20
+ the row position, so it stays put as new rows arrive above it rather than
21
+ drifting every few seconds. The marker is a plain `>` sharing the existing
22
+ icon column, so it survives `NO_COLOR` and costs no width.
23
+ - **Flags: `--repo`, `--refresh`, `--tab`, `--verbose`.** The tool still takes no
24
+ arguments by default. `--repo owner/name` watches a repository you have not
25
+ cloned, and works from any directory. `--refresh` sets the active-tab interval
26
+ between 2 and 3600 seconds — below two a fetch cannot finish before the next
27
+ tick, so the value would silently stop being real, and it is refused rather
28
+ than accepted. `--tab` picks the starting tab. An unrecognised flag still
29
+ exits 2 rather than being ignored.
30
+ - **`--verbose`** writes one line per `gh` invocation to stderr with its duration
31
+ and outcome, for attaching to a bug report. It refuses to start while stderr
32
+ is still a terminal, because the log would otherwise be drawn over the
33
+ dashboard.
34
+ - A pty end-to-end harness (`npm run test:pty`). It drives the real binary under
35
+ a pseudo-terminal against a fixture `gh`, and asserts the things unit tests
36
+ structurally cannot reach: that the alternate screen is entered and left
37
+ exactly once, that the cursor is restored, that the final frame is exactly as
38
+ tall as the terminal and never wider, that a narrow pane still draws its
39
+ chrome, that signal exit codes are 143/130/129, and that nothing is left on
40
+ the primary buffer afterwards. It runs in CI as an advisory check.
41
+
42
+ ### Changed
43
+
44
+ - **Terminal traffic roughly halved.** The renderer now updates only the lines
45
+ that changed instead of rewriting the whole viewport: measured 13,918 bytes
46
+ down to 6,799 on a settled 80x24 pane.
47
+ - Rows are memoised and the spinner frame is no longer handed to the three tabs
48
+ that ignore it, so a running workflow animates one glyph instead of
49
+ reconciling every row ten times a second.
50
+ - The Actions tab count carries a `!` when the newest run failed, so "is CI red"
51
+ is answerable from any tab rather than only from that one.
52
+ - The status bar's key hints are plain ASCII. The arrows, return symbol and
53
+ box-drawing separator it used are East-Asian-Ambiguous, which the renderer
54
+ measures as two columns each — enough to overflow an 80-column terminal once
55
+ selection added a hint.
56
+ - The four fetchers are driven by one registry rather than four near-identical
57
+ functions, colours are named rather than repeated as literals, and the
58
+ terminal-size hook is extracted. No behaviour changed.
59
+ - Installing from a git URL or a local directory no longer writes git hooks.
60
+ - `develop` is now PR-only, admin-enforced, with eight required checks. Its
61
+ previous protection required an approving review that a solo maintainer could
62
+ not give, so every commit had been landing as a direct push and the required
63
+ checks gated nothing.
64
+
65
+ ### Fixed
66
+
67
+ - **`kill` no longer erases your terminal scrollback.** On `SIGTERM`, `SIGINT`
68
+ and `SIGHUP` the dashboard handed the terminal back to the primary buffer and
69
+ the renderer then repainted onto it — preceded by an erase-scrollback escape,
70
+ so a `kill` threw away the terminal history and left a dead dashboard frame
71
+ behind. Measured at 2,728 bytes on an 80x24 pane. Quitting with `q`, `Esc` or
72
+ `Ctrl+C` was never affected. Found by the new pty harness; present since
73
+ before 0.2.0.
74
+
75
+ ## [0.2.0] - 2026-08-03
76
+
77
+ First release. `0.1.0` was never published to any registry and was never
78
+ tagged, so this is the first version with an artifact behind it.
79
+
80
+ The bulk of this entry comes from a pre-launch audit that found 118 issues
81
+ across architecture, the `gh` data layer, rendering, performance, release
82
+ engineering, security, QA and UX. What follows is what changed as a result.
83
+
84
+ ### Security
85
+
86
+ - **Sanitize untrusted GitHub text at the data boundary.** Every string the tool
87
+ displays — issue and PR titles, run titles, branch names, advisory summaries —
88
+ is chosen by whoever opens the issue or pull request. Ink strips CSI sequences
89
+ but deliberately preserves OSC, SGR and bare C0 control characters, so OSC 8
90
+ hyperlinks (an attacker-chosen clickable URL with no visual tell), carriage
91
+ returns (which overwrite the row above, and could blank a critical alert),
92
+ bells and newlines all reached the terminal. A single multi-line title could
93
+ evict other rows out of the pane entirely. Control characters are now replaced
94
+ at the point the JSON is parsed. Emoji, ZWJ sequences, CJK, combining marks,
95
+ right-to-left text and the tool's own Nerd Font glyphs are unaffected.
96
+ - **Remote values can no longer crash the render.** Severity and status strings
97
+ were used directly as object keys, so a code-scanning alert with a severity of
98
+ `constructor` returned a function where a colour was expected and took the
99
+ whole dashboard down — inside the alternate screen, so the stack trace was
100
+ wiped on the way out. Lookups now ignore inherited keys, and each row is
101
+ wrapped in an error boundary.
102
+ - Enabled private vulnerability reporting. `SECURITY.md` told reporters to use
103
+ it while it was switched off, so the documented disclosure path accepted
104
+ nothing.
105
+
106
+ ### Fixed
107
+
108
+ - **A stalled `gh` no longer wedges a tab forever.** Subprocess calls had no
109
+ timeout, and the in-flight guard was only cleared when the promise settled —
110
+ which a hung child never does. That tab then stopped refreshing for the life
111
+ of the process while the spinner kept insisting it was working. All calls now
112
+ carry a timeout, a kill signal, a 16 MiB output buffer and an abort signal.
113
+ - **Errors are readable.** The error formatter checked a property Node never
114
+ sets, so every failure rendered as the entire reconstructed command line —
115
+ roughly 150 characters of JSON field names — against a layout that reserved
116
+ one row for it, overflowing the frame and making the screen flash on every
117
+ redraw. It now shows the first line of stderr, and error and note lines are
118
+ pinned to the single row they are budgeted.
119
+ - **A parse failure no longer reports "no runs".** The payload cache was written
120
+ before parsing, so a malformed response was cached, its error was cleared on
121
+ the next tick, and the retry was skipped — leaving the tab confidently empty
122
+ forever. The cache is written only after a successful parse.
123
+ - **Security failures are no longer misreported as configuration.** Any failure
124
+ on the code-scanning or secret-scanning endpoints — expired token, rate limit,
125
+ network — was reported as "not enabled". Only a genuine 403/404 says that now;
126
+ everything else surfaces as itself, and unavailable sources back off instead
127
+ of being re-asked on every refresh.
128
+ - **Counts stopped lying.** Issues, pull requests and alerts are all capped by
129
+ the fetch, but only the Actions tab said so. Every tab now marks a truncated
130
+ count, and a tab whose fetches are failing is marked in the tab bar rather
131
+ than showing a frozen number at full confidence.
132
+ - **Rows are sorted by what matters.** Security alerts were ordered by which
133
+ endpoint answered first, which put secret-scanning alerts — always critical —
134
+ last, below the fold. They now sort by severity. Issues and pull requests were
135
+ returned oldest-created-first while the age column showed the update time, so
136
+ the column could not be read and truncation dropped recently-active items;
137
+ both now sort by update time.
138
+ - **A crash is visible.** Uncaught errors were drawn into the alternate screen
139
+ and then erased by the exit handler, so the tool vanished with exit code 0.
140
+ Crashes now restore the screen first, print a stack trace, and exit non-zero.
141
+ Interrupts exit 130/143 instead of 0.
142
+ - **Narrow panes work.** Below about 61 columns the fixed columns overflowed the
143
+ frame, rows wrapped and the screen repainted in full every frame; in the band
144
+ just above that the frame looked correct while the title column silently
145
+ rendered empty. Narrow panes now drop columns instead, keeping the frame, tab
146
+ bar and status line on screen.
147
+ - Missing or malformed timestamps rendered as `NaNd ago`; they now render as a
148
+ dash.
149
+ - `GH_FORCE_TTY`, which many people export in their shell profile, made `gh`
150
+ emit coloured JSON that could not be parsed, breaking all four tabs at once.
151
+ The environment passed to `gh` is now neutralized for display variables only.
152
+ - A missing `gh` or a directory that is not a repository produced four copies of
153
+ a raw subprocess error inside the alternate screen, which was then erased on
154
+ exit. Both are now caught before the dashboard starts, with an actionable
155
+ message and a non-zero exit.
156
+
157
+ ### Added
158
+
159
+ - `q` and `Esc` quit; `r` refreshes the current tab immediately.
160
+ - `GH_GLANCE_ICONS=unicode` swaps the Nerd Font Octicons for plain ASCII, so the
161
+ tool is usable without a Nerd Font. The previous advice was to edit the source
162
+ — which would not survive an update once installed as a package.
163
+ - `GH_GLANCE_NO_ANIMATION=1` freezes the spinner, for a pane that sits in
164
+ peripheral vision for hours.
165
+ - A severity column on the Security tab. Severity had been carried by the shield
166
+ icon's colour alone, which made critical and high indistinguishable and
167
+ erased the distinction entirely under `NO_COLOR` or for a colour-blind reader.
168
+ - A staleness marker once the visible tab's data is old enough to mislead.
169
+ - Screen-reader labels on the status icons, which otherwise announce as nothing.
170
+ - A unit test suite on Node's built-in runner — no framework, no build step.
171
+ Before this, no function in the file was executed by any check.
172
+ - `release.yml`, which publishes with provenance from a verified tag.
173
+
174
+ ### Changed
175
+
176
+ - **Node 22 is now the minimum.** Ink and two of its dependencies already
177
+ required it while the package claimed 20.19, so installs on the advertised
178
+ floor emitted engine warnings. Node 20 reached end of life on 2026-04-30.
179
+ - Background tabs refresh every 60 seconds rather than every 20. Steady-state
180
+ polling had been consuming 40-50% of an hourly GitHub API rate limit for a
181
+ single pane; the visible tab is unchanged at 5 seconds.
182
+ - The spinner animates on first load and while a run is executing, rather than
183
+ on every fetch. The previous behaviour kept a 10 fps redraw loop alive
184
+ permanently, costing roughly 44 MB of terminal writes per idle hour.
185
+ - `--version` and `--help` no longer load the rendering stack: 0.27s and 94 MB
186
+ down to 0.04s and 49 MB.
187
+ - Secondary text uses the terminal's own dim attribute rather than a fixed
188
+ colour chosen for dark themes, so it is readable on light backgrounds too.
189
+ - The age column is labelled `UPDATED`, which is what it has always shown.
190
+ - CI runs the test suite, no longer stops the matrix at the first failure,
191
+ asserts exit codes rather than just non-zero, and pins every action to a
192
+ commit SHA.
193
+
194
+ ### Removed
195
+
196
+ - The `main` field from `package.json`. It advertised the file as importable,
197
+ but importing it took over the terminal or exited the host process.
198
+
199
+ [0.3.0]: https://github.com/juan294/gh-glance/releases/tag/v0.3.0
200
+ [0.2.0]: https://github.com/juan294/gh-glance/releases/tag/v0.2.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 juan294
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # gh-glance
2
+
3
+ <a href="https://chapa.thecreativetoken.com/u/juan294">
4
+ <img src="https://chapa.thecreativetoken.com/u/juan294/badge.svg" alt="juan294's Chapa Impact Badge" width="100%" />
5
+ </a>
6
+
7
+ [![CI](https://github.com/juan294/gh-glance/actions/workflows/ci.yml/badge.svg?branch=develop&event=push)](https://github.com/juan294/gh-glance/actions/workflows/ci.yml?query=branch%3Adevelop+event%3Apush)
8
+ [![CodeQL](https://github.com/juan294/gh-glance/actions/workflows/codeql.yml/badge.svg?branch=develop&event=push)](https://github.com/juan294/gh-glance/actions/workflows/codeql.yml?query=branch%3Adevelop+event%3Apush)
9
+ ![Node.js](https://img.shields.io/badge/Node.js-22%2B-43853d)
10
+ [![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
11
+
12
+ A live-refreshing GitHub dashboard that fits in a narrow terminal pane --
13
+ **Actions, Issues, Pull Requests, and Security alerts**, one tab at a time,
14
+ refreshing every 5 seconds with no flicker.
15
+
16
+ Built for pairing with a terminal multiplexer/workspace tool (e.g. a sidebar
17
+ pane next to your editor) where you want an always-on glance at repo activity
18
+ without switching to the browser.
19
+
20
+ ```
21
+ ╭─ Actions ────────────────────────────────────────────────────────────────╮
22
+ │ TITLE WORKFLOW BRANCH TIME UPDATED │
23
+ │ ──────────────────────────────────────────────────────────────────────── │
24
+ │ >+ ci: pin actions to comm… #443 CI develop 1m20s 2d ago │
25
+ │ x fix: restore the primar… #442 Code… develop 1m28s 2d ago │
26
+ │ ! chore: bump dependencies #441 CI dependa…int-10 56h49m 2d ago │
27
+ │ - docs: update the readme #440 CI develop 15s 3d ago │
28
+ │ │
29
+ │ │
30
+ ╰───────────────────────────────────────────────────────────────── 4 of 4 ─╯
31
+ [1:Actions (4)] 2:Issues (3) 3:PRs (2) 4:Security (0)
32
+ ⠋ Fetching Move: jk | Open: Ent | Refresh: r | Quit: q
33
+ ```
34
+
35
+ > Captured from a real run at 76 columns with `GH_GLANCE_ICONS=unicode`, so the
36
+ > status icons render in a browser. With a Nerd Font (the default) they are
37
+ > Octicon glyphs instead.
38
+ >
39
+ > The `>` on the first row is the cursor. Two more markers appear when they
40
+ > apply: a `+` after a tab's count means the list was truncated by the fetch
41
+ > limit, and a `!` after the Actions count means the newest run failed — so
42
+ > "is CI red" is answerable without switching to that tab.
43
+
44
+ <!-- contract:allow-emoji -- the check/cross above stand in for Nerd Font
45
+ Octicons the app actually draws; they are literal examples, not decoration. -->
46
+
47
+ ---
48
+
49
+ ## Why
50
+
51
+ GitHub's own web UI already shows all of this. `gh-glance` exists for the
52
+ moment you don't want to alt-tab to a browser tab to check whether CI is
53
+ still red, whether someone commented on your PR, or whether Dependabot found
54
+ something new -- it's meant to sit in a corner of your terminal and just be
55
+ current.
56
+
57
+ ## Features
58
+
59
+ - **Actions** -- recent workflow runs: status, title, workflow, branch,
60
+ elapsed time, age
61
+ - **Issues** -- open issues: title, author, first label, age
62
+ - **Pull Requests** -- open PRs: title, author, branch, review status
63
+ (approved / changes requested / pending), age
64
+ - **Security** -- open Dependabot alerts: package, summary, age, sorted with the
65
+ most severe first and with severity spelled out in its own column, not carried
66
+ by colour alone.
67
+ Code scanning and secret scanning alerts are included too, on repos/plans
68
+ that have GitHub Advanced Security enabled -- see [Limitations](#limitations).
69
+ - Tab bar with live counts, pinned to the bottom of the pane alongside the
70
+ status line, switchable via `1`-`4`, arrow keys, or `Tab`/`Shift+Tab`
71
+ - `lazygit`-style panel frame: the tab name sits in the top border, the
72
+ visible-of-total row count in the bottom
73
+ - A spinning `Fetching` indicator while a refresh is in flight, so the pane
74
+ says when it's working without spending a line on it
75
+ - Status icons are real GitHub Octicons (via the Nerd Font glyph set), not emoji
76
+ -- with a plain-ASCII fallback for terminals without one
77
+ - Readable without colour: severity has its own column, run states have distinct
78
+ glyphs, and the active tab is bracketed, so `NO_COLOR=1` and colour-vision
79
+ deficiency both stay navigable
80
+ - Says when it is stale rather than showing old data silently, and marks a tab
81
+ whose last refresh failed
82
+ - Adapts row count to the terminal pane's height live, on resize
83
+ - Enters the terminal's alternate screen buffer on launch (like `lazygit`,
84
+ `htop`, `vim`) so the shell prompt that launched it stays out of view, and
85
+ is restored cleanly on exit
86
+
87
+ ## Prerequisites
88
+
89
+ - [Node.js](https://nodejs.org/) `>=22` (Ink requires it; Node 20 is end-of-life)
90
+ - The [`gh` CLI](https://cli.github.com/) `>=2.20`, authenticated (`gh auth login`)
91
+ - A terminal font with [Nerd Font](https://www.nerdfonts.com/) glyphs (for the
92
+ status icons to render correctly -- without one, they'll show as blank
93
+ boxes; see [Icons without a Nerd Font](#icons-without-a-nerd-font))
94
+
95
+ ## Install
96
+
97
+ ```bash
98
+ git clone https://github.com/juan294/gh-glance.git
99
+ cd gh-glance
100
+ npm install
101
+ npm link # makes the `gh-glance` command available globally
102
+ ```
103
+
104
+ (Not yet published to npm -- clone + `npm link` is the current install path.)
105
+
106
+ `npm link` is what puts `gh-glance` on your `PATH`; it symlinks the global
107
+ bin at your Node version's `bin/` directory through to this checkout:
108
+
109
+ ```
110
+ <node>/bin/gh-glance -> <node>/lib/node_modules/gh-glance -> /path/to/your/clone
111
+ ```
112
+
113
+ Because the link resolves to the clone rather than to a copy, you can move
114
+ or rename the directory and the command keeps working. Two things do break
115
+ it, and both are fixed by re-running `npm link` from the clone:
116
+
117
+ - switching Node versions (nvm/fnm install their own global `bin/`)
118
+ - setting up on a fresh machine, or after `npm unlink -g gh-glance`
119
+
120
+ ### Using it as a workspace pane
121
+
122
+ `gh-glance` takes no arguments and infers the repo from the working
123
+ directory, so it drops straight into a pane definition of whatever
124
+ workspace tool you use. With [summon](https://github.com/juan294/summon),
125
+ that's a one-line pane in a layout file:
126
+
127
+ ```
128
+ pane.enhance=gh-glance
129
+ ```
130
+
131
+ Point the pane at the bare command rather than an absolute path to
132
+ `index.mjs` -- resolving through `PATH` is what lets the clone move without
133
+ every layout needing an edit.
134
+
135
+ ## Usage
136
+
137
+ Run it from inside any locally cloned GitHub repository:
138
+
139
+ ```bash
140
+ gh-glance
141
+ ```
142
+
143
+ It infers the repository from the current directory's git remote, the same
144
+ way `gh` itself does -- no flags or config needed.
145
+
146
+ ```bash
147
+ gh-glance --help # usage and keybindings
148
+ gh-glance --version # print the version
149
+ ```
150
+
151
+ It's an interactive full-screen dashboard, so it exits with an error if
152
+ stdout isn't a terminal rather than streaming redraw frames into a pipe.
153
+
154
+ ### Keybindings
155
+
156
+ | Key | Action |
157
+ |---|---|
158
+ | `1` `2` `3` `4` | Jump to Actions / Issues / Pull Requests / Security |
159
+ | `←` / `→` | Previous / next tab |
160
+ | `Tab` / `Shift+Tab` | Next / previous tab |
161
+ | `↑` / `↓` or `j` / `k` | Move the cursor between rows |
162
+ | `PgUp` / `PgDn` | Move a page at a time |
163
+ | `Enter` | Open the selected item in your browser |
164
+ | `r` | Refresh the current tab now |
165
+ | `q` / `Esc` / `Ctrl+C` | Quit |
166
+
167
+ The cursor tracks the *item*, not the row position, so it stays on what you
168
+ selected as new rows arrive above it. `Enter` works on Actions, Issues and Pull
169
+ Requests; the Security tab has no per-alert `gh` command to open.
170
+
171
+ If `gh-glance` is started without an interactive stdin (for example with stdin
172
+ redirected), the key handlers cannot run and the status bar shows only `Quit: ^C`
173
+ rather than advertising keys that would do nothing.
174
+
175
+ ## Configuration
176
+
177
+ `gh-glance` still takes no arguments by default, so it drops straight into a
178
+ pane definition. Flags are there when you want them:
179
+
180
+ | Flag | Effect |
181
+ |---|---|
182
+ | `-R`, `--repo owner/name` | Watch a specific repository instead of the current directory's. Works from anywhere -- you do not need a local clone. |
183
+ | `--refresh <seconds>` | Active-tab poll interval, 2-3600, default 5. Background tabs stay at 12x this. |
184
+ | `--tab <name>` | Start on `actions`, `issues`, `prs` or `security`. |
185
+ | `--verbose` | Log one line per `gh` call to stderr, with timing and outcome. stderr must be redirected: `gh-glance --verbose 2>gh-glance.log`. |
186
+
187
+ An unrecognised flag exits 2 rather than being ignored, so a typo fails loudly.
188
+
189
+ Environment variables work too, and the flags take precedence:
190
+
191
+ | Variable | Effect |
192
+ |---|---|
193
+ | `GH_REPO=owner/name` | Watch a specific repository instead of the current directory's |
194
+ | `GH_GLANCE_ICONS=unicode` | Plain ASCII status icons, for terminals without a Nerd Font |
195
+ | `GH_GLANCE_NO_ANIMATION=1` | Freeze the spinner — no motion at all |
196
+ | `NO_COLOR=1` | Disable colour. Status stays readable: severity has its own column, run states have distinct glyphs, and the active tab is bracketed |
197
+ | `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. |
198
+
199
+ ## Rate limit
200
+
201
+ The visible tab refreshes every 5 seconds; the other three refresh every 60
202
+ seconds, purely to keep their counts honest. That works out at roughly 500
203
+ REST requests an hour, about 10% of the 5,000/hour authenticated limit — so
204
+ leaving a pane open all day does not exhaust the budget your other `gh`
205
+ commands share.
206
+
207
+ ## Limitations
208
+
209
+
210
+ - **Security tab**: code scanning and secret scanning alerts require [GitHub
211
+ Advanced Security](https://docs.github.com/en/code-security/getting-started/github-security-features).
212
+ On repos/plans without it, `gh-glance` doesn't crash or spam errors -- it
213
+ shows a one-line note per unavailable feature and still displays whatever
214
+ it *can* get (Dependabot alerts work independently of GHAS). If your repo
215
+ has GHAS enabled, those alerts just show up automatically -- no
216
+ configuration needed.
217
+ - Scrolling moves through what was fetched, not through everything on GitHub.
218
+ Issues and Pull Requests fetch 150, so there is real range there. Actions
219
+ deliberately fetches about a screenful -- its cost is linear in the number of
220
+ runs requested -- so scrolling that tab has little to move through. The count
221
+ in the bottom edge always says how much you are seeing out of how much was
222
+ fetched.
223
+ - **Minimum width.** Below about 61 columns the table drops to a compact layout
224
+ (icon, title, and one other column) so the frame, tab bar and status line stay
225
+ on screen. Below about 24 columns it will not lay out sensibly.
226
+ - Issues and pull requests are fetched 150 at a time and alerts 100 at a time.
227
+ A count is shown as `n+` when it was truncated, so the number is never
228
+ presented as exact when it is not.
229
+ - The Actions **TIME** column measures from the run's start to its last update.
230
+ `gh` exposes no completion timestamp, so a workflow that was re-run later
231
+ reports the span up to the re-run rather than its original duration.
232
+ - macOS/Linux terminals with ANSI + alternate-screen-buffer support. Not
233
+ tested on Windows -- `npm` will not stop you installing it there, but the
234
+ alternate-screen handling is unverified.
235
+
236
+ ### Icons without a Nerd Font
237
+
238
+ The status icons are Octicon glyphs from the [Nerd
239
+ Fonts](https://www.nerdfonts.com/) private-use-area range. If your terminal
240
+ font isn't a Nerd Font they render as blank boxes -- which would leave status
241
+ carried by the colour of a blank box, and by nothing at all under `NO_COLOR`.
242
+
243
+ Set `GH_GLANCE_ICONS=unicode` for plain ASCII equivalents:
244
+
245
+ ```bash
246
+ GH_GLANCE_ICONS=unicode gh-glance
247
+ ```
248
+
249
+ They are deliberately single-cell ASCII rather than prettier symbols like `✓`
250
+ and `✗`, because those are East-Asian-Ambiguous width and render two cells wide
251
+ in some terminals, which would shift every column to their right.
252
+
253
+ ## Troubleshooting
254
+
255
+ | Symptom | Cause and fix |
256
+ |---|---|
257
+ | `the gh CLI is not installed` | Install it from [cli.github.com](https://cli.github.com), then `gh auth login`. |
258
+ | `not inside a git repository` | Run it from a cloned GitHub repository, or set `GH_REPO=owner/name`. |
259
+ | Status icons are blank boxes | Your terminal font is not a Nerd Font. Use `GH_GLANCE_ICONS=unicode`. |
260
+ | Security tab shows a "not enabled" note | Code scanning and secret scanning need GitHub Advanced Security. Dependabot alerts work independently. A genuine auth or network failure shows the real error instead. |
261
+ | A tab's count is red | That tab's last fetch failed. The error itself is shown when you switch to it. |
262
+ | `stale 2m` in the status bar | The visible tab has not refreshed successfully for a while — usually a network drop. |
263
+ | It exits immediately when piped | Intentional. It is a full-screen dashboard, not a reporting command. |
264
+ | 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. Attach it to a bug report. |
265
+ | `--verbose` refuses to start | stderr is still your terminal, where the log would draw over the dashboard. Redirect it to a file. |
266
+
267
+ ## Contributing
268
+
269
+ See [CONTRIBUTING.md](./CONTRIBUTING.md).
270
+
271
+ ## Security
272
+
273
+ See [SECURITY.md](./SECURITY.md).
274
+
275
+ ## License
276
+
277
+ [MIT](./LICENSE)