-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·117 lines (103 loc) · 4.39 KB
/
install.sh
File metadata and controls
executable file
·117 lines (103 loc) · 4.39 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
#!/usr/bin/env bash
# install.sh — installer for the `second-opinion` skill.
#
# Works for:
# - Claude Code (wires the PreToolUse hook automatically)
# - Any other AI CLI that reads skills from ~/.claude/skills (opencode, etc.)
# - Manual use by a subagent (the files just sit at ~/.claude/skills/second-opinion)
#
# Supported OSes: macOS, Linux. Requires: bash, curl OR git, and optionally jq
# (jq is only required for the auto-hook-wiring step in Claude Code; the skill
# itself fails open without jq and prints a warning).
#
# One-liner:
# curl -fsSL https://raw.githubusercontent.com/pghqdev/second-opinion/main/install.sh | bash
#
# Flags (via env vars):
# SECOND_OPINION_REF=main # branch/tag/sha to install
# SECOND_OPINION_SKIP_HOOK=1 # don't modify ~/.claude/settings.json
# SECOND_OPINION_PREFIX=... # override install root (default: $HOME/.claude)
set -euo pipefail
REF="${SECOND_OPINION_REF:-main}"
PREFIX="${SECOND_OPINION_PREFIX:-$HOME/.claude}"
SKILL_DIR="$PREFIX/skills/second-opinion"
SETTINGS="$PREFIX/settings.json"
REPO_URL="https://github.com/pghqdev/second-opinion"
TARBALL_URL="https://codeload.github.com/pghqdev/second-opinion/tar.gz/refs/heads/$REF"
log() { printf '[second-opinion] %s\n' "$*"; }
die() { printf '[second-opinion] ERROR: %s\n' "$*" >&2; exit 1; }
# --- platform checks ------------------------------------------------------
case "$(uname -s)" in
Darwin|Linux) : ;;
*) die "unsupported OS: $(uname -s). Install manually from $REPO_URL" ;;
esac
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 || command -v git >/dev/null 2>&1 \
|| die "need curl, wget, or git to fetch the skill"
command -v tar >/dev/null 2>&1 || die "need tar to extract the skill"
# --- fetch & extract ------------------------------------------------------
TMP=$(mktemp -d -t second-opinion-install.XXXXXX)
trap 'rm -rf "$TMP"' EXIT
log "fetching $REF from $REPO_URL"
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$TARBALL_URL" -o "$TMP/src.tar.gz"
elif command -v wget >/dev/null 2>&1; then
wget -q "$TARBALL_URL" -O "$TMP/src.tar.gz"
else
git clone --depth 1 --branch "$REF" "$REPO_URL.git" "$TMP/src" >/dev/null 2>&1
fi
if [ -f "$TMP/src.tar.gz" ]; then
tar -xzf "$TMP/src.tar.gz" -C "$TMP"
SRC=$(find "$TMP" -maxdepth 1 -type d -name "second-opinion-*" | head -1)
else
SRC="$TMP/src"
fi
[ -n "$SRC" ] && [ -d "$SRC/skills/second-opinion" ] || die "could not locate skill files in extracted archive"
# --- install skill files --------------------------------------------------
log "installing skill to $SKILL_DIR"
mkdir -p "$(dirname "$SKILL_DIR")"
rm -rf "$SKILL_DIR"
cp -R "$SRC/skills/second-opinion" "$SKILL_DIR"
chmod +x "$SKILL_DIR/scripts/"*.sh
# --- wire Claude Code hook (optional) -------------------------------------
if [ "${SECOND_OPINION_SKIP_HOOK:-0}" = "1" ]; then
log "SECOND_OPINION_SKIP_HOOK=1 set; skipping hook registration"
elif [ ! -d "$PREFIX" ]; then
log "no Claude directory at $PREFIX; skipping hook registration"
elif ! command -v jq >/dev/null 2>&1; then
log "jq not installed; skipping hook registration (run install.sh again after 'brew install jq' or 'apt install jq' to enable auto-gate)"
else
mkdir -p "$PREFIX"
if [ ! -f "$SETTINGS" ]; then
echo '{}' > "$SETTINGS"
fi
HOOK_CMD="$SKILL_DIR/scripts/detect_triggers.sh"
# Idempotently add/replace the PreToolUse:ExitPlanMode hook entry.
NEW=$(jq --arg cmd "$HOOK_CMD" '
.hooks //= {}
| .hooks.PreToolUse //= []
| .hooks.PreToolUse |= (
(map(select(.matcher != "ExitPlanMode" or (.hooks // []) | all(.command != $cmd))))
+ [{"matcher":"ExitPlanMode","hooks":[{"type":"command","command":$cmd}]}]
)
| .hooks.PreToolUse |= unique_by(.matcher)
' "$SETTINGS")
printf '%s\n' "$NEW" > "$SETTINGS"
log "wired PreToolUse:ExitPlanMode hook in $SETTINGS"
fi
# --- verify dependencies on PATH ------------------------------------------
log "installed."
log "Reviewer CLIs detected:"
for cli in codex gemini opencode claude; do
if command -v "$cli" >/dev/null 2>&1; then
log " ✓ $cli ($(command -v $cli))"
else
log " ✗ $cli (not installed)"
fi
done
cat <<EOF
Next steps:
• In Claude Code: restart the session (or run \`/hooks reload\` if available).
• To bypass the gate on a specific plan: include \`<!-- skip second opinion -->\`.
• To uninstall: rm -rf $SKILL_DIR and remove the hook entry from $SETTINGS.
Docs: $REPO_URL
EOF