Releases: Wigata-Intech/kay
Release list
v0.2.0
A major dashboard and fleet release. Fleet now keeps one persistent, self-healing
SSH connection per host; the Overview is a responsive, customisable multi-column
grid with eight panels and richer metrics (per-core CPU, swap, inodes,
connections, failed services, kernel/OS); the tui toolkit gained reusable,
extractable widgets; and a ? help overlay plus fleet drill-in round out the UX.
Changed
- Responsive Overview — the Overview now flows its panels into one, two, or
three columns depending on terminal width (≥105 cols → two, ≥160 → three),
filling the width with a divider between columns, laid out as an ordered grid
(row-major, honouring your panel order), and using width up to 200 cols instead
of the old 100-col cap. Customised layouts keep the multi-column rendering
(previously a custom layout dropped to a single stacked column). internal/tuigained reusable widgets —Bar,Gauge,Sparkline,
Columns,ColumnCount,HumanBytes,HumanDurationmoved out of the
dashboard so the toolkit stays UI-agnostic and reusable (domain colouring stays
in the dashboard).
Fixed
kay versionon local builds — when not built via GoReleaser it now falls
back to the VCS revision/date Go embeds (kay dev (rev abc1234, <date>, dirty))
instead of a baredev.
Added
-
?help overlay — press?in the dashboard orkay fleetfor a
full, context-grouped key-binding reference; any key closes it. Footers now
advertise? help. -
Better command help — every subcommand accepts
-h/--helpand prints its
flags cleanly (exit 0), andkaywith no arguments now leads with examples. -
More Overview panels & metrics — the batched metrics script (still one SSH
round-trip) now also collects per-core CPU, swap and cached memory,
inode usage per filesystem, TCP connection counts (/proc/net/sockstat),
failed systemd units, and the kernel / OS release. The Overview gains
dedicated Memory (RAM + swap + cached), Disk (space + inodes),
Connections (active / time-wait), and Services (failed units) panels; the
System panel shows a per-core level strip (core ▇▂▅▂) and the header shows the
OS. All eight panels are reorderable/hideable via theoeditor and now lay out
as an ordered grid (row-major, honouring your panel order) that fills the width
with a divider between columns. -
Customisable Overview — press
oin the dashboard's Overview tab to reorder
its panels (System, Top processes, Network, Docker) and hide the ones you don't
want:j/kselect,J/Kmove,spacetoggle,wsave,Esccancel. The
layout persists inconfig.jsonunder a newuisection and applies to every
host. The config file gains aversionfield; older files (no version) load
unchanged and are upgraded in place on the next save — no migration step, no
data loss. -
Fleet drill-in — press Enter on a host in
kay fleetto open its full
dashboard, and Esc/qto return to the overview; Ctrl-C (or SIGTERM) exits the
whole app. A single screen and input reader are shared for the session, so the
handoff is seamless (no flicker) and there are never two goroutines competing
for stdin. Internallyfleet.RunView/dashboard.RunViewrun a view against a
caller-owned screen + event channel;cmd/kaycoordinates the two.kay fleet
gains--read-onlyfor the drilled-in dashboard. -
Per-host fleet state — the fleet overview now collects each host
independently and streams results in as they arrive, so one slow or unreachable
host no longer freezes the whole view or blocks input. The overview is
interactive immediately; Enter on a host that is still connecting or offline
shows a brief message instead of drilling in, and only ready hosts open. -
Top containers (
docker stats) — presstin the dashboard's Docker tab
to open a live, sortable "top containers" overlay: CPU%, memory% (coloured),
memory usage, and net I/O per container, sorted by CPU (c) or memory (m),
withrto reload. The query is slow, so it runs on-demand and asynchronously
with a loading state (Esc cancels) — the periodic snapshot stays fast. -
Disk explorer — press Enter (or
l) on a mount in the dashboard's Disk tab
to drill into it: directories (recursivedusize) and files (size via
find) are listed largest-first, showing the name and extension.Enter/l/→
descends into a directory,h/←/Backspace goes up (never above the mount), and
Esc exits. Dotfiles are hidden by default;.toggles them and shown hidden
entries are dimmed and tagged. Opening a file raises a dismissable
"not supported" notice. Scans run on-demand over SSH, one level at a time, and
asynchronously with a loading state so the dashboard stays responsive on
large trees; keys are ignored mid-scan (except Esc to cancel). Paths are
single-quoted so names with spaces or shell metacharacters are inert. -
Vim-friendly keys — the dashboard is consistent across every tab and
overlay:h/j/k/lto move,g/Gfor ends,H/Lto switch tabs, and
Esc/qto back out.
Changed
-
Persistent fleet connections —
kay fleetnow keeps one long-lived,
self-healing SSH connection per host and reuses it for every refresh, instead
of dialing a brand-new connection each tick. Reusing the transport skips the
KEX + public-key-auth handshake on all but the first connect, which cuts CPU,
network round-trips, and — most visibly on the server — the connection churn
that spamsauth.logand pressures sshd'sMaxStartups. A shared dial cap
bounds concurrent connects so a large fleet's cold start can't self-throttle,
and reconnects use exponential backoff with jitter. Drilling into a host now
reuses the connection the fleet already established (no second handshake),
and the drilled-in dashboard inherits the connection's self-healing. New
internal/sshxtypesPoolandManagedimplement this, stdlib-only. -
Responsive startup — the dashboard's first metric collection now runs
asynchronously behind a "connecting…" screen instead of blocking, and both the
dashboard andkay fleetignore input (except quit) until the first data
arrives. Keys pressed during the initial 1–3 s connect no longer queue up and
fire when the view appears.
v0.1.2
Internal cleanup: no behavior change and no new features. Reduces duplication,
splits an oversized file, tightens package seams, and makes the interactive code
testable (total coverage 66.9% → 73.7%).
Changed
- Shared UI helpers — moved the duplicated
setColor,clampAll,
firstLine, and colour-threshold logic out ofdashboardandfleetinto the
tuitoolkit (SetColorMode,ClampAll,FirstLine,ThreshColor). No
behavior change; both views now share one source of truth for colour and
layout. - Split
dashboard.go— the 1200-line file is now four focused files in the
same package:dashboard.go(lifecycle + data),input.go(keys/actions),
render.go(view builders), andformat.go(pure formatting helpers). Pure
code move, no behavior change. - Unified the SSH seam —
dashboard.Clientis now an alias of
metrics.Runner, so the dashboard and the metrics collector share one
interface instead of two identical copies. - Split
tui.ListintoList+Pager— the selectable list and the
scrollable overlay were one dual-mode type gated by aselectableflag;
they are now two focused widgets (List.Render(w, h)drops the flag), which
removes the never-used pager branch from the list path. - Raised
sshxcoverage from ~48% to ~72% with white-box tests for the
non-interactive helpers (termType,classifyDialError,contains,
appendKnownHost,confirmHost, and thehostKeyCallbackpinning/rejection
paths). The remaining gap is interactive (Shell, terminal read). - Testability seams — extracted terminal-independent cores so the
interactive paths can be tested without a real TTY, with no behavior change:
the host-key TOFU prompt (confirmHost), the key passphrase decrypt path
(parseSigner), and the dashboard/fleet event loops (loop, driven by an
injectedscreeninterface and input/signal/tick channels). Total coverage
rose from ~67% to ~74% (dashboard 80%, fleet 62%, sshx 72%, keys 77%).
v0.1.1
Quality, tooling, and documentation hardening. No new features and no behavior
changes (one concurrency bug fixed).
Added
- CI quality gates —
lint(golangci-lint v2),gosec, andgovulncheck
jobs, mirrored locally bymake ci. gosec runs through thesetup-go
toolchain so CI matches local exactly. - Cyclomatic-complexity gate —
gocyclo(min-complexity 15) added to the
lint config; every function is now ≤15 (Go Report Card A+). - CodeQL advanced setup — a workflow + config carrying a query-filter for the
intentional, opt-in--insecurehost-key path. - Coverage tooling —
make cover/make cover-html; aCoverageworkflow
publishing a self-hosted shields badge (no external service); and a CI coverage
report with a 50% regression floor and a sticky per-package PR comment. RELEASING.md— maintainer guide for cutting a release.
Changed
- Reduced every function above cyclomatic complexity 15 to ≤15 via dispatch
tables and helper extraction, with no change in behavior. - Standardized tests — external black-box packages, table-driven, positive-then-
error ordering — and raised total coverage from 35.6% to 66.9%. - Relaxed the
go.moddirective togo 1.26(minor granularity).
Fixed
- License detection — replaced
LICENSEwith the canonical Apache-2.0 text
so pkg.go.dev reports Apache-2.0 instead of "UNKNOWN". - SSH client data race —
sshx.Client.Closereassigned thedonechannel
while the keepalive goroutine read it;Closenow closes the channel once via
sync.Onceand never reassigns it, so it is race-free and idempotent.
Security
- Added audited
//#nosecdirectives for the intentional paths: G106
(--insecureopt-in), G304 (reads from kay's own key/config store), and G306
(world-readable.pub).