-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·387 lines (341 loc) · 16.8 KB
/
install.sh
File metadata and controls
executable file
·387 lines (341 loc) · 16.8 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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
#!/usr/bin/env bash
# install.sh — clawspark one-click installer.
# Sets up OpenClaw with a local LLM on NVIDIA DGX Spark, Jetson, or RTX hardware.
#
# Quick start:
# curl -fsSL https://clawspark.dev/install.sh | bash
#
# Or clone and run:
# git clone https://github.com/theshiphq/claw-spark && cd claw-spark && bash install.sh
set -euo pipefail
# ── Bootstrap: if piped from curl, clone the repo and re-exec ─────────────
SCRIPT_DIR=""
if [[ -n "${BASH_SOURCE[0]:-}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd 2>/dev/null || true)"
fi
if [[ -z "${SCRIPT_DIR}" ]] || [[ ! -d "${SCRIPT_DIR}/lib" ]]; then
# Running via curl pipe -- no lib/ available, need to clone
CLONE_DIR="$(mktemp -d)/claw-spark"
echo "Downloading clawspark..."
if command -v git &>/dev/null; then
git clone --depth 1 https://github.com/theshiphq/claw-spark.git "${CLONE_DIR}" 2>/dev/null
else
# Fallback: download tarball if git is not available
mkdir -p "${CLONE_DIR}"
curl -fsSL https://github.com/theshiphq/claw-spark/archive/refs/heads/main.tar.gz \
| tar xz --strip-components=1 -C "${CLONE_DIR}"
fi
# Re-exec from the cloned repo, reconnecting stdin to the terminal
# so interactive prompts work (curl pipe leaves stdin at EOF).
# Prefer Homebrew bash on macOS (system bash is 3.2, too old).
_REEXEC_BASH="bash"
if [[ "$(uname)" == "Darwin" ]]; then
if [[ -x /opt/homebrew/bin/bash ]]; then
_REEXEC_BASH=/opt/homebrew/bin/bash
elif [[ -x /usr/local/bin/bash ]]; then
_REEXEC_BASH=/usr/local/bin/bash
fi
fi
exec "${_REEXEC_BASH}" "${CLONE_DIR}/install.sh" "$@" </dev/tty
fi
# ── Parse command-line flags ────────────────────────────────────────────────
CLAWSPARK_DEFAULTS="${CLAWSPARK_DEFAULTS:-false}"
AIR_GAP="false"
FLAG_MODEL=""
FLAG_MESSAGING=""
DEPLOY_MODE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--defaults)
CLAWSPARK_DEFAULTS="true"
shift ;;
--air-gap|--airgap)
AIR_GAP="true"
shift ;;
--model=*)
FLAG_MODEL="${1#*=}"
shift ;;
--messaging=*)
FLAG_MESSAGING="${1#*=}"
shift ;;
-h|--help)
cat <<HELP
Usage: install.sh [OPTIONS]
Options:
--defaults Skip all interactive prompts (use defaults)
--air-gap Enable air-gap mode after setup
--model=<id> Ollama model ID to use (e.g. qwen3.5:35b-a3b)
--messaging=<type> whatsapp | telegram | both | skip
-h, --help Show this help
HELP
exit 0 ;;
*)
echo "Unknown option: $1" >&2
exit 1 ;;
esac
done
export CLAWSPARK_DEFAULTS AIR_GAP FLAG_MODEL FLAG_MESSAGING DEPLOY_MODE
# ── Require bash 4.2+ (macOS ships 3.2 which lacks nameref, ${var,,}, etc.) ─
if [[ "${BASH_VERSINFO[0]}" -lt 4 ]] || { [[ "${BASH_VERSINFO[0]}" -eq 4 ]] && [[ "${BASH_VERSINFO[1]}" -lt 2 ]]; }; then
echo ""
echo "ERROR: Bash 4.2+ is required (you have ${BASH_VERSION})."
echo ""
if [[ "$(uname)" == "Darwin" ]]; then
echo "macOS ships with bash 3.2. Install modern bash with Homebrew:"
echo ""
echo " brew install bash"
echo ""
echo "Then re-run the installer with:"
echo ""
echo " /opt/homebrew/bin/bash <(curl -fsSL https://clawspark.dev/install.sh)"
echo ""
else
echo "Please install bash 4.2+ and re-run the installer."
fi
exit 1
fi
# ── Prepare clawspark directory ─────────────────────────────────────────────
CLAWSPARK_DIR="${HOME}/.clawspark"
mkdir -p "${CLAWSPARK_DIR}"
CLAWSPARK_LOG="${CLAWSPARK_DIR}/install.log"
: > "${CLAWSPARK_LOG}" # truncate / create log
# ── Source library modules ──────────────────────────────────────────────────
_source_lib() {
local lib_dir="${SCRIPT_DIR}/lib"
if [[ ! -d "${lib_dir}" ]]; then
echo "ERROR: Cannot find lib/ directory at ${lib_dir}" >&2
exit 1
fi
local f
for f in \
common.sh \
detect-hardware.sh \
select-model.sh \
setup-inference.sh \
setup-openclaw.sh \
setup-skills.sh \
setup-messaging.sh \
setup-voice.sh \
setup-tailscale.sh \
setup-dashboard.sh \
setup-models.sh \
setup-mcp.sh \
setup-browser.sh \
setup-sandbox.sh \
setup-systemd.sh \
secure.sh \
verify.sh \
; do
if [[ -f "${lib_dir}/${f}" ]]; then
# shellcheck source=/dev/null
source "${lib_dir}/${f}"
else
echo "ERROR: Missing library file: ${lib_dir}/${f}" >&2
exit 1
fi
done
# Store lib location for the CLI tool later
CLAWSPARK_LIB_DIR="${lib_dir}"
}
_source_lib
# ── Error trap ──────────────────────────────────────────────────────────────
_on_error() {
local exit_code=$?
local line_no=$1
log_error "Installation failed at line ${line_no} (exit code ${exit_code})."
log_error "Check the log for details: ${CLAWSPARK_LOG}"
printf '\n %sIf this looks like a bug, please open an issue at:%s\n' "${YELLOW}" "${RESET}"
printf ' https://github.com/theshiphq/claw-spark/issues\n\n'
exit "${exit_code}"
}
trap '_on_error ${LINENO}' ERR
# ── Detect if stdin is a terminal (for curl-pipe support) ───────────────────
if [[ ! -t 0 ]]; then
# Piped from curl — force defaults mode if user can't interact
if [[ ! -t 1 ]]; then
CLAWSPARK_DEFAULTS="true"
fi
fi
# ── ASCII banner ────────────────────────────────────────────────────────────
_show_banner() {
printf '%s' "${RED}"
cat <<'BANNER'
___ _ ___ __ __ ___ ___ ___ ___ _ __
/ __|| | / \\ \ /\ / / / __|| _ \ / \ | _ \| |/ /
| (__ | |__ | (_) |\ V V / \__ \| _/ | (_) || /| <
\___||____| |\___/ \_/\_/ |___/|_| \___/ |_|_\|_|\_\
|_|
BANNER
printf '%s' "${RESET}"
printf '%s' "${CYAN}"
cat <<'CLAW'
_____
/ \
/ () () \
| .____. |
\ \__/ /
___ \______/ ___
/ '-..__ __..-'' \
/ .--._ '' _.---. \
| / ___\ /___ \ |
| | ( \ / ) | |
\ \ '---'/\\'---' / /
'.\_ / \ _/.'
'---' '---'
CLAW
printf '%s' "${RESET}"
printf '\n'
printf ' %s%sOne-click AI agent setup for NVIDIA hardware%s\n' "${BOLD}" "${BLUE}" "${RESET}"
printf ' %sPowered by OpenClaw + Ollama%s\n\n' "${CYAN}" "${RESET}"
hr
}
# ── Step 1: Banner ─────────────────────────────────────────────────────────
log_info "Step 1/19: Welcome"
_show_banner
# ════════════════════════════════════════════════════════════════════════════
# INSTALLATION FLOW
# ════════════════════════════════════════════════════════════════════════════
# ── Cache sudo credentials upfront so the install never pauses for password ──
if sudo -v 2>/dev/null; then
log_info "sudo credentials cached."
# Keep sudo alive in background for the duration of the install
( while true; do sudo -n true 2>/dev/null; sleep 50; done ) &
SUDO_KEEPALIVE_PID=$!
trap 'kill ${SUDO_KEEPALIVE_PID} 2>/dev/null; _on_error ${LINENO}' ERR
trap 'kill ${SUDO_KEEPALIVE_PID} 2>/dev/null' EXIT
else
log_warn "sudo not available. Some steps (firewall, systemd) will be skipped."
fi
# ── Step 2: Hardware detection ──────────────────────────────────────────────
log_info "Step 2/19: Detecting hardware"
detect_hardware
# ── Step 3: Model selection ─────────────────────────────────────────────────
log_info "Step 3/19: Selecting model"
select_model
# ── Step 4: Deployment mode ─────────────────────────────────────────────────
log_info "Step 4/19: Deployment mode"
if [[ -z "${DEPLOY_MODE}" ]]; then
if prompt_yn "Use cloud APIs as fallback? (requires API key)" "n"; then
DEPLOY_MODE="hybrid"
else
DEPLOY_MODE="local"
fi
fi
export DEPLOY_MODE
log_info "Deploy mode: ${DEPLOY_MODE}"
# ── Step 5: Messaging preference ───────────────────────────────────────────
log_info "Step 5/19: Messaging preference"
if [[ -z "${FLAG_MESSAGING}" ]]; then
msg_opts=("WhatsApp" "Telegram" "Both" "Skip")
FLAG_MESSAGING=$(prompt_choice "Connect a messaging platform? (Web UI is always available)" msg_opts 3)
fi
# Lowercase for consistent matching downstream
FLAG_MESSAGING=$(to_lower "${FLAG_MESSAGING}")
export FLAG_MESSAGING
log_info "Messaging: ${FLAG_MESSAGING}"
hr
printf '\n %s%sBeginning installation...%s\n\n' "${BOLD}" "${GREEN}" "${RESET}"
# ── Step 6: Inference engine ────────────────────────────────────────────────
log_info "Step 6/19: Setting up inference engine"
setup_inference
# ── Step 7: OpenClaw ────────────────────────────────────────────────────────
log_info "Step 7/19: Installing OpenClaw"
setup_openclaw
# ── Install the clawspark CLI early so it is available for troubleshooting ──
if [[ -f "${SCRIPT_DIR}/clawspark" ]]; then
sudo cp "${SCRIPT_DIR}/clawspark" /usr/local/bin/clawspark 2>/dev/null || {
cp "${SCRIPT_DIR}/clawspark" "${CLAWSPARK_DIR}/clawspark" 2>/dev/null || true
}
sudo chmod +x /usr/local/bin/clawspark 2>/dev/null || true
fi
if [[ -d "${SCRIPT_DIR}/lib" ]]; then
cp -r "${SCRIPT_DIR}/lib" "${CLAWSPARK_DIR}/"
fi
if [[ -d "${SCRIPT_DIR}/configs" ]]; then
cp -r "${SCRIPT_DIR}/configs" "${CLAWSPARK_DIR}/"
fi
# ── Step 8: Skills ──────────────────────────────────────────────────────────
log_info "Step 8/19: Installing skills"
setup_skills
# ── Step 9: Voice ──────────────────────────────────────────────────────────
log_info "Step 9/19: Setting up voice"
setup_voice
# ── Step 10: Messaging ─────────────────────────────────────────────────────
log_info "Step 10/19: Setting up messaging"
setup_messaging
# ── Step 11: Tailscale ─────────────────────────────────────────────────────
log_info "Step 11/19: Setting up Tailscale"
setup_tailscale
# ── Step 12: Dashboard ─────────────────────────────────────────────────────
log_info "Step 12/19: Setting up dashboard"
setup_dashboard || log_warn "Dashboard setup had issues -- continuing with install."
# ── Step 13: Vision & multi-model ──────────────────────────────────────────
log_info "Step 13/19: Configuring vision and multi-model support"
setup_models || log_warn "Model configuration had issues -- continuing."
# ── Step 14: MCP servers (diagrams, memory, reasoning) ───────────────────
log_info "Step 14/19: Setting up MCP servers"
setup_mcp || log_warn "MCP setup had issues -- continuing."
# ── Step 15: Browser automation ────────────────────────────────────────────
log_info "Step 15/19: Setting up browser automation"
setup_browser || log_warn "Browser setup had issues -- continuing."
# ── Step 16: Docker sandbox ────────────────────────────────────────────────
log_info "Step 16/19: Setting up Docker sandbox"
setup_sandbox || log_warn "Sandbox setup had issues -- continuing."
# ── Step 17: Systemd services ──────────────────────────────────────────────
log_info "Step 17/19: Creating systemd services for auto-start on boot"
setup_systemd_services || log_warn "Systemd setup had issues -- services will use PID management."
# ── Step 18: Security ──────────────────────────────────────────────────────
log_info "Step 18/19: Applying security"
secure_setup
# ── Start node host (after all config changes are done) ───────────────────
# Skip if systemd already started the node host (step 16)
if check_command systemctl && systemctl is-active --quiet clawspark-nodehost.service 2>/dev/null; then
log_info "Node host already running via systemd."
else
log_info "Starting node host..."
_start_node_host || log_warn "Node host failed to start -- you can start it with: clawspark start"
fi
# ── Step 18: Verification ──────────────────────────────────────────────────
log_info "Step 19/19: Verifying installation"
verify_installation
# ── Final CLI refresh (picks up any changes made during install) ──────────
if [[ -f "${SCRIPT_DIR}/clawspark" ]]; then
sudo cp "${SCRIPT_DIR}/clawspark" /usr/local/bin/clawspark 2>/dev/null || true
sudo chmod +x /usr/local/bin/clawspark 2>/dev/null || true
fi
[[ -d "${SCRIPT_DIR}/lib" ]] && cp -r "${SCRIPT_DIR}/lib" "${CLAWSPARK_DIR}/"
[[ -d "${SCRIPT_DIR}/configs" ]] && cp -r "${SCRIPT_DIR}/configs" "${CLAWSPARK_DIR}/"
# ── Final message ───────────────────────────────────────────────────────────
printf '\n'
hr
printf '\n'
printf ' %s%s' "${GREEN}" "${BOLD}"
cat <<'DONE'
__ __ _ _ _ _ _
\ \ / /___ _ _ ( )_ _ ___ __ _| | | ___ ___ | |_| |
\ V // _ \| || | |/| '_/ -_) / _` | | | (_-</ -_)| _|_|
|_| \___/ \_,_| |_| \___| \__,_|_|_| /__/\___| \__(_)
DONE
printf '%s\n' "${RESET}"
_final_urls=()
_final_urls+=("Chat UI: http://localhost:18789/__openclaw__/canvas/")
_final_urls+=("Dashboard: http://localhost:8900")
if [[ -f "${CLAWSPARK_DIR}/tailscale.url" ]]; then
_final_urls+=("Tailscale: $(cat "${CLAWSPARK_DIR}/tailscale.url")")
fi
print_box \
"${BOLD}Next Steps${RESET}" \
"" \
"${_final_urls[@]}" \
"" \
"1. Open the Chat UI in your browser to talk to your agent" \
"2. Or send a message via WhatsApp or Telegram" \
"3. Manage your setup: ${CYAN}clawspark status${RESET}" \
"4. Install skill packs: ${CYAN}clawspark skills pack research${RESET}" \
"5. Switch models: ${CYAN}clawspark model list${RESET}" \
"6. Enable sandbox: ${CYAN}clawspark sandbox on${RESET}" \
"7. View logs: ${CYAN}clawspark logs${RESET}" \
"" \
"Services auto-start on boot (systemd)." \
"Full log: ${CLAWSPARK_LOG}"
printf '\n %sHappy hacking!%s\n\n' "${CYAN}" "${RESET}"