-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·110 lines (93 loc) · 3.46 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·110 lines (93 loc) · 3.46 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
#!/usr/bin/env bash
# Install ghost-code as a Claude Code hook.
# Builds the Rust binary, symlinks it, and merges hook config into settings.json.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
HOOKS_DIR="$HOME/.claude/hooks"
SETTINGS="$HOME/.claude/settings.json"
BINARY="ghost-code"
mkdir -p "$HOOKS_DIR"
# Build
if ! command -v cargo &>/dev/null; then
echo "Error: cargo not found. Install Rust: https://rustup.rs"
exit 1
fi
echo "Building..."
cargo build --release --manifest-path "$SCRIPT_DIR/Cargo.toml"
# Symlink binary
ln -sf "$SCRIPT_DIR/target/release/$BINARY" "$HOOKS_DIR/$BINARY"
echo "Linked $BINARY → $HOOKS_DIR/"
# Create .env from example if missing
if [ ! -f "$HOOKS_DIR/ghost-code.env" ]; then
cp "$SCRIPT_DIR/.env.example" "$HOOKS_DIR/ghost-code.env"
echo "Created $HOOKS_DIR/ghost-code.env — edit it with your bot token and chat ID."
else
echo "ghost-code.env already exists, skipping."
fi
# Read STATUSLINE setting from env file (default: true)
STATUSLINE="true"
if [ -f "$HOOKS_DIR/ghost-code.env" ]; then
SL=$(grep -E '^STATUSLINE=' "$HOOKS_DIR/ghost-code.env" 2>/dev/null | tail -1 | cut -d= -f2 | tr -d '"'"'" | tr '[:upper:]' '[:lower:]')
if [ "$SL" = "false" ]; then
STATUSLINE="false"
fi
fi
# Merge hooks into settings.json
python3 - "$SETTINGS" "$HOOKS_DIR/$BINARY" "$STATUSLINE" <<'PYEOF'
import json, sys
from pathlib import Path
path = Path(sys.argv[1])
binary = sys.argv[2]
statusline = sys.argv[3] == "true"
settings = json.loads(path.read_text()) if path.exists() else {}
hooks = settings.setdefault("hooks", {})
CMD_STOP = f"{binary} stop"
CMD_NOTIF = f"{binary} notification"
CMD_PRE = f"{binary} pre-tool-use"
CMD_SL = f"{binary} statusline"
def has_command(entries, cmd):
for entry in entries:
for h in entry.get("hooks", []):
if h.get("command", "") == cmd:
return True
return False
def remove_command(entries, cmd):
return [
e for e in entries
if not any(h.get("command", "") == cmd for h in e.get("hooks", []))
]
# Core hooks (always installed)
for event, cmd in [("Stop", CMD_STOP), ("Notification", CMD_NOTIF), ("PreToolUse", CMD_PRE)]:
entries = hooks.setdefault(event, [])
if not has_command(entries, cmd):
entries.append({"hooks": [{"type": "command", "command": cmd}]})
print(f"Added {event} hook.")
else:
print(f"{event} hook already configured.")
# Statusline hook (optional, controlled by STATUSLINE env var)
sl_entries = hooks.setdefault("StatusLine", [])
if statusline:
if not has_command(sl_entries, CMD_SL):
sl_entries.append({"hooks": [{"type": "command", "command": CMD_SL}]})
print("Added StatusLine hook.")
else:
print("StatusLine hook already configured.")
else:
if has_command(sl_entries, CMD_SL):
hooks["StatusLine"] = remove_command(sl_entries, CMD_SL)
print("Removed StatusLine hook (STATUSLINE=false).")
else:
print("StatusLine hook skipped (STATUSLINE=false).")
# Clean up empty hook arrays
hooks = {k: v for k, v in hooks.items() if v}
settings["hooks"] = hooks
path.write_text(json.dumps(settings, indent=2) + "\n")
PYEOF
echo ""
echo "Installation complete."
echo " - Edit $HOOKS_DIR/ghost-code.env with your bot token and chat ID"
echo " - Run 'bash test.sh' to verify hooks"
echo " - Run '$HOOKS_DIR/$BINARY bot' to start the bot"
if [ "$STATUSLINE" = "true" ]; then
echo " - StatusLine hook installed (set STATUSLINE=false in .env to disable)"
fi