Repository navigation
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·152 lines (138 loc) · 6 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·152 lines (138 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env bash
# agent-notify installer (macOS).
#
# Installs:
# • the `agent-notify` CLI → symlinked into a bin dir on your PATH
# • the state file → ~/.config/agent-notify/state.json (seeded once)
# • the menu-bar app → a venv under ~/.local/share/agent-notify + a LaunchAgent
#
# It does NOT touch your agent's config unless you pass --register-claude, which adds
# the notify hook to ~/.claude/settings.json (Claude Code). Otherwise it prints the
# snippet for you to paste yourself.
#
# Flags:
# --dry-run print what would happen, change nothing
# --no-menubar skip the menu-bar app + LaunchAgent (CLI + hook only)
# --register-claude add the Notification/Stop hook to ~/.claude/settings.json (backup + idempotent)
# --bindir DIR where to symlink the CLI (default ~/.local/bin)
# -h, --help this help
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/register.sh
. "$REPO/lib/register.sh"
DRY=0; DO_MENUBAR=1; REGISTER_CLAUDE=0
BINDIR="${AGENT_NOTIFY_BINDIR:-$HOME/.local/bin}"
CONFIG_DIR="${AGENT_NOTIFY_CONFIG_DIR:-$HOME/.config/agent-notify}"
STATE_FILE="$CONFIG_DIR/state.json"
DATA_DIR="${AGENT_NOTIFY_DATA_DIR:-$HOME/.local/share/agent-notify}"
VENV="$DATA_DIR/venv"
LABEL="com.agent-notify.menubar"
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
LOG="$HOME/Library/Logs/agent-notify-menubar.log"
CLAUDE_SETTINGS="${CLAUDE_SETTINGS:-$HOME/.claude/settings.json}"
HOOK="$REPO/hooks/notify.sh"
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY=1 ;;
--no-menubar) DO_MENUBAR=0 ;;
--register-claude) REGISTER_CLAUDE=1 ;;
--bindir) BINDIR="$2"; shift ;;
-h|--help) sed -n '2,24p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "install: unknown flag '$1'" >&2; exit 2 ;;
esac
shift
done
say() { printf '\033[1m==>\033[0m %s\n' "$*"; }
do_() { if [ "$DRY" = 1 ]; then printf ' would: %s\n' "$*"; else eval "$*"; fi; }
have() { command -v "$1" >/dev/null 2>&1; }
# ---- dependency checks --------------------------------------------------------
say "Checking dependencies"
have jq || { echo " jq is required (brew install jq)" >&2; exit 1; }
echo " jq ✓"
if [ "$DO_MENUBAR" = 1 ]; then
PYTHON="$(command -v /usr/bin/python3 || command -v python3 || true)"
[ -n "$PYTHON" ] || { echo " python3 is required for the menu-bar app (or pass --no-menubar)" >&2; exit 1; }
echo " python3 ✓ ($PYTHON)"
fi
have flock || echo " note: flock not found (brew install flock) — speech from concurrent sessions may overlap"
# ---- CLI ----------------------------------------------------------------------
say "Installing the agent-notify CLI"
do_ "chmod +x '$HOOK' '$REPO/bin/agent-notify'"
do_ "mkdir -p '$BINDIR'"
do_ "ln -sf '$REPO/bin/agent-notify' '$BINDIR/agent-notify'"
echo " $BINDIR/agent-notify -> $REPO/bin/agent-notify"
case ":$PATH:" in *":$BINDIR:"*) ;; *) echo " ⚠ $BINDIR is not on your PATH — add it to use \`agent-notify\`" ;; esac
# ---- state --------------------------------------------------------------------
say "Seeding state file"
if [ -f "$STATE_FILE" ]; then
echo " $STATE_FILE already exists — leaving it"
else
do_ "mkdir -p '$CONFIG_DIR'"
do_ "cp '$REPO/config/state.default.json' '$STATE_FILE'"
echo " $STATE_FILE"
fi
say "Seeding config.env (secrets like the chat webhook live here, not in settings.json)"
CONFIG_ENV="$CONFIG_DIR/config.env"
if [ -f "$CONFIG_ENV" ]; then
echo " $CONFIG_ENV already exists — leaving it"
else
do_ "mkdir -p '$CONFIG_DIR'"
do_ "cp '$REPO/config/config.env.example' '$CONFIG_ENV'"
do_ "chmod 600 '$CONFIG_ENV'"
echo " $CONFIG_ENV (edit to add your webhook, etc.)"
fi
# ---- menu-bar app -------------------------------------------------------------
if [ "$DO_MENUBAR" = 1 ]; then
say "Setting up the menu-bar app"
do_ "mkdir -p '$DATA_DIR'"
if [ -x "$VENV/bin/python" ]; then
echo " venv exists — updating deps"
else
do_ "'$PYTHON' -m venv '$VENV'"
fi
do_ "'$VENV/bin/pip' install --quiet --upgrade pip"
do_ "'$VENV/bin/pip' install --quiet -r '$REPO/menubar/requirements.txt'"
echo " venv: $VENV"
say "Installing the LaunchAgent"
if [ "$DRY" = 1 ]; then
printf ' would: render %s -> %s\n' "$REPO/launchagents/menubar.plist.template" "$PLIST"
else
mkdir -p "$(dirname "$PLIST")" "$(dirname "$LOG")"
sed -e "s|__LABEL__|$LABEL|g" \
-e "s|__PYTHON__|$VENV/bin/python|g" \
-e "s|__APP__|$REPO/menubar/app.py|g" \
-e "s|__HOME__|$HOME|g" \
-e "s|__LOG__|$LOG|g" \
"$REPO/launchagents/menubar.plist.template" > "$PLIST"
fi
do_ "launchctl bootout 'gui/$(id -u)/$LABEL' 2>/dev/null || true"
do_ "launchctl bootstrap 'gui/$(id -u)' '$PLIST'"
echo " $PLIST (label $LABEL)"
echo " a 🔊 icon should appear in your menu bar"
fi
# ---- Claude Code hook registration (opt-in) -----------------------------------
say "Agent hook registration (Claude Code)"
if [ "$REGISTER_CLAUDE" = 1 ]; then
if [ ! -f "$CLAUDE_SETTINGS" ]; then
echo " $CLAUDE_SETTINGS not found — is Claude Code installed? Skipping."
elif [ "$DRY" = 1 ]; then
printf ' would: back up %s and add Notification/Stop hooks -> %s\n' "$CLAUDE_SETTINGS" "$HOOK"
else
cp "$CLAUDE_SETTINGS" "$CLAUDE_SETTINGS.agent-notify.bak"
tmp="$(mktemp)"
register_hook "$CLAUDE_SETTINGS" "$HOOK" > "$tmp" && mv "$tmp" "$CLAUDE_SETTINGS"
echo " registered in $CLAUDE_SETTINGS (backup: $CLAUDE_SETTINGS.agent-notify.bak)"
echo " restart Claude Code (or start a new session) to load the hook"
fi
else
cat <<EOF
Not registered (pass --register-claude to do it automatically). Add this to
the "hooks" object of ~/.claude/settings.json, under BOTH "Notification" and "Stop":
{ "hooks": [ { "type": "command", "command": "$HOOK", "timeout": 30, "async": true } ] }
EOF
fi
say "Done."
echo "Control it: agent-notify (status)"
echo " agent-notify off (focus / mute)"
echo " agent-notify on"
echo "Or use the 🔊 menu-bar icon."