Set real values for genericized git-config/encryption/send-alert/printing

Mirrors the azos-core change: drops the now-fully-migrated
features/{git-config,encryption,printing}, rewrites features/homey-alert
down to just the azos-homey-ntfy-alert overlay package (the ntfy-specific
remote-notification command plugged into azos.send-alert.remoteCommand),
and sets every real personal value (name/email/signing key, GPG key id,
YubiKey/browserpass/gpg-ssh toggles and keygrip/pubkey, printing username)
directly in home-manager/home.nix and nixos/configuration.nix, same place
the other personal values (azos.name, azos.headphones.devices) already
live.
This commit is contained in:
2026-10-13 09:50:44 +03:00
parent 8b633f598c
commit b880a194ba
14 changed files with 56 additions and 433 deletions
+21 -184
View File
@@ -1,191 +1,28 @@
{...}: {
config.flake.modules.homeManager.homey-alert = {
lib,
config,
pkgs,
...
}: {
options.azos.homey-alert.enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
};
options.azos.homey-alert.longCommandThresholdSeconds = lib.mkOption {
default = 300;
example = 600;
type = lib.types.int;
description = ''
Installs a global PreToolUse hook (matcher "Bash") in
~/.claude/settings.json that transparently wraps every Bash command
Claude Code runs: it times the command, and if it ran at or past
this threshold, fires homey-alert with the elapsed time and exit
code once it finishes. Commands that finish faster are unaffected.
config.flake.overlayPkgs.azos-homey-ntfy-alert = pkgs:
pkgs.writeShellApplication {
name = "azos-homey-ntfy-alert";
runtimeInputs = with pkgs; [curl pass];
text = ''
TOKEN="$(pass zakobar-homecenter/ntfy-token)"
This exists so long-running commands (big rclone transfers, builds)
notify automatically even when Claude never thinks to chain
homey-alert itself, and even if the harness moves the command to
the background partway through.
CMD=(
curl -sf
-H "Authorization: Bearer $TOKEN"
-H "Priority: ''${PRIORITY:-default}"
)
[[ -n "''${TITLE:-}" ]] && CMD+=(-H "Title: $TITLE")
[[ -n "''${TAGS:-}" ]] && CMD+=(-H "Tags: $TAGS")
CMD+=(-d "''${MESSAGE:-}" https://ntfy.zakobar.com/alerts)
The hook only adds timing + notification around the command as
given -- it does not change permissions, so normal confirmation
prompts for risky commands still happen exactly as before.
'';
};
config = lib.mkIf config.azos.homey-alert.enable (let
threshold = toString config.azos.homey-alert.longCommandThresholdSeconds;
# Rewrites every Bash tool command to time itself and fire
# homey-alert if it ran at or past the threshold. The original
# command is spliced in verbatim (not eval'd from an encoded blob)
# so it stays human-readable in any permission prompt, and it's run
# in a subshell so the wrapper's own timing/notify code still runs
# even if the original command uses `set -e` or calls `exit`.
# permissionDecision is deliberately omitted from the hook's JSON
# output: supplying it (even as "allow") would bypass the normal
# confirmation flow, which must stay untouched here.
bashNotifyHook = pkgs.writeShellApplication {
name = "azos-bash-notify-hook";
runtimeInputs = [pkgs.jq];
text = ''
input=$(cat)
command=$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null) || command=""
if [ -z "$command" ]; then
echo '{}'
exit 0
fi
wrapped="__azos_notify_start=\$(date +%s)
(
$command
)
__azos_notify_rc=\$?
__azos_notify_dur=\$(( \$(date +%s) - __azos_notify_start ))
if [ \"\$__azos_notify_dur\" -ge ${threshold} ]; then
__azos_notify_tag=\$([ \"\$__azos_notify_rc\" -eq 0 ] && echo white_check_mark || echo x)
homey-alert -t \"Long command\" -T \"\$__azos_notify_tag\" \"Finished in \$__azos_notify_dur s (exit \$__azos_notify_rc)\" >/dev/null 2>&1 || true
fi
exit \"\$__azos_notify_rc\""
jq -n --arg cmd "$wrapped" \
'{hookSpecificOutput: {hookEventName: "PreToolUse", updatedInput: {command: $cmd}}}' 2>/dev/null || echo '{}'
'';
};
in {
azos.claude.globalSkills.notify = ./notify-skill.md;
home.activation.configureBashNotifyHook = lib.hm.dag.entryAfter ["writeBoundary"] ''
SETTINGS_JSON="$HOME/.claude/settings.json"
HOOK_ENTRY=$(${pkgs.jq}/bin/jq -n \
--arg cmd "${bashNotifyHook}/bin/azos-bash-notify-hook" \
'{
matcher: "Bash",
hooks: [{type: "command", command: $cmd}]
}')
if [ -f "$SETTINGS_JSON" ]; then
tmp=$(mktemp)
${pkgs.jq}/bin/jq --argjson entry "$HOOK_ENTRY" \
'.hooks.PreToolUse = ((.hooks.PreToolUse // []) | map(select(.matcher != $entry.matcher))) + [$entry]' \
"$SETTINGS_JSON" > "$tmp" && mv "$tmp" "$SETTINGS_JSON"
if [[ -n "''${AZOS_SEND_ALERT_PRINT_REMOTE:-}" ]]; then
# Shell-quote each element so the output is safe to embed in SSH commands --
# the token is already resolved above, so the remote host only needs curl.
printf '%q ' "''${CMD[@]}"
printf '\n'
else
${pkgs.jq}/bin/jq -n --argjson entry "$HOOK_ENTRY" \
'{hooks: {PreToolUse: [$entry]}}' > "$SETTINGS_JSON"
"''${CMD[@]}"
fi
'';
home.packages = [
bashNotifyHook
(pkgs.writeShellApplication {
name = "homey-alert";
runtimeInputs = with pkgs; [curl pass libnotify];
text = ''
usage() {
cat <<EOF
Usage: homey-alert [OPTIONS] [MESSAGE]
Send a notification to the homey ntfy server (ntfy.zakobar.com/alerts),
and (when run locally, not with --print-remote) also via notify-send --
the ntfy server isn't always reachable, so the local desktop notification
always fires too, independent of whether the ntfy push succeeds.
MESSAGE can be given as a positional argument or piped via stdin.
Options:
-t, --title TITLE notification title
-p, --priority PRIO priority: min|low|default|high|urgent (default: default)
-T, --tags TAGS comma-separated emoji shortcodes (e.g. warning,rotating_light)
-r, --print-remote print the curl command instead of running it
(for pasting into SSH commands to remote machines)
-h, --help show this help
Examples:
# Local
long_cmd && homey-alert -t "Training" -p high -T white_check_mark "done"
# Remote — expands locally, runs on the remote machine
ssh user@host "python train.py && \$(homey-alert -r -t 'Training' 'done')"
EOF
}
TITLE=""
PRIORITY="default"
TAGS=""
PRINT_REMOTE=false
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--title) TITLE="$2"; shift 2 ;;
-p|--priority) PRIORITY="$2"; shift 2 ;;
-T|--tags) TAGS="$2"; shift 2 ;;
-r|--print-remote) PRINT_REMOTE=true; shift ;;
-h|--help) usage; exit 0 ;;
--) shift; break ;;
-*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
*) break ;;
esac
done
if [[ $# -gt 0 ]]; then
MESSAGE="$*"
elif [[ ! -t 0 ]]; then
MESSAGE="$(cat)"
else
echo "homey-alert: no message provided" >&2
usage >&2
exit 1
fi
TOKEN="$(pass zakobar-homecenter/ntfy-token)"
# Build the curl invocation as an array — single source of truth for both modes
CMD=(
curl -sf
-H "Authorization: Bearer $TOKEN"
-H "Priority: $PRIORITY"
)
[[ -n "$TITLE" ]] && CMD+=(-H "Title: $TITLE")
[[ -n "$TAGS" ]] && CMD+=(-H "Tags: $TAGS")
CMD+=(-d "$MESSAGE" https://ntfy.zakobar.com/alerts)
if $PRINT_REMOTE; then
# Shell-quote each element so the output is safe to embed in SSH commands
printf '%q ' "''${CMD[@]}"
printf '\n'
else
"''${CMD[@]}" || true
# Local desktop notification, independent of the ntfy push above --
# the server isn't always up, so this always fires as a fallback.
URGENCY="normal"
case "$PRIORITY" in
min|low) URGENCY="low" ;;
high|urgent) URGENCY="critical" ;;
esac
notify-send -u "$URGENCY" "''${TITLE:-homey-alert}" "$MESSAGE" || true
fi
'';
})
];
});
};
};
}