From fb38a8576c9e2a7f49cdaec4f8a660b70c7f90b3 Mon Sep 17 00:00:00 2001 From: xscriptor Date: Tue, 3 Nov 2026 14:29:59 +0100 Subject: [PATCH 1/4] feat: add machine-readable addon catalog Add root index.json covering all plugins with a deterministic generator at scripts/generate_catalog.py. The generator supports --check for stale-catalog detection and derives native metadata from Cargo.toml and wasm metadata from xfetch-plugin.json. No plugin code or manifests changed. --- CHANGELOG.md | 7 ++ index.json | 220 +++++++++++++++++++++++++++++++++ scripts/generate_catalog.py | 234 ++++++++++++++++++++++++++++++++++++ 3 files changed, 461 insertions(+) create mode 100644 index.json create mode 100755 scripts/generate_catalog.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 13d03b1..edf0ba9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 2026-11-03 — Addon catalog index + +- Added the root `index.json`, a machine-readable addon catalog consumed by `xfetch plugin search` and the other remote addon discovery commands. +- Added `scripts/generate_catalog.py` to regenerate the catalog from each plugin's `Cargo.toml` or `xfetch-plugin.json`; `--check` fails when the committed index is stale. +- The catalog lists all 20 addons, sorted by name. Native entries use `runtime: "native"` and WebAssembly entries use `runtime: "wasm"` with their manifest capabilities preserved. +- No plugin code or manifests changed. Crate versions remain 0.2.0 (except the existing `banner-text` 0.1.0); only the catalog version is 1.0.2. + ## 2026-10-24 — Dependency security automation - Added `.github/workflows/security-audit.yml`: runs `cargo audit` 0.22.2 with `--deny warnings` on push, pull request and a weekly schedule, with actions pinned by commit SHA and no persisted checkout credentials. diff --git a/index.json b/index.json new file mode 100644 index 0000000..4cd0690 --- /dev/null +++ b/index.json @@ -0,0 +1,220 @@ +{ + "schema_version": 1, + "catalog_version": "1.0.2", + "entries": [ + { + "name": "animate-logo", + "description": "Xfetch plugin that animates the logo with user-controlled frames and duration", + "version": "0.2.0", + "kind": "logo_animation", + "runtime": "native", + "path": "plugins/animate-logo", + "install": "animate-logo" + }, + { + "name": "banner", + "description": "Xfetch logo-animation plugin that prints a Chinese/Japanese proverb banner under (or above) the logo", + "version": "0.2.0", + "kind": "logo_animation", + "runtime": "native", + "path": "plugins/banner", + "install": "banner" + }, + { + "name": "banner-text", + "description": "Xfetch info plugin that emits text lines from a file or literal argument", + "version": "0.1.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/banner-text", + "install": "banner-text" + }, + { + "name": "chocolatey", + "description": "Xfetch plugin that counts locally installed Chocolatey packages", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/chocolatey", + "install": "chocolatey" + }, + { + "name": "display-resolution", + "description": "Xfetch plugin that reports the display resolution via xrandr/wayland probes", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/display-resolution", + "install": "display-resolution" + }, + { + "name": "docker", + "description": "Xfetch plugin that reports Docker status and containers from the local daemon", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/docker", + "install": "docker" + }, + { + "name": "gauges", + "description": "Xfetch plugin that renders memory, swap, disk and battery usage as progress bars", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/gauges", + "install": "gauges" + }, + { + "name": "github-stats", + "description": "Xfetch plugin that shows GitHub statistics via the GitHub API", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/github-stats", + "install": "github-stats" + }, + { + "name": "langs", + "description": "Xfetch plugin that shows the languages of a repository or an org/user with glyphs and brand colors", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/langs", + "install": "langs" + }, + { + "name": "music-player", + "description": "Xfetch plugin that shows the current track via playerctl/mpd/Spotify probes", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/music-player", + "install": "music-player" + }, + { + "name": "temperature", + "description": "Xfetch plugin that shows CPU temperature from hwmon/sensors probes", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/temperature", + "install": "temperature" + }, + { + "name": "theme-detection", + "description": "Xfetch plugin that detects the system color theme (GTK/KDE Plasma)", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/theme-detection", + "install": "theme-detection" + }, + { + "name": "theme-manager", + "description": "Xfetch plugin that fetches and manages themes from the XFetch registry", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/theme-manager", + "install": "theme-manager" + }, + { + "name": "timezone", + "description": "Xfetch plugin that shows the current timezone via local probes", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/timezone", + "install": "timezone" + }, + { + "name": "user-info", + "description": "Xfetch plugin that shows user account information from local probes", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/user-info", + "install": "user-info" + }, + { + "name": "wasm-crypto", + "description": "Crypto spot prices (Coinbase) fetched through the sandboxed HTTP host call", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "wasm", + "guest_runtime": "core", + "path": "plugins/wasm-crypto", + "install": "wasm-crypto", + "capabilities": { + "http": { + "allow": [ + "https://api.coinbase.com/*" + ] + } + } + }, + { + "name": "wasm-ip-geo", + "description": "Public IP, location, network and timezone via ipapi.co (Python component)", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "wasm", + "guest_runtime": "component", + "path": "plugins/wasm-ip-geo", + "install": "wasm-ip-geo", + "capabilities": { + "http": { + "allow": [ + "https://ipapi.co/*" + ] + } + } + }, + { + "name": "wasm-pacman", + "description": "Package counts (repository vs AUR/foreign) from the local pacman database", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "wasm", + "guest_runtime": "core", + "path": "plugins/wasm-pacman", + "install": "wasm-pacman", + "capabilities": { + "exec": { + "allow": [ + "pacman" + ] + } + } + }, + { + "name": "wasm-proc", + "description": "Load average, memory usage and uptime read from /proc (freestanding C)", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "wasm", + "guest_runtime": "core", + "path": "plugins/wasm-proc", + "install": "wasm-proc", + "capabilities": { + "fs": [ + { + "host": "/proc", + "guest": "/proc", + "mode": "ro" + } + ] + } + }, + { + "name": "weather", + "description": "Xfetch plugin that shows the current weather from wttr.in", + "version": "0.2.0", + "kind": "info_provider", + "runtime": "native", + "path": "plugins/weather", + "install": "weather" + } + ] +} diff --git a/scripts/generate_catalog.py b/scripts/generate_catalog.py new file mode 100755 index 0000000..7eb028c --- /dev/null +++ b/scripts/generate_catalog.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 +"""Generate the machine-readable addon catalog at the repository root. + +Every addon lives in ``plugins//`` and is either a native plugin with a +``Cargo.toml`` or a WebAssembly plugin with an ``xfetch-plugin.json`` manifest. +The catalog only carries discovery metadata; installation still reads the +plugin manifest, so this file cannot grant capabilities by itself. + +Usage: + python3 scripts/generate_catalog.py + python3 scripts/generate_catalog.py --check + +``--check`` exits non-zero when ``index.json`` differs from what the generator +would write, which makes stale catalogs easy to catch in CI. +""" + +from __future__ import annotations + +import argparse +import json +import sys +import tomllib +from pathlib import Path +from typing import Any + +ROOT = Path(__file__).resolve().parent.parent +PLUGINS_DIR = ROOT / "plugins" +CATALOG_PATH = ROOT / "index.json" + +SCHEMA_VERSION = 1 +CATALOG_VERSION = "1.0.2" +NATIVE_PACKAGE_PREFIX = "xfetch-plugin-" +LOGO_ANIMATION_PLUGINS = frozenset({"animate-logo", "banner"}) +GUEST_RUNTIMES = frozenset({"core", "component"}) + + +class CatalogError(Exception): + """A plugin directory cannot be turned into a catalog entry.""" + + +def _read_json(path: Path) -> dict[str, Any]: + try: + with path.open("r", encoding="utf-8") as handle: + data = json.load(handle) + except (OSError, json.JSONDecodeError) as err: + raise CatalogError(f"cannot read {path.relative_to(ROOT)}: {err}") from err + if not isinstance(data, dict): + raise CatalogError(f"{path.relative_to(ROOT)} must contain a JSON object") + return data + + +def _read_cargo_package(path: Path) -> dict[str, Any]: + try: + with path.open("rb") as handle: + data = tomllib.load(handle) + except (OSError, tomllib.TOMLDecodeError) as err: + raise CatalogError(f"cannot read {path.relative_to(ROOT)}: {err}") from err + package = data.get("package") + if not isinstance(package, dict): + raise CatalogError(f"{path.relative_to(ROOT)} has no [package] table") + return package + + +def _required_string(mapping: dict[str, Any], key: str, source: Path) -> str: + value = mapping.get(key) + if not isinstance(value, str) or not value.strip(): + raise CatalogError( + f"{source.relative_to(ROOT)} is missing a non-empty '{key}'" + ) + return value.strip() + + +def _wasm_entry(directory: Path) -> dict[str, Any]: + manifest_path = directory / "xfetch-plugin.json" + manifest = _read_json(manifest_path) + + name = _required_string(manifest, "name", manifest_path) + if name != directory.name: + raise CatalogError( + f"{manifest_path.relative_to(ROOT)} names '{name}' but lives in " + f"'{directory.name}'" + ) + + kind = _required_string(manifest, "kind", manifest_path) + version = _required_string(manifest, "version", manifest_path) + description = _required_string(manifest, "description", manifest_path) + + capabilities = manifest.get("capabilities") + if not isinstance(capabilities, dict): + raise CatalogError( + f"{manifest_path.relative_to(ROOT)} is missing a 'capabilities' object" + ) + + guest_runtime = manifest.get("runtime") + if guest_runtime not in GUEST_RUNTIMES: + raise CatalogError( + f"{manifest_path.relative_to(ROOT)} has unsupported runtime " + f"{guest_runtime!r}; expected 'core' or 'component'" + ) + + return { + "name": name, + "description": description, + "version": version, + "kind": kind, + "runtime": "wasm", + "guest_runtime": guest_runtime, + "path": f"plugins/{name}", + "install": name, + "capabilities": capabilities, + } + + +def _native_entry(directory: Path) -> dict[str, Any]: + cargo_path = directory / "Cargo.toml" + package = _read_cargo_package(cargo_path) + + package_name = _required_string(package, "name", cargo_path) + expected_name = f"{NATIVE_PACKAGE_PREFIX}{directory.name}" + if package_name != expected_name: + raise CatalogError( + f"{cargo_path.relative_to(ROOT)} package name '{package_name}' does " + f"not match directory '{directory.name}' (expected '{expected_name}')" + ) + + version = _required_string(package, "version", cargo_path) + description = _required_string(package, "description", cargo_path) + kind = "logo_animation" if directory.name in LOGO_ANIMATION_PLUGINS else "info_provider" + + return { + "name": directory.name, + "description": description, + "version": version, + "kind": kind, + "runtime": "native", + "path": f"plugins/{directory.name}", + "install": directory.name, + } + + +def _is_native_plugin(directory: Path) -> bool: + cargo_path = directory / "Cargo.toml" + if not cargo_path.is_file(): + return False + try: + with cargo_path.open("rb") as handle: + package = tomllib.load(handle).get("package") + except (OSError, tomllib.TOMLDecodeError): + return False + if not isinstance(package, dict): + return False + name = package.get("name") + return isinstance(name, str) and name.startswith(NATIVE_PACKAGE_PREFIX) + + +def collect_entries() -> list[dict[str, Any]]: + """Return catalog entries sorted by addon name.""" + if not PLUGINS_DIR.is_dir(): + raise CatalogError("plugins/ directory not found") + + entries: list[dict[str, Any]] = [] + for directory in sorted(PLUGINS_DIR.iterdir(), key=lambda path: path.name): + if not directory.is_dir() or directory.name.startswith("."): + continue + if (directory / "xfetch-plugin.json").is_file(): + entries.append(_wasm_entry(directory)) + elif _is_native_plugin(directory): + entries.append(_native_entry(directory)) + + entries.sort(key=lambda entry: entry["name"]) + names = [entry["name"] for entry in entries] + duplicates = sorted({name for name in names if names.count(name) > 1}) + if duplicates: + raise CatalogError(f"duplicate catalog entries: {', '.join(duplicates)}") + if not entries: + raise CatalogError("no addons found under plugins/") + return entries + + +def render_catalog(entries: list[dict[str, Any]]) -> str: + catalog = { + "schema_version": SCHEMA_VERSION, + "catalog_version": CATALOG_VERSION, + "entries": entries, + } + return json.dumps(catalog, indent=2, ensure_ascii=False) + "\n" + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description="Generate or verify the repository addon catalog." + ) + parser.add_argument( + "--check", + action="store_true", + help="fail if index.json is missing or out of date instead of writing it", + ) + args = parser.parse_args(argv) + + try: + entries = collect_entries() + except CatalogError as err: + print(f"error: {err}", file=sys.stderr) + return 1 + + rendered = render_catalog(entries) + + if args.check: + try: + current = CATALOG_PATH.read_text(encoding="utf-8") + except OSError as err: + print(f"error: cannot read index.json: {err}", file=sys.stderr) + return 1 + if current != rendered: + print( + "error: index.json is stale; run " + "python3 scripts/generate_catalog.py", + file=sys.stderr, + ) + return 1 + print(f"index.json is up to date ({len(entries)} entries).") + return 0 + + try: + CATALOG_PATH.write_text(rendered, encoding="utf-8") + except OSError as err: + print(f"error: cannot write index.json: {err}", file=sys.stderr) + return 1 + print(f"Wrote index.json ({len(entries)} entries).") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 3c2c7a129e95109881af941b6f1f145898f9b55b Mon Sep 17 00:00:00 2001 From: xscriptor Date: Tue, 3 Nov 2026 14:50:43 +0100 Subject: [PATCH 2/4] chore(deps): update workspace dependencies and migrate gauges to sysinfo 0.40 - Apply the remaining semver-compatible lockfile patches. - Move gauges 0.2.1 to sysinfo 0.40.1 and adapt the fallible constructors and the removal of Disks::list(). - Move theme-manager 0.2.1 to dirs 7. - Update the security-audit workflow actions and regenerate the catalog. --- .github/workflows/security-audit.yml | 4 +- CHANGELOG.md | 8 +++ Cargo.lock | 76 ++++++++++------------------ index.json | 4 +- plugins/gauges/Cargo.toml | 4 +- plugins/gauges/src/main.rs | 13 +++-- plugins/theme-manager/Cargo.toml | 4 +- 7 files changed, 50 insertions(+), 63 deletions(-) diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 89b1c76..bf63ec0 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -20,12 +20,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Install stable Rust toolchain - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable + uses: dtolnay/rust-toolchain@18f0487477426dce244608110aa2660c2893deb7 # stable with: toolchain: stable diff --git a/CHANGELOG.md b/CHANGELOG.md index edf0ba9..60105d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2026-11-03 — Dependency updates + +- Updated the workspace lockfile with semver-compatible patches: `libc` 0.2.191, `libredox` 0.1.25, `objc2` 0.6.5, `redox_users` 0.5.3, `serde_json` 1.0.154, `syn` 3.0.9, `thiserror` 2.0.21, `thiserror-impl` 2.0.21 and `unicode-ident` 1.0.27. +- `gauges` 0.2.1: moved to `sysinfo` 0.40.1 and adapted the fallible constructors and the removal of `Disks::list()`. The measurements and output format are unchanged. +- `theme-manager` 0.2.1: moved to `dirs` 7.0.0. The `dirs::config_dir()` call is unchanged. +- Updated the security-audit workflow to `actions/checkout` 7.0.1 and the pinned `dtolnay/rust-toolchain` commit. +- Regenerated `index.json` so the catalog reports the new `gauges` and `theme-manager` versions. + ## 2026-11-03 — Addon catalog index - Added the root `index.json`, a machine-readable addon catalog consumed by `xfetch plugin search` and the other remote addon discovery commands. diff --git a/Cargo.lock b/Cargo.lock index 0e55c90..d772adb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,17 +14,11 @@ version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - [[package]] name = "dirs" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f" dependencies = [ "dirs-sys", ] @@ -51,17 +45,6 @@ dependencies = [ "objc2", ] -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "itoa" version = "1.0.18" @@ -70,15 +53,15 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "libc" -version = "0.2.189" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "libredox" -version = "0.1.20" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ "libc", ] @@ -100,9 +83,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +checksum = "08849bbd4767dfae9457696856ae1c84fe4e0281bbe4a7abff2d0e06fb7981f8" dependencies = [ "objc2-encode", ] @@ -181,11 +164,10 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" dependencies = [ - "getrandom", "libredox", "thiserror", ] @@ -217,14 +199,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -246,9 +228,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -257,9 +239,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.39.6" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2071df9448915b71c4fe6d25deaf1c22f12bd234f01540b77312bb8e41361e6" +checksum = "0e8a3edbe0394ce115f3917a00349dd242be09eb5a091ed509eaf67b55cfb8a8" dependencies = [ "libc", "memchr", @@ -272,35 +254,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.20" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.20" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "winapi" @@ -517,7 +493,7 @@ dependencies = [ [[package]] name = "xfetch-plugin-gauges" -version = "0.2.0" +version = "0.2.1" dependencies = [ "serde", "sysinfo", @@ -571,7 +547,7 @@ dependencies = [ [[package]] name = "xfetch-plugin-theme-manager" -version = "0.2.0" +version = "0.2.1" dependencies = [ "dirs", "serde", diff --git a/index.json b/index.json index 4cd0690..cd61989 100644 --- a/index.json +++ b/index.json @@ -59,7 +59,7 @@ { "name": "gauges", "description": "Xfetch plugin that renders memory, swap, disk and battery usage as progress bars", - "version": "0.2.0", + "version": "0.2.1", "kind": "info_provider", "runtime": "native", "path": "plugins/gauges", @@ -113,7 +113,7 @@ { "name": "theme-manager", "description": "Xfetch plugin that fetches and manages themes from the XFetch registry", - "version": "0.2.0", + "version": "0.2.1", "kind": "info_provider", "runtime": "native", "path": "plugins/theme-manager", diff --git a/plugins/gauges/Cargo.toml b/plugins/gauges/Cargo.toml index 85bad0c..4197af5 100644 --- a/plugins/gauges/Cargo.toml +++ b/plugins/gauges/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "xfetch-plugin-gauges" -version = "0.2.0" +version = "0.2.1" edition = "2024" license = "MIT" description = "Xfetch plugin that renders memory, swap, disk and battery usage as progress bars" [dependencies] serde = { version = "1", features = ["derive"] } -sysinfo = "0.39" +sysinfo = "0.40.1" xfetch-plugin-api = { workspace = true } diff --git a/plugins/gauges/src/main.rs b/plugins/gauges/src/main.rs index 648833e..c43bcb1 100644 --- a/plugins/gauges/src/main.rs +++ b/plugins/gauges/src/main.rs @@ -102,10 +102,11 @@ fn collect(args: &PluginArgs) -> Vec { let mut lines = Vec::new(); - if enabled("memory") || enabled("swap") { - let sys = System::new_with_specifics( + if (enabled("memory") || enabled("swap")) + && let Ok(sys) = System::new_with_specifics( RefreshKind::nothing().with_memory(MemoryRefreshKind::everything()), - ); + ) + { if enabled("memory") { lines.push(format!( "{} {}", @@ -204,11 +205,13 @@ fn human(bytes: u64) -> String { } fn disk_lines(style: &str, width: usize, include_tmpfs: bool, glyph: &str) -> Vec { - let disks = Disks::new_with_refreshed_list(); + let Ok(disks) = Disks::new_with_refreshed_list() else { + return Vec::new(); + }; let mut seen = std::collections::HashSet::new(); let mut rows: Vec<(String, String)> = Vec::new(); - for disk in disks.list() { + for disk in &disks { let total = disk.total_space(); if total == 0 { continue; diff --git a/plugins/theme-manager/Cargo.toml b/plugins/theme-manager/Cargo.toml index 9487801..0300d15 100644 --- a/plugins/theme-manager/Cargo.toml +++ b/plugins/theme-manager/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xfetch-plugin-theme-manager" -version = "0.2.0" +version = "0.2.1" edition = "2024" license = "MIT" description = "Xfetch plugin that fetches and manages themes from the XFetch registry" @@ -8,5 +8,5 @@ description = "Xfetch plugin that fetches and manages themes from the XFetch reg [dependencies] serde = { version = "1", features = ["derive"] } serde_json = "1" -dirs = "6" +dirs = "7" xfetch-plugin-api = { workspace = true } From 3d0f5bad6075543323cbc3adee5d67a68502dadd Mon Sep 17 00:00:00 2001 From: xscriptor Date: Tue, 3 Nov 2026 14:57:53 +0100 Subject: [PATCH 3/4] docs: document banner, gauges and langs in the plugin tables --- CHANGELOG.md | 3 ++- README.md | 12 ++++++++++++ docs/compatibility.md | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60105d5..d6e419d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ - Added the root `index.json`, a machine-readable addon catalog consumed by `xfetch plugin search` and the other remote addon discovery commands. - Added `scripts/generate_catalog.py` to regenerate the catalog from each plugin's `Cargo.toml` or `xfetch-plugin.json`; `--check` fails when the committed index is stale. - The catalog lists all 20 addons, sorted by name. Native entries use `runtime: "native"` and WebAssembly entries use `runtime: "wasm"` with their manifest capabilities preserved. -- No plugin code or manifests changed. Crate versions remain 0.2.0 (except the existing `banner-text` 0.1.0); only the catalog version is 1.0.2. +- Documented `banner`, `gauges` and `langs` in the README and platform compatibility tables. All three were already present in `index.json`. +- Crate versions remain 0.2.0 except `banner-text` 0.1.0, `gauges` 0.2.1 and `theme-manager` 0.2.1; the catalog version is 1.0.2. ## 2026-10-24 — Dependency security automation diff --git a/README.md b/README.md index 4347443..0e3727a 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,10 @@ animate-logo Animated ASCII logos with sweep, wave, rainbow, sparkle, breathing, and frame modes. + + banner + Prints a Chinese/Japanese proverb banner under or above the ASCII logo; requires a CJK-capable terminal font. + banner-text Emits text lines from a file or literal argument; works with image logos. @@ -49,10 +53,18 @@ docker Displays Docker container statistics using the local Docker CLI. + + gauges + Renders memory, swap, disk and battery usage as progress bars. + github-stats Displays GitHub user statistics such as stars, repos, pull requests, and followers. + + langs + Shows the languages of a GitHub repository or aggregates a user/org with brand colors. + display-resolution Displays monitor resolution and refresh rate. diff --git a/docs/compatibility.md b/docs/compatibility.md index 5bea5c3..64fa6a6 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -22,6 +22,11 @@ ✓✓✓ Pure computation, no OS dependencies. + + banner + ✓✓✓ + Logo-animation plugin; pure computation, but needs a TTY and a CJK-capable font. + banner-text ✓✓✓ @@ -42,11 +47,21 @@ ✓✓✓ Requires the Docker CLI (Docker Desktop on Windows/macOS). + + gauges + ✓✓✓ + Memory, swap and disks via sysinfo on all platforms; battery lines are Linux-only. + github-stats ✓✓✓ Requires curl and network access. + + langs + ✓✓✓ + Requires curl and network access to the GitHub API; set GITHUB_TOKEN/GH_TOKEN for higher rate limits. + music-player ✓~✗ From 4e02244e1757c1b4707cada57b52a6571721c86f Mon Sep 17 00:00:00 2001 From: xscriptor Date: Tue, 3 Nov 2026 21:05:32 +0100 Subject: [PATCH 4/4] docs: mark the v1.0.2 release train in the changelog --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6e419d..877cc03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## 2026-11-03 — Dependency updates +## 2026-11-03 — v1.0.2 + +Release train v1.0.2 (catalog schema 1, catalog_version 1.0.2). + +### Dependency updates - Updated the workspace lockfile with semver-compatible patches: `libc` 0.2.191, `libredox` 0.1.25, `objc2` 0.6.5, `redox_users` 0.5.3, `serde_json` 1.0.154, `syn` 3.0.9, `thiserror` 2.0.21, `thiserror-impl` 2.0.21 and `unicode-ident` 1.0.27. - `gauges` 0.2.1: moved to `sysinfo` 0.40.1 and adapted the fallible constructors and the removal of `Disks::list()`. The measurements and output format are unchanged. @@ -8,7 +12,7 @@ - Updated the security-audit workflow to `actions/checkout` 7.0.1 and the pinned `dtolnay/rust-toolchain` commit. - Regenerated `index.json` so the catalog reports the new `gauges` and `theme-manager` versions. -## 2026-11-03 — Addon catalog index +### Addon catalog index - Added the root `index.json`, a machine-readable addon catalog consumed by `xfetch plugin search` and the other remote addon discovery commands. - Added `scripts/generate_catalog.py` to regenerate the catalog from each plugin's `Cargo.toml` or `xfetch-plugin.json`; `--check` fails when the committed index is stale.