Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ jobs:
with:
go-version: '1.22'
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v8
with:
version: latest
version: v2.5.0
args: --timeout=5m
- name: Check formatting
run: |
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ RELEASE.md

# Go build artifacts
bin/
sysgreet
/sysgreet
*.test
*.exe
*.exe~
Expand Down
80 changes: 44 additions & 36 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,46 +1,54 @@
version: "2"
run:
timeout: 5m
tests: true
modules-download-mode: readonly

tests: true
linters:
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- gofmt
- goimports
- misspell
- unconvert
- unparam
- copyloopvar
- goconst
- gocyclo
- gosec
- copyloopvar

linters-settings:
gocyclo:
min-complexity: 15
goconst:
min-len: 3
min-occurrences: 3
misspell:
locale: US

- misspell
- unconvert
- unparam
settings:
goconst:
min-len: 3
min-occurrences: 3
gocyclo:
min-complexity: 15
misspell:
locale: US
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- gocyclo
- gosec
- unparam
path: _test\.go
- linters:
- staticcheck
text: cgo-gcc-prolog
paths:
- third_party$
- builtin$
- examples$
issues:
exclude-rules:
# Exclude some linters from running on tests files
- path: _test\.go
linters:
- gocyclo
- gosec
- unparam
# Ignore CGO warnings from dependencies
- text: "cgo-gcc-prolog"
linters:
- staticcheck
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# Changelog

## v1.1.0

### Added

- **Width-aware rendering** - Sysgreet now detects the terminal width and guarantees the banner never wraps mid-glyph. When the configured font is too wide it steps down gracefully: drop the domain from the hostname (the full name moves to an info line), try a narrower font, and finally render a clean single-line ruled header. Narrow tmux panes and phone SSH sessions stay readable.
- **`Small` font** - A narrower FIGlet font (from the standard figlet distribution) embedded as the last art step before the plain-header fallback.
- **Truecolor gradients** - On terminals advertising `COLORTERM=truecolor`, gradient stops are interpolated into a smooth 24-bit fade. 16-color terminals keep the existing per-line cycling.
- **`--json` flag** - Emit the banner as structured JSON for scripting (section data includes raw percentages for thresholding in pipelines). Never prompts for bootstrap.
- **New flags** - `--font` (per-run font override), `--width` (assume a terminal width), `--no-color`, `--config` (explicit config path), `--list-fonts`.
- **`layout.max_width`** - Config key (and `SYSGREET_LAYOUT_MAX_WIDTH`) to cap banner width below the detected terminal size.
- **Windows legacy console support** - Virtual terminal processing is enabled before writing escapes; when the console refuses, output falls back to plain text instead of printing raw escape codes.

### Fixed

- **`NO_COLOR` now covers the whole banner** - Previously the hostname art kept its gradient with `NO_COLOR` set; escape sequences are now fully suppressed, including when output is piped or `TERM=dumb`.
- **Piped output is plain** - `sysgreet > motd.txt` no longer embeds ANSI codes; color is keyed off whether stdout is a terminal.
- **`--text` and `--demo` honor your config** - Both modes previously ignored the config file, so custom fonts and gradients silently didn't apply.
- **Compact mode is actually compact** - `layout.compact` now emits a true single line using the plain hostname instead of embedding the multi-line art.
- **Unknown fonts fall back deterministically** - A typo in `ascii.font` now falls back to the default font (logged under `SYSGREET_DEBUG`) instead of picking a random font every login.
- **Long body lines clip cleanly** - Info lines that exceed the terminal width are truncated with an ellipsis instead of wrapping.

### Changed

- **Collectors run concurrently** - All five collectors gather in parallel under a shared 250 ms deadline, so a slow metric source can never hang a login. Windows logins no longer pay the 100 ms CPU sample serially.
- **One color palette** - The ANSI color tables previously duplicated (and drifted) across packages now live in a single `internal/terminal` package alongside width and capability detection.

## v0.9.1

### Added
Expand Down
15 changes: 14 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ sysgreet/
│ ├── collectors/ # System data collectors
│ ├── config/ # Configuration loading
│ ├── network/ # Network utilities
│ └── render/ # Layout and color rendering
│ ├── render/ # Layout, clipping, and JSON rendering
│ └── terminal/ # Terminal width/color detection, ANSI palette
├── test/
│ ├── benchmarks/ # Performance benchmarks
│ └── integration/ # Platform-specific integration tests
Expand Down Expand Up @@ -199,6 +200,18 @@ Sysgreet has strict performance requirements:

When adding new collectors or features, ensure they don't violate these constraints.

Collectors run concurrently inside `Providers.Gather` under a shared 250 ms
deadline, so honor the `context.Context` you receive — a collector that
ignores cancellation can still delay a login.

## Output Rules

- Never print wider than the terminal. The ascii renderer receives a
`MaxWidth` and walks a fallback ladder; anything you add to the banner body
is clipped by the render layer. Don't bypass either.
- All color must flow through `internal/terminal` so `NO_COLOR`, `TERM=dumb`,
piped output, and Windows console quirks stay handled in one place.

## Documentation

### README Updates
Expand Down
55 changes: 48 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,26 @@ network or depending on external runtimes.

- **Single static binary** - Go 1.22+, no CGO, no daemons, no service
dependencies.
- **Fits any terminal** - Sysgreet measures the terminal before printing and
steps the banner down gracefully (shorter hostname, then a narrower font,
then a clean one-line header) instead of wrapping ASCII art into garbage.
Split tmux panes and phone SSH sessions stay readable.
- **Cross-platform parity** - Linux/macOS show load averages; Windows surfaces
CPU usage. Interface filtering avoids noisy virtual adapters everywhere.
CPU usage (and legacy consoles get plain text instead of raw escape codes).
Interface filtering avoids noisy virtual adapters everywhere.
- **Configurable yet optional** - YAML or TOML profiles toggle sections, pick
fonts/colors, set layout order, and cap the interface list. Defaults "just
work" with zero files.
- **Graceful degradation** - Missing metrics or SSH metadata simply fall back;
the banner keeps rendering.
- **Performance-guarded** - Startup benchmark (<50 ms median, <80 ms p95) runs in
CI; process RSS stays <15 MB.
- **Professional aesthetics** - Unicode block fonts with gradient colors,
automatic monochrome fallback, 80-column mindful layout.
- **Performance-guarded** - Collectors run in parallel under a hard 250 ms
deadline; the startup benchmark (<50 ms median, <80 ms p95) runs in CI and
process RSS stays <15 MB.
- **Professional aesthetics** - Unicode block fonts with gradient colors —
smooth 24-bit fades on truecolor terminals — plus automatic monochrome
fallback and full `NO_COLOR` support.
- **Script-friendly** - `--json` emits the same data as structured JSON;
piped output is always plain text.

---

Expand Down Expand Up @@ -107,6 +116,19 @@ sysgreet --disable
sysgreet --text "Production DB"
sysgreet --text "Coffee Break"
sysgreet --text "Deploy Day"

# JSON mode - structured output for scripts (no art, no prompts)
sysgreet --json | jq -r '.hostname'
```

**Useful flags:**

```bash
sysgreet --list-fonts # Print the embedded fonts
sysgreet --font "ANSI Shadow" # One-off font override
sysgreet --width 60 # Preview how a 60-column session renders
sysgreet --no-color # Plain output (NO_COLOR works too)
sysgreet --config ~/alt.yaml # Point at a specific config file
```

> **Tip:** Use `--text` to create custom banners for different environments, reminders, or just for fun. Great for distinguishing production boxes, marking maintenance windows, or adding personality to your terminals.
Expand All @@ -119,7 +141,10 @@ sysgreet --text "Deploy Day"

Sysgreet looks for configuration in this order:

1. `SYSGREET_CONFIG` environment variable (absolute or `~/` paths)
1. `--config` flag or `SYSGREET_CONFIG` environment variable (absolute or
`~/` paths). An explicit path is exclusive — if the file is missing,
sysgreet uses built-in defaults rather than silently reading another
config.
2. `~/.config/sysgreet/config.yaml` (or `.yml`, `.toml`)
3. `~/.sysgreet.yaml` / `.toml`

Expand Down Expand Up @@ -147,6 +172,7 @@ display:

layout:
compact: false
max_width: 0 # cap banner width in columns; 0 = detected terminal width
sections: ["header", "network", "system", "resources"]

network:
Expand Down Expand Up @@ -182,12 +208,28 @@ Environment variables override everything (e.g.
yellow, ≥90% in red). Windows surfaces realtime CPU usage; Unix hosts show load
averages.

### Terminal width handling

The hostname art is only printed when it actually fits. On narrow terminals
sysgreet steps down automatically:

1. Full hostname in your configured font
2. Hostname without the domain (`pve1.home.lan` → `PVE1`, with the full name
kept on an info line)
3. Progressively narrower fonts (`standard`, then `Small`)
4. A single ruled line — `═════ PVE1 ═════` — that fits any width

Set `layout.max_width` to cap the width below what the terminal reports, or
pass `--width` to preview a specific size.

---

## Performance guarantees

- **Startup** - `< 50 ms` median, `< 80 ms` p95 (validated by
`go test -bench Startup ./test/benchmarks`)
- **Never hangs a login** - Collectors run concurrently under a shared 250 ms
deadline; a stuck metric source just drops its section
- **Binary footprint** - `< 10 MB` for all release targets (GoReleaser checks)
- **Runtime memory** - `< 15 MB` RSS for default banner
- **No network activity** - All data collected locally, offline-safe
Expand Down Expand Up @@ -237,7 +279,6 @@ platform-specific improvements before diving in.

## Roadmap

- Optional JSON output for scripting in CI/CD pipelines
- Extended GPU/storage telemetry for workstation profiles
- Pluggable section framework (e.g., Kubernetes context, vault status)
- Prebuilt Windows installer for enterprise onboarding
Expand Down
Loading
Loading