Skip to content

feat(status-bar): add /battery toggle for a color-coded battery read-out - #68860

Merged
OutThisLife merged 2 commits into
mainfrom
bb/battery-status
Jul 21, 2026
Merged

feat(status-bar): add /battery toggle for a color-coded battery read-out#68860
OutThisLife merged 2 commits into
mainfrom
bb/battery-status

Conversation

@OutThisLife

Copy link
Copy Markdown
Collaborator

Summary

Adds an opt-in battery indicator to the CLI and TUI status bars, rendered as the first element and color-coded by charge — the way many shell prompts show it. Off by default; a no-op on machines without a battery (desktops/servers/VMs).

  • ⚡ 82% while charging, 🔋 82% on battery.
  • Colors: green (>50% or charging) → yellow (≤50%) → orange (≤20%) → red (≤10%), reusing the existing status-bar style classes / theme colors.

What's in it

  • agent/battery.py — a small shared, psutil-backed reader (psutil is already a dependency). Memoises the reading for a few seconds so the status bar can poll it on every repaint cheaply, buckets the level into a color category, and formats a compact label. Every failure path degrades to "unavailable" and simply renders nothing.
  • CLI/battery [on|off|status] toggles the read-out and persists to display.battery (survives restarts). Prepended ahead of the marker in every status-bar width tier (both the fragment and plain-text renderers).
  • TUI/battery slash command, display.battery config sync, a system.battery JSON-RPC method that returns the reading, a poller that runs only while the indicator is enabled, and a pinned first segment in StatusRule (width-budgeted so it never crushes model/context).
  • Docs entry in website/docs/reference/slash-commands.md.

Footprint

No new core model tool and no new .env var — this is a display setting in config.yaml (display.battery, default false) toggled by a CLI-only slash command, consistent with /statusbar, show_cost, etc.

Test plan

  • tests/agent/test_battery.py — reader (no psutil / no battery / clamp / cache) + category thresholds + label/glyph.
  • tests/test_tui_gateway_server.pysystem.battery (reading + fail-open) and config.set battery (toggle + explicit off).
  • ui-tui vitest — StatusRule battery rendering/coloring/omission + toBatteryInfo coercion.
  • npm run typecheck + eslint clean on changed TUI files.
  • Existing CLI status-bar and command-registry suites still green.
  • Manual: /battery on on a laptop (charging + on battery), and confirm it's a no-op on a desktop.

Add an opt-in battery indicator to the CLI and TUI status bars, shown as
the first element and colour-coded by charge (green/yellow/orange/red, or
green while charging). Off by default and a no-op on machines without a
battery.

- agent/battery.py: shared psutil-backed reader with a short TTL cache,
  category bucketing, and a compact 🔋/⚡ label. Fails open to
  "unavailable" everywhere.
- CLI: /battery [on|off|status] toggle persisted to display.battery,
  rendered first in every status-bar width tier.
- TUI: /battery slash command, config sync, a system.battery RPC polled
  while enabled, and a pinned first segment in StatusRule.
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

running on 3c2903a

looks good to me!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an opt-in, color-coded battery indicator to Hermes’ CLI and TUI status bars, backed by a shared psutil reader and surfaced via a new /battery toggle plus a TUI JSON-RPC endpoint.

Changes:

  • Introduces agent/battery.py to read/cache battery state and derive a color category + compact label.
  • Wires the battery segment into the CLI status bar (text + fragments) and adds /battery [on|off|status] with persistence via display.battery.
  • Adds TUI support via system.battery, a polling hook, status-bar rendering updates, and accompanying Python/TS tests + docs.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
agent/battery.py New shared battery reader/category/formatter with short TTL caching.
cli.py Adds /battery handler, persists display.battery, and prepends battery segment in status bar rendering.
hermes_cli/commands.py Registers the new CLI-only /battery slash command.
hermes_cli/config.py Adds display.battery default config key (off by default).
tui_gateway/server.py Adds system.battery RPC and supports config.set for battery persistence.
tests/agent/test_battery.py Unit tests for battery reading/clamping/caching, category thresholds, and formatting.
tests/test_tui_gateway_server.py Tests system.battery fail-open behavior and config.set battery persistence.
ui-tui/src/gatewayTypes.ts Adds display.battery typing and SystemBatteryResponse RPC type.
ui-tui/src/app/interfaces.ts Introduces BatteryInfo / BatteryCategory and stores them in UiState.
ui-tui/src/app/uiStore.ts Initializes battery UI state (battery, batteryStatus).
ui-tui/src/app/useConfigSync.ts Syncs display.battery from gateway config into UI state.
ui-tui/src/app/useBatteryPoll.ts New polling hook + coercion helper for system.battery payloads.
ui-tui/src/app/useMainApp.ts Enables the battery poller alongside other config-driven hooks.
ui-tui/src/app/slash/commands/core.ts Adds TUI /battery command to toggle the indicator and persist via config.set.
ui-tui/src/components/appLayout.tsx Plumbs battery state into StatusRule.
ui-tui/src/components/appChrome.tsx Renders a pinned first battery segment with category-based coloring.
ui-tui/src/__tests__/useBatteryPoll.test.ts Tests payload coercion/clamping and category normalization.
ui-tui/src/__tests__/appChromeStatusRule.test.tsx Verifies StatusRule battery segment rendering/coloring/omission behavior.
website/docs/reference/slash-commands.md Documents /battery and marks it CLI-only in the notes section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ui-tui/src/app/slash/commands/core.ts
Comment thread ui-tui/src/components/appChrome.tsx
Comment thread tui_gateway/server.py Outdated
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 21, 2026
- TUI /battery matches the CLI surface: adds `status` (live reading via
  system.battery), and the help/usage strings now consistently read
  [on|off|status].
- batteryLabel() renders `--` for an unknown percent so a null can never
  surface as "null%" even without the showBattery guard.
- Move the system.battery RPC out of the config section into
  "Methods: tools & system" where system.* RPCs belong.
@OutThisLife
OutThisLife merged commit 413ed6b into main Jul 21, 2026
82 of 85 checks passed
@OutThisLife
OutThisLife deleted the bb/battery-status branch July 21, 2026 20:33
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
…atus

feat(status-bar): add /battery toggle for a color-coded battery read-out
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants