@hitechclaw/clawspark 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/LICENSE +21 -0
  3. package/README.md +378 -0
  4. package/clawspark +2715 -0
  5. package/configs/models.yaml +108 -0
  6. package/configs/skill-packs.yaml +44 -0
  7. package/configs/skills.yaml +37 -0
  8. package/install.sh +387 -0
  9. package/lib/common.sh +249 -0
  10. package/lib/detect-hardware.sh +156 -0
  11. package/lib/diagnose.sh +636 -0
  12. package/lib/render-diagram.sh +47 -0
  13. package/lib/sandbox-commands.sh +415 -0
  14. package/lib/secure.sh +244 -0
  15. package/lib/select-model.sh +442 -0
  16. package/lib/setup-browser.sh +138 -0
  17. package/lib/setup-dashboard.sh +228 -0
  18. package/lib/setup-inference.sh +128 -0
  19. package/lib/setup-mcp.sh +142 -0
  20. package/lib/setup-messaging.sh +242 -0
  21. package/lib/setup-models.sh +121 -0
  22. package/lib/setup-openclaw.sh +808 -0
  23. package/lib/setup-sandbox.sh +188 -0
  24. package/lib/setup-skills.sh +113 -0
  25. package/lib/setup-systemd.sh +224 -0
  26. package/lib/setup-tailscale.sh +188 -0
  27. package/lib/setup-voice.sh +101 -0
  28. package/lib/skill-audit.sh +449 -0
  29. package/lib/verify.sh +177 -0
  30. package/package.json +57 -0
  31. package/scripts/release.sh +133 -0
  32. package/uninstall.sh +161 -0
  33. package/v2/README.md +50 -0
  34. package/v2/configs/providers.yaml +79 -0
  35. package/v2/configs/skills.yaml +36 -0
  36. package/v2/install.sh +116 -0
  37. package/v2/lib/common.sh +285 -0
  38. package/v2/lib/detect-hardware.sh +119 -0
  39. package/v2/lib/select-runtime.sh +273 -0
  40. package/v2/lib/setup-extras.sh +95 -0
  41. package/v2/lib/setup-openclaw.sh +187 -0
  42. package/v2/lib/setup-provider.sh +131 -0
  43. package/v2/lib/verify.sh +133 -0
  44. package/web/index.html +1835 -0
  45. package/web/install.sh +387 -0
  46. package/web/logo-hero.svg +11 -0
  47. package/web/logo-icon.svg +12 -0
  48. package/web/logo.svg +17 -0
  49. package/web/vercel.json +8 -0
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env bash
2
+ # lib/setup-sandbox.sh -- Optional Docker-based sandbox for safe code execution.
3
+ # Enables OpenClaw to run agent-generated code in an isolated container.
4
+ # If Docker is not installed, the installer continues without sandbox support.
5
+ set -euo pipefail
6
+
7
+ setup_sandbox() {
8
+ # Install Docker if not available
9
+ if ! check_command docker; then
10
+ log_info "Docker not found. Installing for sandboxed code execution..."
11
+ if check_command apt-get; then
12
+ # Linux: install via official Docker convenience script
13
+ (curl -fsSL https://get.docker.com | sh) >> "${CLAWSPARK_LOG}" 2>&1 &
14
+ spinner $! "Installing Docker..."
15
+ if check_command docker; then
16
+ # Add current user to docker group so we don't need sudo
17
+ sudo usermod -aG docker "${USER}" 2>> "${CLAWSPARK_LOG}" || true
18
+ # Start Docker daemon
19
+ sudo systemctl start docker 2>> "${CLAWSPARK_LOG}" || true
20
+ sudo systemctl enable docker 2>> "${CLAWSPARK_LOG}" || true
21
+ log_success "Docker installed."
22
+ else
23
+ log_warn "Docker installation failed -- sandbox will not be available."
24
+ return 0
25
+ fi
26
+ elif check_command brew; then
27
+ log_info "Installing Docker via Homebrew..."
28
+ (brew install --cask docker) >> "${CLAWSPARK_LOG}" 2>&1 &
29
+ spinner $! "Installing Docker..."
30
+ if [[ -d "/Applications/Docker.app" ]]; then
31
+ log_success "Docker installed. Open Docker.app to start the daemon."
32
+ log_warn "Docker daemon not running yet -- sandbox will be available after starting Docker."
33
+ return 0
34
+ else
35
+ log_warn "Docker installation failed -- sandbox will not be available."
36
+ return 0
37
+ fi
38
+ else
39
+ log_warn "No package manager found -- install Docker manually for sandbox support."
40
+ return 0
41
+ fi
42
+ fi
43
+
44
+ # Check if Docker daemon is running
45
+ if ! docker info &>/dev/null; then
46
+ # Try to start it
47
+ if check_command systemctl; then
48
+ sudo systemctl start docker 2>> "${CLAWSPARK_LOG}" || true
49
+ sleep 2
50
+ fi
51
+ if ! docker info &>/dev/null; then
52
+ log_warn "Docker is installed but daemon is not running -- sandbox skipped."
53
+ log_info "Start Docker and run: clawspark sandbox on"
54
+ return 0
55
+ fi
56
+ fi
57
+
58
+ log_info "Setting up Docker sandbox for safe code execution..."
59
+
60
+ # ── Create sandbox directory and Dockerfile ───────────────────────────────
61
+ local sandbox_dir="${CLAWSPARK_DIR}/sandbox"
62
+ mkdir -p "${sandbox_dir}"
63
+
64
+ cat > "${sandbox_dir}/Dockerfile" <<'DOCKERFILE'
65
+ FROM ubuntu:22.04
66
+
67
+ # Non-interactive apt
68
+ ENV DEBIAN_FRONTEND=noninteractive
69
+
70
+ # Install common dev tools
71
+ RUN apt-get update && apt-get install -y --no-install-recommends \
72
+ python3 python3-pip python3-venv \
73
+ nodejs npm \
74
+ git curl wget jq \
75
+ build-essential \
76
+ && rm -rf /var/lib/apt/lists/*
77
+
78
+ # Create non-root user
79
+ RUN useradd -m -s /bin/bash sandbox
80
+ USER sandbox
81
+ WORKDIR /sandbox
82
+
83
+ # Set up Python virtual env
84
+ RUN python3 -m venv /sandbox/.venv
85
+ ENV PATH="/sandbox/.venv/bin:$PATH"
86
+
87
+ # Install common Python packages
88
+ RUN pip install --no-cache-dir \
89
+ requests flask fastapi uvicorn \
90
+ pandas numpy matplotlib \
91
+ beautifulsoup4 lxml
92
+
93
+ CMD ["/bin/bash"]
94
+ DOCKERFILE
95
+
96
+ # ── Seccomp profile (block dangerous syscalls) ────────────────────────────
97
+ cat > "${sandbox_dir}/seccomp-profile.json" <<'SECCOMP'
98
+ {
99
+ "defaultAction": "SCMP_ACT_ALLOW",
100
+ "syscalls": [
101
+ {
102
+ "names": [
103
+ "mount", "umount2", "pivot_root",
104
+ "swapon", "swapoff",
105
+ "reboot", "kexec_load", "kexec_file_load",
106
+ "init_module", "finit_module", "delete_module",
107
+ "acct", "settimeofday", "clock_settime",
108
+ "ptrace",
109
+ "add_key", "request_key", "keyctl",
110
+ "unshare", "setns"
111
+ ],
112
+ "action": "SCMP_ACT_ERRNO",
113
+ "errnoRet": 1
114
+ }
115
+ ]
116
+ }
117
+ SECCOMP
118
+
119
+ # ── Build the sandbox image ───────────────────────────────────────────────
120
+ log_info "Building sandbox image (this may take a minute)..."
121
+ (docker build -t clawspark-sandbox:latest "${sandbox_dir}") >> "${CLAWSPARK_LOG}" 2>&1 &
122
+ spinner $! "Building clawspark-sandbox image..."
123
+
124
+ if docker image inspect clawspark-sandbox:latest &>/dev/null; then
125
+ log_success "Sandbox image built: clawspark-sandbox:latest"
126
+ else
127
+ log_warn "Sandbox image build failed. Check ${CLAWSPARK_LOG}."
128
+ return 0
129
+ fi
130
+
131
+ # NOTE: We do NOT write sandbox config to openclaw.json during install.
132
+ # Setting agents.defaults.sandbox with network:"none" breaks the main agent's
133
+ # network access. The sandbox image and seccomp profile are ready for use via
134
+ # "clawspark sandbox on" which will enable it when the user explicitly wants it.
135
+ # The sandbox run.sh helper works standalone without any openclaw.json changes.
136
+
137
+ # Persist sandbox state as "off" (available but not active)
138
+ echo "false" > "${CLAWSPARK_DIR}/sandbox.state"
139
+ log_success "Sandbox image and seccomp profile ready."
140
+ log_info "Enable later with: clawspark sandbox on"
141
+
142
+ # ── Helper script for manual sandbox use ──────────────────────────────────
143
+ cat > "${sandbox_dir}/run.sh" <<'RUNSH'
144
+ #!/usr/bin/env bash
145
+ # run.sh -- Run a command inside the clawspark sandbox.
146
+ # Usage: ~/.clawspark/sandbox/run.sh <command>
147
+ # Example: ~/.clawspark/sandbox/run.sh python3 -c "print('hello')"
148
+ set -euo pipefail
149
+
150
+ SANDBOX_DIR="${HOME}/.clawspark/sandbox"
151
+
152
+ if ! command -v docker &>/dev/null; then
153
+ echo "Error: Docker is not installed." >&2
154
+ exit 1
155
+ fi
156
+
157
+ if ! docker info &>/dev/null; then
158
+ echo "Error: Docker daemon is not running." >&2
159
+ exit 1
160
+ fi
161
+
162
+ if ! docker image inspect clawspark-sandbox:latest &>/dev/null; then
163
+ echo "Error: Sandbox image not found. Run install.sh or rebuild with:" >&2
164
+ echo " docker build -t clawspark-sandbox:latest ${SANDBOX_DIR}" >&2
165
+ exit 1
166
+ fi
167
+
168
+ docker run --rm -it \
169
+ --read-only \
170
+ --tmpfs /tmp:size=100m \
171
+ --tmpfs /sandbox/work:size=500m \
172
+ --network=none \
173
+ --cap-drop=ALL \
174
+ --security-opt=no-new-privileges \
175
+ --security-opt="seccomp=${SANDBOX_DIR}/seccomp-profile.json" \
176
+ --memory=1g \
177
+ --cpus=2 \
178
+ --pids-limit=200 \
179
+ -v "${PWD}:/sandbox/code:ro" \
180
+ clawspark-sandbox:latest \
181
+ "$@"
182
+ RUNSH
183
+ chmod +x "${sandbox_dir}/run.sh"
184
+
185
+ log_success "Sandbox setup complete."
186
+ log_info "Sub-agent code execution will run in isolated Docker containers."
187
+ log_info "Manual use: ~/.clawspark/sandbox/run.sh <command>"
188
+ }
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bash
2
+ # lib/setup-skills.sh — Reads skills.yaml and installs each enabled skill via clawhub.
3
+ set -euo pipefail
4
+
5
+ setup_skills() {
6
+ log_info "Installing OpenClaw skills..."
7
+ hr
8
+
9
+ # ── Locate skills.yaml ──────────────────────────────────────────────────
10
+ local skills_file=""
11
+ local search_paths=(
12
+ "${CLAWSPARK_DIR}/skills.yaml"
13
+ "${SCRIPT_DIR:-/opt/clawspark}/configs/skills.yaml"
14
+ )
15
+
16
+ for candidate in "${search_paths[@]}"; do
17
+ if [[ -f "${candidate}" ]]; then
18
+ skills_file="${candidate}"
19
+ break
20
+ fi
21
+ done
22
+
23
+ if [[ -z "${skills_file}" ]]; then
24
+ log_warn "No skills.yaml found — skipping skill installation."
25
+ return 0
26
+ fi
27
+
28
+ log_info "Using skills config: ${skills_file}"
29
+
30
+ # Copy to CLAWSPARK_DIR if not already there
31
+ if [[ "${skills_file}" != "${CLAWSPARK_DIR}/skills.yaml" ]]; then
32
+ cp "${skills_file}" "${CLAWSPARK_DIR}/skills.yaml"
33
+ fi
34
+
35
+ local -a skills=()
36
+ while IFS= read -r slug; do
37
+ skills+=("${slug}")
38
+ done < <(_parse_enabled_skills "${skills_file}")
39
+
40
+ if [[ ${#skills[@]} -eq 0 ]]; then
41
+ log_warn "No skills found under 'enabled:' in ${skills_file}."
42
+ return 0
43
+ fi
44
+
45
+ log_info "Found ${#skills[@]} skill(s) to install."
46
+
47
+ # ── Fix npm cache permissions (root-owned ~/.npm from sudo npm) ─────────
48
+ _fix_npm_cache_perms
49
+
50
+ # ── Install each skill ──────────────────────────────────────────────────
51
+ local installed=0
52
+ local failed=0
53
+
54
+ local skill_timeout=120 # 2 minutes max per skill
55
+
56
+ for skill in "${skills[@]}"; do
57
+ printf ' %s→%s Installing %s%s%s ... ' "${CYAN}" "${RESET}" "${BOLD}" "${skill}" "${RESET}"
58
+ if timeout "${skill_timeout}" npx --yes clawhub@latest install --force "${skill}" >> "${CLAWSPARK_LOG}" 2>&1; then
59
+ printf '%s✓%s\n' "${GREEN}" "${RESET}"
60
+ installed=$(( installed + 1 ))
61
+ else
62
+ local ec=$?
63
+ if [[ ${ec} -eq 124 ]]; then
64
+ printf '%s✗ (timed out after %ds, skipping)%s\n' "${YELLOW}" "${skill_timeout}" "${RESET}"
65
+ else
66
+ printf '%s✗ (failed, continuing)%s\n' "${YELLOW}" "${RESET}"
67
+ fi
68
+ log_warn "Skill '${skill}' failed to install — see ${CLAWSPARK_LOG}"
69
+ failed=$(( failed + 1 ))
70
+ fi
71
+ done
72
+
73
+ printf '\n'
74
+ log_success "Skills installed: ${installed} succeeded, ${failed} failed."
75
+
76
+ # ── Install essential community skills (web search, research) ─────────
77
+ _install_community_skills
78
+ }
79
+
80
+ # ── Community skills that don't need API keys ─────────────────────────────
81
+ _install_community_skills() {
82
+ log_info "Installing community web search skills..."
83
+ local -a community_skills=(
84
+ "ddg-web-search"
85
+ "deep-research-pro"
86
+ "local-web-search-skill"
87
+ )
88
+ for skill in "${community_skills[@]}"; do
89
+ printf ' %s->%s Installing %s%s%s ... ' "${CYAN}" "${RESET}" "${BOLD}" "${skill}" "${RESET}"
90
+ if timeout 120 npx --yes clawhub@latest install --force "${skill}" >> "${CLAWSPARK_LOG}" 2>&1; then
91
+ printf '%sOK%s\n' "${GREEN}" "${RESET}"
92
+ else
93
+ printf '%sskipped%s\n' "${YELLOW}" "${RESET}"
94
+ fi
95
+ done
96
+ log_success "Community skills installed (web search, deep research)."
97
+ }
98
+
99
+ # ── Fix root-owned npm cache (common after sudo npm install -g) ───────────
100
+ _fix_npm_cache_perms() {
101
+ local npm_cache="${HOME}/.npm"
102
+ if [[ -d "${npm_cache}" ]]; then
103
+ # Check if any files are owned by root (uid 0)
104
+ local root_files
105
+ root_files=$(find "${npm_cache}" -maxdepth 2 -uid 0 2>/dev/null | head -1)
106
+ if [[ -n "${root_files}" ]]; then
107
+ log_info "Fixing npm cache permissions (root-owned files in ~/.npm)..."
108
+ sudo chown -R "$(id -u):$(id -g)" "${npm_cache}" 2>/dev/null || {
109
+ log_warn "Could not fix ~/.npm permissions. Skills may fail to install."
110
+ }
111
+ fi
112
+ fi
113
+ }
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env bash
2
+ # lib/setup-systemd.sh -- Creates systemd services for OpenClaw gateway,
3
+ # node host, and ClawMetry dashboard so they auto-start on boot.
4
+ # Skipped on platforms without systemd (macOS, containers).
5
+ set -euo pipefail
6
+
7
+ setup_systemd_services() {
8
+ # Skip on non-systemd platforms (macOS, Docker, WSL1, etc.)
9
+ if ! check_command systemctl; then
10
+ log_info "systemd not available -- services will use PID-based management."
11
+ return 0
12
+ fi
13
+
14
+ # Verify systemd is actually running (not just the binary present)
15
+ # is-system-running returns non-zero for "degraded" (common when minor
16
+ # services fail), so we must check the output text, not the exit code.
17
+ local sys_state
18
+ sys_state=$(systemctl is-system-running 2>/dev/null || true)
19
+ case "${sys_state}" in
20
+ running|degraded|starting|initializing)
21
+ log_info "systemd active (state: ${sys_state})."
22
+ ;;
23
+ *)
24
+ log_info "systemd not active (state: ${sys_state}) -- skipping service creation."
25
+ return 0
26
+ ;;
27
+ esac
28
+
29
+ log_info "Creating systemd services for auto-start on boot..."
30
+
31
+ local user_name
32
+ user_name=$(whoami)
33
+ local user_home="${HOME}"
34
+
35
+ # Find binary paths
36
+ local openclaw_bin
37
+ openclaw_bin=$(command -v openclaw 2>/dev/null || echo "")
38
+ if [[ -z "${openclaw_bin}" ]]; then
39
+ local npm_bin
40
+ npm_bin="$(npm config get prefix 2>/dev/null)/bin"
41
+ [[ -x "${npm_bin}/openclaw" ]] && openclaw_bin="${npm_bin}/openclaw"
42
+ fi
43
+
44
+ if [[ -z "${openclaw_bin}" ]]; then
45
+ log_warn "openclaw binary not found -- skipping systemd setup."
46
+ return 0
47
+ fi
48
+
49
+ local env_file="${user_home}/.openclaw/gateway.env"
50
+
51
+ # Compute a comprehensive PATH for systemd (it starts with minimal PATH)
52
+ # The env file also has PATH, but belt-and-suspenders is safer here
53
+ local npm_prefix_bin
54
+ npm_prefix_bin="$(npm config get prefix 2>/dev/null)/bin"
55
+ local svc_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
56
+ [[ -d "${npm_prefix_bin}" ]] && svc_path="${npm_prefix_bin}:${svc_path}"
57
+ [[ -d "${user_home}/.npm-global/bin" ]] && svc_path="${user_home}/.npm-global/bin:${svc_path}"
58
+ [[ -d "/snap/bin" ]] && svc_path="${svc_path}:/snap/bin"
59
+
60
+ # ── Gateway service ──────────────────────────────────────────────────────
61
+ sudo tee /etc/systemd/system/clawspark-gateway.service > /dev/null <<GWEOF
62
+ [Unit]
63
+ Description=clawspark OpenClaw Gateway
64
+ After=network.target ollama.service
65
+ Wants=ollama.service
66
+
67
+ [Service]
68
+ Type=simple
69
+ User=${user_name}
70
+ Environment=HOME=${user_home}
71
+ Environment=PATH=${svc_path}
72
+ EnvironmentFile=-${env_file}
73
+ ExecStart=${openclaw_bin} gateway run --bind loopback
74
+ Restart=on-failure
75
+ RestartSec=5
76
+ StandardOutput=append:${user_home}/.clawspark/gateway.log
77
+ StandardError=append:${user_home}/.clawspark/gateway.log
78
+
79
+ [Install]
80
+ WantedBy=multi-user.target
81
+ GWEOF
82
+ log_success "Created clawspark-gateway.service"
83
+
84
+ # ── Node host service ────────────────────────────────────────────────────
85
+ sudo tee /etc/systemd/system/clawspark-nodehost.service > /dev/null <<NHEOF
86
+ [Unit]
87
+ Description=clawspark OpenClaw Node Host
88
+ After=clawspark-gateway.service
89
+ Requires=clawspark-gateway.service
90
+
91
+ [Service]
92
+ Type=simple
93
+ User=${user_name}
94
+ Environment=HOME=${user_home}
95
+ Environment=PATH=${svc_path}
96
+ EnvironmentFile=-${env_file}
97
+ ExecStartPre=/bin/sleep 3
98
+ ExecStart=${openclaw_bin} node run --host 127.0.0.1 --port 18789
99
+ Restart=on-failure
100
+ RestartSec=5
101
+ StandardOutput=append:${user_home}/.clawspark/node.log
102
+ StandardError=append:${user_home}/.clawspark/node.log
103
+
104
+ [Install]
105
+ WantedBy=multi-user.target
106
+ NHEOF
107
+ log_success "Created clawspark-nodehost.service"
108
+
109
+ # ── Dashboard service ────────────────────────────────────────────────────
110
+ local clawmetry_bin=""
111
+ if command -v clawmetry &>/dev/null; then
112
+ clawmetry_bin=$(command -v clawmetry)
113
+ elif [[ -x "${user_home}/.local/bin/clawmetry" ]]; then
114
+ clawmetry_bin="${user_home}/.local/bin/clawmetry"
115
+ fi
116
+
117
+ if [[ -n "${clawmetry_bin}" ]]; then
118
+ sudo tee /etc/systemd/system/clawspark-dashboard.service > /dev/null <<DBEOF
119
+ [Unit]
120
+ Description=clawspark ClawMetry Dashboard
121
+ After=network.target
122
+
123
+ [Service]
124
+ Type=simple
125
+ User=${user_name}
126
+ Environment=HOME=${user_home}
127
+ ExecStart=${clawmetry_bin} --port 8900 --host 127.0.0.1
128
+ Restart=on-failure
129
+ RestartSec=5
130
+ StandardOutput=append:${user_home}/.clawspark/dashboard.log
131
+ StandardError=append:${user_home}/.clawspark/dashboard.log
132
+
133
+ [Install]
134
+ WantedBy=multi-user.target
135
+ DBEOF
136
+ log_success "Created clawspark-dashboard.service"
137
+ else
138
+ log_info "clawmetry binary not found -- dashboard service not created."
139
+ fi
140
+
141
+ # ── Enable all services ──────────────────────────────────────────────────
142
+ sudo systemctl daemon-reload
143
+
144
+ sudo systemctl enable clawspark-gateway.service >> "${CLAWSPARK_LOG}" 2>&1 || true
145
+ sudo systemctl enable clawspark-nodehost.service >> "${CLAWSPARK_LOG}" 2>&1 || true
146
+ if [[ -n "${clawmetry_bin}" ]]; then
147
+ sudo systemctl enable clawspark-dashboard.service >> "${CLAWSPARK_LOG}" 2>&1 || true
148
+ fi
149
+
150
+ log_success "Systemd services enabled -- will auto-start on boot."
151
+
152
+ # ── Migrate running nohup processes to systemd ───────────────────────────
153
+ # Stop the nohup-started processes and let systemd take over.
154
+ # This ensures a clean state right now, not just after next reboot.
155
+ log_info "Migrating running services to systemd..."
156
+
157
+ # Helper: safely kill a PID from a pid file (validates numeric + process identity)
158
+ _safe_kill_pid() {
159
+ local pid_file="$1" name_hint="$2"
160
+ if [[ -f "${pid_file}" ]]; then
161
+ local pid
162
+ pid=$(cat "${pid_file}" 2>/dev/null || echo "")
163
+ if [[ -n "${pid}" ]] && [[ "${pid}" =~ ^[0-9]+$ ]]; then
164
+ # Verify the PID belongs to an openclaw/clawmetry process
165
+ local proc_cmd
166
+ proc_cmd=$(ps -p "${pid}" -o comm= 2>/dev/null || echo "")
167
+ if [[ "${proc_cmd}" == *"openclaw"* ]] || [[ "${proc_cmd}" == *"clawmetry"* ]] || [[ "${proc_cmd}" == *"python"* ]]; then
168
+ kill "${pid}" 2>/dev/null || true
169
+ fi
170
+ fi
171
+ rm -f "${pid_file}"
172
+ fi
173
+ }
174
+
175
+ _safe_kill_pid "${CLAWSPARK_DIR}/gateway.pid" "gateway"
176
+ _safe_kill_pid "${CLAWSPARK_DIR}/node.pid" "node"
177
+ _safe_kill_pid "${CLAWSPARK_DIR}/dashboard.pid" "dashboard"
178
+
179
+ sleep 2
180
+
181
+ # Start via systemd
182
+ sudo systemctl start clawspark-gateway.service || {
183
+ log_warn "Gateway systemd start failed. Check: sudo journalctl -u clawspark-gateway"
184
+ }
185
+ sleep 3
186
+ sudo systemctl start clawspark-nodehost.service || {
187
+ log_warn "Node host systemd start failed. Check: sudo journalctl -u clawspark-nodehost"
188
+ }
189
+ if [[ -n "${clawmetry_bin}" ]]; then
190
+ sudo systemctl start clawspark-dashboard.service || {
191
+ log_warn "Dashboard systemd start failed. Check: sudo journalctl -u clawspark-dashboard"
192
+ }
193
+ fi
194
+
195
+ # Verify
196
+ sleep 3
197
+ local all_ok=true
198
+ if sudo systemctl is-active --quiet clawspark-gateway.service; then
199
+ log_success "Gateway running via systemd."
200
+ else
201
+ log_warn "Gateway not running via systemd."
202
+ all_ok=false
203
+ fi
204
+ if sudo systemctl is-active --quiet clawspark-nodehost.service; then
205
+ log_success "Node host running via systemd."
206
+ else
207
+ log_warn "Node host not running via systemd."
208
+ all_ok=false
209
+ fi
210
+ if [[ -n "${clawmetry_bin}" ]]; then
211
+ if sudo systemctl is-active --quiet clawspark-dashboard.service; then
212
+ log_success "Dashboard running via systemd."
213
+ else
214
+ log_warn "Dashboard not running via systemd."
215
+ all_ok=false
216
+ fi
217
+ fi
218
+
219
+ if [[ "${all_ok}" == "true" ]]; then
220
+ log_success "All services running via systemd. They will auto-start on boot."
221
+ else
222
+ log_warn "Some services failed to start via systemd. Use 'clawspark restart' or check journalctl."
223
+ fi
224
+ }