The module path, the CI pipeline and the self-updater all named GitHub. They now
name the Gitea instance everything else already runs on.
The workflows are rewritten rather than translated, for the reason recorded in
ci.yaml: Gitea's runner image is ubuntu:22.04, whose nodejs is Node 12, so no JS
action runs there -- actions/checkout@v4 dies with a SyntaxError before doing
anything. Every step is shell and checkout is a plain clone, which this public
repo needs no credential for. upload-artifact/download-artifact are JS actions
too, and there is no artifact store here, so the job that builds the binaries is
the job that publishes them.
internal/updater keeps its release and asset types unchanged: Gitea's release
payload carries the same tag_name, and its attachments the same name and
browser_download_url, so only the URL, the Accept header and one error string
move. The asset naming in release.yaml is load-bearing for that matching.
This does strand already-installed binaries, which still poll api.github.com.
The GitHub repository is left in place and untouched, so they report themselves
up to date rather than erroring; its last release is the bridge, and crossing it
is a one-time manual download.
Stats was the one full-screen view reached by a key of its own rather
than by tab, and the interface was less coherent for it. It is now a
section sitting third, after Alerts, and behaves like every other one:
tab in, tab out, r to refresh.
Three things fall out of the move. It auto-refreshes for the first time
— the tick handler skips every non-dashboard mode, which is why the
overlay never updated while it was open. Its error path no longer forces
the queue back into view on a failed fetch, an assumption that only made
sense while stats floated above the dashboard. And first-visit loading
keys off a statsLoaded flag rather than slice emptiness, because the
three empty slices a quiet server returns are a real answer, not a
missing one; the loading placeholder is likewise suppressed once
something has been drawn, so a background refresh cannot blank the page
out from under whoever is reading it.
The S key is gone, and with it the ability to peek at statistics from an
open incident and land back on it. That round-trip was the only thing
statsReturnMode bought, and it was the whole reason stats needed a mode.
terdut-server v0.4.0 splits the alerts row into two objects, and the
endpoints this client drove for acknowledgement, comments and archiving
are gone. Pointing the same screens at the new paths would have missed
the point of the split: alerts are now Alertmanager's record, read-only
and carrying no human state, while the incident is the thing anyone
actually works on.
Incidents lead the section list and are what the client opens on. The
queue shows severity, status, assignee and age, and the detail view adds
what only exists server-side now: the group labels Alertmanager
correlated on, the member alerts, and an append-only timeline where
system events and notes are interleaved. That timeline is the whole
history the server keeps — alert rows are still mutated in place — so
rendering it in order matters more than styling it.
Actions all move onto the incident: a/A acknowledge, s assign, z/Z
snooze, c note, d delete note, x archive, R resolve.
Two of those need care rather than a keybinding:
- R, not r, resolves, and it asks first. The server treats a manual
resolve as terminal: a later occurrence opens a new incident instead
of reopening this one, and an alert that never stops firing leaves
the incident closed for good. A stray keypress is not recoverable,
so the prompt says what it means.
- x refuses on an open incident rather than archiving it, since
archiving unresolved work only hides it. Snooze is offered as the
"not now" answer, and the client treats a snoozed_until in the past
as not snoozed, matching the server, which sweeps nothing.
Statistics lead with MTTA and MTTR, neither of which was computable
before. The server sends null until something has actually been
acknowledged or resolved, and that renders as — rather than 0: no data
is a different claim from instant.
Alerts keep a tab of their own as the raw feed — useful for asking what
Alertmanager is really sending — with an Incident column replacing Ack
By, and i in the detail view jumping to the incident where something can
be done about it. Archived now holds archived incidents; archiving an
alert is server-side housekeeping and no longer a user action.
BREAKING CHANGE: requires terdut-server v0.4.0 or later. Against an
older server every incident request 404s. Use terdut-tui v0.3.x with
servers before v0.4.0.
The alert list showed only Started, which comes from Prometheus and
never changes for the lifetime of an alert instance. A firing alert
that started 12 days ago looked identical whether Alertmanager
refreshed it 30 seconds ago or went silent a week ago.
terdut-server already tracks this: the webhook upsert sets
received_at on every accepted payload, including the periodic
re-sends issued at repeat_interval, and its archiver treats the
field as a liveness heartbeat. The field was already decoded into
api.Alert.ReceivedAt and simply never rendered.
Add a Last Seen column to the alert tables, rendered with the
existing humanAgo helper. The Alerts and Archived tabs share
alertColumns/alertRows, so both pick it up. The width budget is
re-derived for five columns; the slack constant now accounts for
all of bubbles' per-cell padding, so the table lands exactly on
the terminal width instead of overflowing by two columns as it
did with four.
The detail view gains a matching Last Seen line, with the timeline
labels widened to keep values aligned. Since received_at stops
advancing once an alert resolves, also pull through the server's
resolution_source and show it in the status header
(RESOLVED · alertmanager vs RESOLVED · expiry) so a frozen
timestamp is explained.
Sets up the full project structure following the hactl/gokapi-tui
architecture: strict Elm-pattern Bubbletea TUI, YAML config at
~/.config/terdut-tui/config.yaml, REST API client with Bearer auth,
self-update via GitHub Releases, and a three-section tab placeholder
(Alerts / Schedule / Users) that verifies server connectivity on startup.