-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·240 lines (219 loc) · 8.27 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·240 lines (219 loc) · 8.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#!/bin/sh
# Ryu one-line installer for macOS and Linux.
#
# curl -fsSL https://raw.githubusercontent.com/amajorai/ryu/main/install.sh | sh
#
# Installs and starts the headless stack — ryu-core, ryu-gateway, ryu-cli — in
# ~/.ryu/bin. Starting Core is part of the install so the same entry point also
# kicks off the bundled models, engines, skills, and built-in defaults. Core owns
# those defaults; this script is the cross-surface bootstrap that starts them.
# Shadow and Ghost are preinstalled and started by Core. Island is preinstalled
# and kept up to date through the global download center, but remains stopped
# until the companion feature is enabled in a later release.
#
# Environment overrides:
# RYU_INSTALL_DIR install location (default: $HOME/.ryu/bin)
# RYU_VERSION release tag e.g. v0.0.4 (default: latest)
# RYU_SKIP_CHECKSUM 1 to skip sha256 verify (default: verify, abort on failure)
# RYU_NO_MODIFY_PATH 1 to leave shell rc untouched
# RYU_START_CORE 0 to install binaries without starting Core (default: 1)
# RYU_CORE_BIND Core bind address (default: 127.0.0.1:7980)
# RYU_CORE_URL Core health URL (default: http://127.0.0.1:7980)
# RYU_PROGRESS_FORMAT json to emit RYU_INSTALL_EVENT JSON lines for callers
# RYU_INSTALL_MARKER version marker written beside installed binaries
set -eu
REPO="amajorai/ryu"
INSTALL_DIR="${RYU_INSTALL_DIR:-$HOME/.ryu/bin}"
BINARIES="ryu-core ryu-gateway ryu-cli"
PROGRESS_FORMAT="${RYU_PROGRESS_FORMAT:-human}"
START_CORE="${RYU_START_CORE:-1}"
CORE_BIND="${RYU_CORE_BIND:-127.0.0.1:7980}"
CORE_URL="${RYU_CORE_URL:-http://127.0.0.1:7980}"
INSTALL_MARKER="${RYU_INSTALL_MARKER:-latest}"
FORCE_INSTALL="${RYU_FORCE_INSTALL:-0}"
EVENT_PREFIX="RYU_INSTALL_EVENT:"
info() { printf ' %s\n' "$1"; }
emit() {
[ "$PROGRESS_FORMAT" = "json" ] || return 0
phase="$1"
component="$2"
status="$3"
percent="$4"
printf '%s{"version":1,"phase":"%s","component":"%s","status":"%s","percent":%s}\n' \
"$EVENT_PREFIX" "$phase" "$component" "$status" "$percent"
}
err() { printf 'error: %s\n' "$1" >&2; exit 1; }
fail() {
component="$1"
message="$2"
emit "error" "$component" "failed" 0
err "$message"
}
# --- detect OS/arch and map to release-asset suffix -------------------------
os="$(uname -s)"
arch="$(uname -m)"
case "$os" in
Darwin)
case "$arch" in
arm64|aarch64) suffix="macos-aarch64" ;;
*) err "Intel Macs are not supported by the prebuilt binaries. Build from source: https://github.com/$REPO#quick-start-self-host" ;;
esac
;;
Linux)
case "$arch" in
x86_64|amd64) suffix="linux-x86_64" ;;
*) err "Linux $arch is not supported by the prebuilt binaries (only x86_64). Build from source: https://github.com/$REPO#quick-start-self-host" ;;
esac
;;
*)
err "unsupported OS '$os'. On Windows use install.ps1; see https://github.com/$REPO#quick-start-self-host" ;;
esac
# --- pick a downloader ------------------------------------------------------
if command -v curl >/dev/null 2>&1; then
dl() { curl -fsSL "$1" -o "$2"; }
elif command -v wget >/dev/null 2>&1; then
dl() { wget -qO "$2" "$1"; }
else
err "need curl or wget on PATH"
fi
if [ -n "${RYU_VERSION:-}" ]; then
base="https://github.com/$REPO/releases/download/$RYU_VERSION"
else
base="https://github.com/$REPO/releases/latest/download"
fi
# --- sha256 verification (fail closed) ---------------------------------------
# Releases publish a .sha256 next to every binary, so a missing/failed checksum
# is treated as an error, not a shrug — otherwise a network hiccup (or an
# attacker stripping the checksum) silently disables verification. Emergency
# escape hatch: RYU_SKIP_CHECKSUM=1.
sha_cmd=""
if command -v sha256sum >/dev/null 2>&1; then sha_cmd="sha256sum";
elif command -v shasum >/dev/null 2>&1; then sha_cmd="shasum -a 256"; fi
verify() { # <file> <sha_url>
file="$1"; sha_url="$2"
if [ "${RYU_SKIP_CHECKSUM:-0}" = "1" ]; then
info "RYU_SKIP_CHECKSUM=1 — skipping checksum verification (not recommended)"
return 0
fi
if [ -z "$sha_cmd" ]; then
printf '%s\n' 'error: no sha256 tool (sha256sum/shasum) on PATH — install one, or set RYU_SKIP_CHECKSUM=1 to bypass verification (not recommended)' >&2
return 1
fi
tmp_sha="$file.sha256"
if ! dl "$sha_url" "$tmp_sha"; then
printf 'error: could not download checksum %s — refusing to install an unverified binary (set RYU_SKIP_CHECKSUM=1 to bypass)\n' "$sha_url" >&2
return 1
fi
want="$(awk '{print $1; exit}' "$tmp_sha")"
got="$($sha_cmd "$file" | awk '{print $1}')"
rm -f "$tmp_sha"
if [ "${#want}" -ne 64 ]; then
printf 'error: malformed checksum file at %s — refusing to install (set RYU_SKIP_CHECKSUM=1 to bypass)\n' "$sha_url" >&2
return 1
fi
if [ "$want" != "$got" ]; then
printf 'error: checksum mismatch for %s (want %s, got %s)\n' "$(basename "$file")" "$want" "$got" >&2
return 1
fi
}
# --- install ----------------------------------------------------------------
printf 'Installing Ryu (%s) into %s\n' "$suffix" "$INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
install_binary() {
bin="$1"
ordinal="$2"
asset="$bin-$suffix"
url="$base/$asset"
dest="$INSTALL_DIR/$bin"
out="$tmp/$bin"
before=$(( (ordinal - 1) * 15 ))
after=$(( ordinal * 15 ))
if [ "$FORCE_INSTALL" != "1" ] && [ -x "$dest" ] && [ -f "$dest.version" ] \
&& [ "$(cat "$dest.version")" = "$INSTALL_MARKER" ]; then
info "$bin already installed"
emit "binary" "$bin" "skipped" "$after"
return 0
fi
info "$bin"
emit "binary" "$bin" "started" "$before"
dl "$url" "$out" || fail "$bin" "download failed: $url"
verify "$out" "$url.sha256" || fail "$bin" "verification failed: $url"
chmod +x "$out"
mv "$out" "$dest"
printf '%s\n' "$INSTALL_MARKER" > "$dest.version"
emit "binary" "$bin" "complete" "$after"
}
install_binary ryu-core 1
install_binary ryu-gateway 2
install_binary ryu-cli 3
# --- PATH -------------------------------------------------------------------
added_path=0
case ":$PATH:" in
*":$INSTALL_DIR:"*) ;;
*)
if [ "${RYU_NO_MODIFY_PATH:-0}" != "1" ]; then
line="export PATH=\"$INSTALL_DIR:\$PATH\""
for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.profile"; do
[ -f "$rc" ] || continue
grep -qF "$INSTALL_DIR" "$rc" 2>/dev/null && continue
printf '\n# Ryu\n%s\n' "$line" >> "$rc"
added_path=1
done
fi
;;
esac
printf '\nDone. Installed: %s\n' "$BINARIES"
if [ "$added_path" = "1" ]; then
info "Added $INSTALL_DIR to your PATH — open a new terminal, or run:"
info " export PATH=\"$INSTALL_DIR:\$PATH\""
fi
if [ "$START_CORE" = "1" ]; then
# The desktop and the one-line install now share this exact Core bring-up. The
# Core process owns the default model/engine/skill installers and continues
# those downloads in the background after its health endpoint is ready.
emit "core" "ryu-core" "started" 55
core_log="${RYU_CORE_LOG:-$HOME/.ryu/ryu-core.log}"
core_dir="$(dirname "$core_log")"
mkdir -p "$core_dir"
http_ok() {
if command -v curl >/dev/null 2>&1; then
curl -fsS --max-time 3 "$CORE_URL/api/health" >/dev/null 2>&1
else
wget -qO- --timeout=3 "$CORE_URL/api/health" >/dev/null 2>&1
fi
}
if ! http_ok; then
info "starting Ryu Core"
nohup "$INSTALL_DIR/ryu-core" "--bind=$CORE_BIND" \
>>"$core_log" 2>&1 </dev/null &
else
info "Ryu Core is already running"
fi
healthy=0
attempt=0
while [ "$attempt" -lt 60 ]; do
if http_ok; then
healthy=1
break
fi
attempt=$((attempt + 1))
sleep 1
done
[ "$healthy" = "1" ] || fail "ryu-core" "Ryu Core did not become healthy at $CORE_URL"
emit "core" "ryu-core" "complete" 75
info "Core is provisioning bundled models, engines, skills, and defaults"
emit "defaults" "bundled-defaults" "started" 80
info "Core is preinstalling Shadow, Ghost, and Island (Island stays stopped)"
emit "defaults" "shadow" "started" 85
emit "defaults" "ghost" "started" 90
emit "defaults" "island" "started" 95
fi
emit "bootstrap" "ryu" "complete" 100
cat <<EOF
Next:
ryu-core # already running; bundled defaults continue provisioning
ryu-cli # in another terminal, connect the TUI to it
Point any OpenAI-compatible client at the Gateway: http://127.0.0.1:7981/v1
EOF