Skip to content

Releases: kinncj/Heimdall

v2.7.3 — Tiny-viewport windowing fix

Choose a tag to compare

@kinncj kinncj released this 03 Jul 16:52
bbfbc1a

Fixed

  • Very short scroll viewports (1–2 rows) now show content instead of only a `▲/▼ more` marker. After the v2.7.2 windowing unification, a body overflowing a 1-row viewport could render just the marker and no content; the pane cursor could also be overwritten by an edge marker at a scrolled boundary. Both are fixed.

Full Changelog: v2.7.2...v2.7.3

v2.7.2 — Unify TUI windowing (internal)

Choose a tag to compare

@kinncj kinncj released this 03 Jul 15:48
ae519b3

Changed

  • Dashboard modals and detail view now scroll through the shared `pane.Window`; the duplicate `scrollWindow`/`keepSelVisible` are gone, so modals show the same `▲/▼ more · y/total` affordance as the top view. The unused pane `Filterable`/`Sortable` API was dropped (the dashboard keeps its own filter/sort idiom). No user-facing change. Closes #8.

Full Changelog: v2.7.1...v2.7.2

v2.7.1 — Ghostty over SSH shows the splash image

Choose a tag to compare

@kinncj kinncj released this 03 Jul 14:39
9fb1745

Fixed

  • Ghostty over SSH now shows the splash image, not the ASCII fallback. Image detection recognised Ghostty only by `TERM_PROGRAM=ghostty`, which SSH and tmux strip — so a dashboard run over SSH from Ghostty fell back to ASCII even though the terminal can render images. It now also treats `TERM=xterm-ghostty` (always forwarded) as Kitty-graphics-capable.

Full Changelog: v2.7.0...v2.7.1

v2.7.0 - Himinbjörg — one focus + scroll primitive for the TUI

Choose a tag to compare

@kinncj kinncj released this 03 Jul 14:24
4a23967

What's Changed

  • Himinbjörg: one focus + scroll primitive for the TUI by @kinncj in #7

Himinbjörg — one focus + scroll primitive for the TUI

Scrolling was implemented three times in the TUI and behaved differently in each
place; the full-screen top view (t) didn't scroll like the rest, selection lists
let the cursor drift off-screen, and the mouse wheel did nothing in the top view.
This introduces one shared primitive and moves the top view onto it.

Story: docs/stories/himinbjorg-focus-scroll-20260702235455-0021/Story.md
Design: docs/specs/himinbjorg-focus-scroll/design.md · ADR: docs/architecture/0023-tui-focus-scroll-pane-primitive.md

What's in it

  • New app/internal/tui/pane package — the primitive:
    • Pane: scroll, selection that follows the cursor, / filter, sort cycle,
      ▲/▼ more · y/total affordances, focus ring by border weight (survives NO_COLOR).
    • Group: grid layout (side-by-side panels), reading-order Tab, two-level
      page+pane scroll, pointer-targeted mouse, and a whole-page-first focus stop.
    • Capability interfaces (Filterable/Sortable) are opt-in — static panels get neither.
  • Top view (t) runs on the primitive. The whole view is the first focus (↑/↓ +
    wheel scroll the entire screen at any resolution); Tab steps the ring through each
    panel and wraps back; wheel/click target the panel under the pointer (was dead here);
    the wide 2-column grid is kept. topview's own scrollWindow copy is deleted.
  • Selection stays in view in the command / log-source / sort pickers (keepSelVisible).
  • Search / filter, one idiom (/), extended to every list: command picker (by
    name), command result (by output line), and the process view (by command) — on top
    of the existing log search. Each clears with esc and keeps the cursor in view.
  • Docs: new docs/guides/18-using-the-dashboard.md (drive the TUI after setup +
    a full keybindings table), corrected 12-top-view.md, updated in-app help (?).

Verification

  • 303 unit tests green across 29 packages (go test ./...); go vet clean.
  • New tests cover the pane math (clamp, keep-visible, page-auto-scroll), grid focus +
    mouse hit-testing, whole-page focus, and every new filter.
  • Top view verified with a headless render (grid alignment, focus ring, whole-page +
    page scroll).
  • Gates: Karpathy 87 (PASS_WITH_APPROVAL), a11y PASS (0 critical/serious,
    NO_COLOR-safe).

Deferred (tracked as a follow-up)

Migrating the remaining dashboard modal bodies onto pane.Group so the dashboard's
own scrollWindow copy can be deleted and the Filterable/Sortable API gets a
direct consumer. It's internal dedup with no user-facing change (log/cmd/process
filters already work via the dashboard's own idiom), so it's kept out of this PR to
avoid a large rewrite of a stable view. See the follow-up issue.

Full Changelog: v2.6.3...v2.7.0

v2.6.3

Choose a tag to compare

@kinncj kinncj released this 02 Jul 20:23
835e831

Standardization boundary + P/E core grouping fix

The fix you can see

