{ config, lib, pkgs, ... }: let cfg = config.programs.ai-usage; providerNames = [ "claude" "codex" "cursor" ]; executablePath = value: if lib.isDerivation value then lib.getExe value else value; enabledProviders = builtins.filter (name: cfg.providers.${name}.enable) providerNames; executableOverrides = lib.mapAttrs (_: provider: executablePath provider.executable) (lib.filterAttrs (_: provider: provider.executable != null) cfg.providers); in { options.programs.ai-usage = { enable = lib.mkEnableOption "AI Usage Monitor for Waybar"; package = lib.mkOption { type = lib.types.package; description = "ai-usage package from this flake."; }; refreshMinutes = lib.mkOption { type = lib.types.enum [ 5 15 30 60 ]; default = 5; description = "How often the daemon refreshes usage, in minutes."; }; showUsedPercentage = lib.mkOption { type = lib.types.bool; default = false; description = "Show used percentage instead of remaining percentage."; }; providers = lib.genAttrs providerNames (name: { enable = lib.mkOption { type = lib.types.bool; default = true; description = "Refresh and show ${name}."; }; executable = lib.mkOption { type = lib.types.nullOr (lib.types.either lib.types.str lib.types.package); default = null; example = lib.literalExpression "pkgs.claude-code"; description = "Absolute path or package for ${name}. A package uses lib.getExe."; }; }); }; config = lib.mkIf cfg.enable (lib.mkMerge [ { home.packages = [ cfg.package ]; xdg.configFile."ai-usage/config.json".text = builtins.toJSON { refreshMinutes = cfg.refreshMinutes; enabledProviders = enabledProviders; executableOverrides = executableOverrides; showUsedPercentage = cfg.showUsedPercentage; }; systemd.user.services.ai-usage = { Unit = { Description = "AI Usage Monitor"; PartOf = [ "graphical-session.target" ]; After = [ "graphical-session.target" ]; }; Service = { ExecStart = "${lib.getExe cfg.package} daemon"; Restart = "on-failure"; RestartSec = 2; Environment = [ "DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus" "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt" "PATH=${lib.makeBinPath [ pkgs.sqlite ]}:%h/.local/bin:%h/.nix-profile/bin:/etc/profiles/per-user/%u/bin:/run/current-system/sw/bin" ]; }; Install.WantedBy = [ "graphical-session.target" ]; }; } (lib.mkIf config.programs.waybar.enable { programs.waybar.settings.mainBar = { "custom/ai-usage" = { exec = "${lib.getExe cfg.package} waybar"; return-type = "json"; interval = 60; signal = 1; on-click = "${lib.getExe cfg.package} refresh"; tooltip = true; }; modules-right = lib.mkBefore [ "custom/ai-usage" ]; }; programs.waybar.style = lib.mkAfter '' #custom-ai-usage.ok { color: #a6e3a1; } #custom-ai-usage.warning { color: #fab387; } #custom-ai-usage.critical { color: #f38ba8; } #custom-ai-usage.unknown { color: #cdd6f4; } ''; }) ]); }