-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·146 lines (133 loc) · 5.13 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·146 lines (133 loc) · 5.13 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
#!/bin/bash
# ccbit installer. Fetches the prebuilt binary for this platform from the latest
# GitHub release (no Go required), falling back to building from source when Go
# is available. Merges the statusLine into ~/.claude/settings.json (backed up
# first, never overwritten wholesale) and removes config left by the legacy
# hooks-based installer.
set -e
REPO="livlign/ccbit"
DEST_DIR="$HOME/.claude/ccbit"
DEST="$DEST_DIR/ccbit"
SETTINGS="$HOME/.claude/settings.json"
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
case "$ARCH" in
x86_64|amd64) ARCH=amd64 ;;
arm64|aarch64) ARCH=arm64 ;;
*) ARCH="" ;;
esac
case "$OS" in
darwin|linux) ;;
*) OS="" ;;
esac
ASSET="ccbit_${OS}_${ARCH}.tar.gz"
URL="https://github.com/$REPO/releases/latest/download/$ASSET"
CHECKSUMS_URL="https://github.com/$REPO/releases/latest/download/checksums.txt"
# sha256_of prints the SHA-256 of a file, using whichever tool is present.
# Returns non-zero when neither is available (caller skips verification).
sha256_of() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | awk '{print $1}'
else
return 1
fi
}
# verify_checksum checks the downloaded asset against the release's
# checksums.txt. A mismatch is fatal (return 1). When verification genuinely
# can't run — checksums.txt unreachable, asset unlisted, or no sha256 tool — it
# warns and returns 0 so a release predating checksums still installs.
verify_checksum() {
local asset_path="$1" sums want got
sums="$(dirname "$asset_path")/checksums.txt"
if ! curl -fsSL "$CHECKSUMS_URL" -o "$sums" 2>/dev/null; then
echo "ccbit: WARNING — could not fetch checksums.txt; skipping integrity check" >&2
return 0
fi
want=$(awk -v f="$ASSET" '$2 == f {print $1}' "$sums")
if [ -z "$want" ]; then
echo "ccbit: WARNING — no checksum listed for $ASSET; skipping integrity check" >&2
return 0
fi
if ! got=$(sha256_of "$asset_path"); then
echo "ccbit: WARNING — no sha256 tool (sha256sum/shasum); skipping integrity check" >&2
return 0
fi
if [ "$got" != "$want" ]; then
echo "ccbit: ERROR — checksum mismatch for $ASSET (refusing to install)" >&2
echo " expected $want" >&2
echo " got $got" >&2
return 1
fi
echo "ccbit: checksum verified"
}
fetch_release() {
[ -n "$OS" ] && [ -n "$ARCH" ] || return 1
command -v curl >/dev/null 2>&1 || return 1
local tmp
tmp=$(mktemp -d) || return 1
# shellcheck disable=SC2064
trap "rm -rf '$tmp'" RETURN 2>/dev/null || true
echo "ccbit: downloading $ASSET from the latest release"
curl -fsSL "$URL" -o "$tmp/$ASSET" || { rm -rf "$tmp"; return 1; }
verify_checksum "$tmp/$ASSET" || { rm -rf "$tmp"; return 1; }
tar -xzf "$tmp/$ASSET" -C "$tmp" ccbit || { rm -rf "$tmp"; return 1; }
mkdir -p "$DEST_DIR"
install -m 0755 "$tmp/ccbit" "$DEST"
rm -rf "$tmp"
}
build_from_source() {
command -v go >/dev/null 2>&1 || return 1
local src
src="$(cd "$(dirname "${BASH_SOURCE[0]:-.}")" && pwd)"
[ -f "$src/go.mod" ] || return 1 # piped through curl: no source tree here
echo "ccbit: no prebuilt binary for ${OS:-$(uname -s)}/${ARCH:-$(uname -m)}; building from source"
mkdir -p "$DEST_DIR"
(cd "$src" && go build -o "$DEST" ./cmd/ccbit)
}
fetch_release || build_from_source || {
echo "ccbit: could not install a binary." >&2
echo " - no release asset for ${OS:-$(uname -s)}/${ARCH:-$(uname -m)} (or curl is missing), and" >&2
echo " - no Go toolchain (or no source tree) to build from." >&2
echo "Install Go 1.26+ and run: go build -o $DEST ./cmd/ccbit (from a clone)," >&2
echo "or download an asset manually: https://github.com/$REPO/releases/latest" >&2
exit 1
}
echo "ccbit: installed $DEST"
STATUSLINE='{"type":"command","command":"~/.claude/ccbit/ccbit","refreshInterval":1,"padding":1}'
if ! command -v jq >/dev/null 2>&1; then
echo "ccbit: jq not found — add this to $SETTINGS yourself:"
echo "{
\"statusLine\": $STATUSLINE
}"
exit 0
fi
if [ -f "$SETTINGS" ]; then
BAK="$SETTINGS.bak.$(date +%Y%m%d%H%M%S)"
cp "$SETTINGS" "$BAK"
echo "ccbit: backed up settings.json -> $BAK"
if jq -e '.statusLine and (.statusLine.command | test("ccbit/(ccbit|statusline.sh)") | not)' "$SETTINGS" >/dev/null 2>&1; then
echo "ccbit: WARNING — replacing an existing statusLine config (only one is allowed). Old value is in the backup."
fi
else
mkdir -p "$(dirname "$SETTINGS")"
echo '{}' > "$SETTINGS"
echo "ccbit: created new settings.json"
fi
# Set the statusLine; drop hook entries left by the legacy shell installer
# (the Go binary needs none).
TMP="$SETTINGS.tmp.$$"
jq --argjson sl "$STATUSLINE" '
def dropccbit:
map(.hooks |= map(select(((.command // "") | test("ccbit/hooks/")) | not)))
| map(select(.hooks != []));
.statusLine = $sl
| (if .hooks then
.hooks |= (with_entries(.value |= dropccbit) | with_entries(select(.value != [])))
| (if .hooks == {} then del(.hooks) else . end)
else . end)
' "$SETTINGS" > "$TMP"
mv "$TMP" "$SETTINGS"
echo "ccbit: statusLine configured in $SETTINGS"
echo "ccbit: done. Open a new Claude Code session to see Bit."