-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·182 lines (166 loc) · 5.27 KB
/
install.sh
File metadata and controls
executable file
·182 lines (166 loc) · 5.27 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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/bin/bash
# Installer for Claude Code WebUI hooks (new architecture)
#
# Installs 3 Python hook scripts (PermissionRequest, SessionStart, SessionEnd).
# No external dependencies (no jq, curl — hooks are pure Python).
#
# Scopes:
# --project Install hooks into <cwd>/.claude/settings.json (project-level only)
# --global Install hooks into ~/.claude/settings.json + create symlinks in ~/.claude/hooks/
# --daemon Install systemd service for auto-start (Linux only)
#
# Usage: /path/to/install.sh --project|--global|--daemon [--daemon]
# Deps: jq (for settings.json manipulation only)
set -e
SHARED_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(pwd)"
HOOKS_DIR="$HOME/.claude/hooks"
usage() {
echo "Usage: $0 --project|--global|--daemon [--daemon]"
echo ""
echo " --project Install hooks into <cwd>/.claude/settings.json"
echo " --global Install hooks into ~/.claude/settings.json + symlinks"
echo " --daemon Install systemd service for auto-start (Linux only)"
echo ""
echo "Flags can be combined: $0 --global --daemon"
exit 1
}
prompt_scope() {
echo "Select install scope:"
echo " 1) project — Install hooks into <cwd>/.claude/settings.json"
echo " 2) global — Install hooks into ~/.claude/settings.json + symlinks"
echo " 3) daemon — Install systemd service for auto-start (Linux only)"
echo ""
echo "Enter choices separated by space (e.g. '1 3' or '2'):"
printf "> "
read -r choices
for c in $choices; do
case "$c" in
1) DO_PROJECT=true ;;
2) DO_GLOBAL=true ;;
3) DO_DAEMON=true ;;
*) echo "Invalid choice: $c"; exit 1 ;;
esac
done
if [ "$DO_PROJECT" = false ] && [ "$DO_GLOBAL" = false ] && [ "$DO_DAEMON" = false ]; then
echo "No scope selected"; exit 1
fi
}
DO_PROJECT=false
DO_GLOBAL=false
DO_DAEMON=false
if [ $# -eq 0 ]; then
prompt_scope
else
for arg in "$@"; do
case "$arg" in
--project) DO_PROJECT=true ;;
--global) DO_GLOBAL=true ;;
--daemon) DO_DAEMON=true ;;
*) usage ;;
esac
done
fi
# Resolve $HOME at install time — Claude Code may not use a shell that expands env vars
HOOKS_PATH="$HOME/.claude/hooks"
HOOKS_CONFIG="$(cat <<EOFJSON
{
"PermissionRequest": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "python3 \"$HOOKS_PATH/hook-permission-request.py\"",
"timeout": 86400
}
]
}
],
"SessionStart": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "python3 \"$HOOKS_PATH/hook-session-start.py\"",
"timeout": 5
}
]
}
],
"SessionEnd": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "python3 \"$HOOKS_PATH/hook-session-end.py\"",
"timeout": 5
}
]
}
]
}
EOFJSON
)"
install_symlinks() {
mkdir -p "$HOOKS_DIR"
# Also remove old symlinks from previous architectures
for old_script in permission-request.py session-start.py session-end.py permission-request.sh post-tool-use.sh stop.sh user-prompt-submit.sh session-start.sh session-end.sh; do
[ -L "$HOOKS_DIR/$old_script" ] && rm -f "$HOOKS_DIR/$old_script"
done
for script in hook-permission-request.py hook-session-start.py hook-session-end.py permission_rules.py platform_utils.py auto-allow.json; do
ln -sf "$SHARED_DIR/$script" "$HOOKS_DIR/$script"
done
echo "Symlinked hooks to: $HOOKS_DIR"
}
install_settings() {
local settings_file="$1"
local settings_dir
settings_dir="$(dirname "$settings_file")"
mkdir -p "$settings_dir"
if [ -f "$settings_file" ]; then
EXISTING=$(cat "$settings_file")
echo "$EXISTING" | jq --argjson hooks "$HOOKS_CONFIG" '.hooks = $hooks' > "$settings_file.tmp" && mv "$settings_file.tmp" "$settings_file"
echo "Updated: $settings_file"
else
echo "$HOOKS_CONFIG" | jq '{hooks: .}' > "$settings_file"
echo "Created: $settings_file"
fi
}
install_daemon() {
if [ "$(uname)" != "Linux" ]; then
echo "WARNING: --daemon is Linux only (systemd). Skipping on $(uname)."
return
fi
if ! command -v systemctl >/dev/null 2>&1; then
echo "ERROR: systemctl not found. Is systemd installed?"
exit 1
fi
if ! command -v inotifywait >/dev/null 2>&1; then
echo "Installing inotify-tools..."
sudo apt install -y inotify-tools
fi
sudo cp "$SHARED_DIR/claude-webui-linux.service" /etc/systemd/system/claude-webui.service
sudo cp "$SHARED_DIR/claude-webui-watcher-linux.service" /etc/systemd/system/claude-webui-watcher.service
sudo systemctl daemon-reload
sudo systemctl enable --now claude-webui.service claude-webui-watcher.service
echo "Daemon installed and started (claude-webui + claude-webui-watcher)"
}
if [ "$DO_GLOBAL" = true ]; then
install_symlinks
install_settings "$HOME/.claude/settings.json"
echo "WebUI hooks installed globally (all projects)"
fi
if [ "$DO_PROJECT" = true ]; then
# Symlinks are always needed — hook commands reference $HOME/.claude/hooks/
install_symlinks
install_settings "$PROJECT_DIR/.claude/settings.json"
echo "WebUI hooks installed for: $PROJECT_DIR"
fi
if [ "$DO_DAEMON" = true ]; then
install_daemon
fi
echo "Start the server: python3 $SHARED_DIR/server.py"
echo "Then open: http://localhost:19836"