The top view's P/E core grouping was computed in the dashboard, keyed off a metric field (Gauge) that the wire drops for per-core metrics — so every host fell back to the plain grid. The grouping now lives in the domain core and is derived from data that actually crosses the wire.

The architecture

Moved core grouping out of the views into domain.CoreGroups / domain.CoreTypeSummary (framework-free, tested once). The rule, now written down in ADR-0022 and a contributor guide:

Adapters translate platform specifics into neutral metrics · the domain core standardizes them · consumers (TUI, CLI, dashboard) render only.

  • CLI now reports core_groups (standardized P/E/LP with real core ids + util) — agents read structured groups, not a 12P + 4E string.
  • Rule codified in CLAUDE.md, AGENTS.md, Copilot instructions, a Cursor rule, and the architect agent across all harnesses.

Security

  • golang.org/x/net 0.51.0 → 0.55.0 — medium-severity HTML-parser DoS (Dependabot #1 / PR #6).

Update

  • heimdall-dashboard to see the grouped grid; heimdall-cli for core_groups. Daemons need no change for this.

v2.6.2

Choose a tag to compare

@kinncj kinncj released this 02 Jul 20:04
1959de0

Fix: top view showed the plain per-core grid instead of P/E grouping

The grouping keyed off cpu.topology's Gauge (the distinct-core-type count), but per-core metrics ride the protobuf per_core oneof — so the Gauge is dropped on the wire and the dashboard received it as 0, falling back to the unlabelled grid on every host.

It now derives the type count from the PerCore slice, which does cross the wire. Worked locally (--once) and in unit tests because the Gauge is set in-process; only the wire round-trip lost it. The cpu clusters: power line was never affected.

Update the heimdall-dashboard binary on the machine you watch from.

v2.6.1

Choose a tag to compare

@kinncj kinncj released this 02 Jul 19:52
d1df47b

Fix: CPU power blank on Linux/AMD hosts with a GPU

The daemon's in-process-first gate treated power.total as proof it already had CPU power. But power.total is synthesised from power.gpu on any GPU-equipped host — so the daemon short-circuited and never consulted the root helper for RAPL power.cpu. Result: power.cpu went blank on every Linux/AMD box with a GPU, even with the helper running.

The gate now checks for an actual CPU rail (power.cpu / power.pkg), not the whole-machine total. A non-root Linux daemon with a running helper reads RAPL again.

  • Regression from the v2.5.0 power standardization.
  • Apple (SMC/IOReport in-process) and Windows (Scaphandre in-process) were never affected.
  • ARM hosts with no RAPL (GB10) correctly stay a dash.

Update the heimdall-daemon binary on Linux/AMD hosts that have the root helper running.

v2.6.0

Choose a tag to compare

@kinncj kinncj released this 02 Jul 19:17
ff4dedd

Top view: per-core grid labelled by core type + per-cluster CPU power

  • P/E-labelled core grid. On hybrid silicon the top view groups per-core bars under P-cores (N): / E-cores (N): headers with real core ids. New unprivileged cpu.topology metric: sysctl hw.perflevel* (Apple Silicon — E-cluster owns the low ids, verified live on an M3 Max), cpu_core/cpu_atom sysfs (Intel hybrid Linux), EfficiencyClass (Windows). AMD / non-hybrid / ARM stay uniform and keep the plain grid.
  • Apple Pro/Max cluster power. The SMC P/E rails now ship as power.cpu.pcluster / power.cpu.ecluster; the POWER panel shows cpu clusters: P … W · E … W under the CPU figure. Hosts without cluster rails emit nothing — never a fabricated 0.
  • BC: new metric names only. Older daemons and dashboards render exactly as before.

Story 0028 · #5

v2.5.2

Choose a tag to compare

@kinncj kinncj released this 02 Jul 18:05
d0fd98b

Hardening: the Apple SMC CPU-power fallback can never show a garbage number on an unmapped chip.

Fixed

  • The SMC CPU cluster keys are verified on an M3 Max; on a different Apple die the same keys could mean something else. power.cpu from SMC is now rejected if the sum is implausible (NaN/Inf, negative, or > 200 W), so such a chip falls back to Unavailable rather than showing garbage. IOReport stays the first source (covers every base die), so this only affects the Pro/Max SMC fallback — no change on Linux (RAPL) or Windows (Scaphandre).

v2.5.1

Choose a tag to compare

@kinncj kinncj released this 02 Jul 17:58
a0af60d

Apple Pro/Max CPU power now covers the whole CPU, not just the P-cores.

Changed

  • power.cpu on Apple Pro/Max is the full CPU complex. The SMC CPU sum was PC02+PC42 (the two P-clusters only), which undercounted by missing the E-cores. It now also includes the E-core / cluster rails that scale with CPU load (PC03+PC43) — verified by sweeping the SMC keys under a full 16-core load on an M3 Max (memory PC32 and GPU PC1x/PC2x keys stay excluded). power.cpu reads ~18–20 W under load, labelled CPU complex (SMC).