#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" SKILL_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)" HOME_DIR="${HOME:?HOME is required}" WORKSPACE_DEFAULT="$HOME_DIR/.openclaw/workspace" WORKSPACE="${WATCHDOG_B_WORKSPACE:-$WORKSPACE_DEFAULT}" LIVE_SCRIPT_DIR="${WATCHDOG_B_LIVE_SCRIPT_DIR:-$WORKSPACE/scripts/watchdog-b}" SYSTEMD_USER_DIR="${WATCHDOG_B_SYSTEMD_USER_DIR:-$HOME_DIR/.config/systemd/user}" CONFIG_DIR="${WATCHDOG_B_CONFIG_DIR:-$HOME_DIR/.config/openclaw}" CONFIG_FILE="${WATCHDOG_B_CONFIG_FILE:-$CONFIG_DIR/watchdog-b.env}" PROBE_SCRIPT="${WATCHDOG_B_RUNTIME_PROBE:-$SCRIPT_DIR/openclaw_runtime_probe.py}" NODE_BIN_RAW="${WATCHDOG_B_NODE_BIN:-}" OPENCLAW_MJS="${WATCHDOG_B_OPENCLAW_MJS:-}" OPENCLAW_ENTRY="${WATCHDOG_B_OPENCLAW_ENTRY:-}" OWNER_REPORT_PRODUCER="${WATCHDOG_B_OWNER_PRODUCER:-$LIVE_SCRIPT_DIR/owner_report_producer.py}" OWNER_REPORT_DRIVER="${WATCHDOG_B_OWNER_DRIVER:-$LIVE_SCRIPT_DIR/owner_report_driver.py}" OWNER_REPORT_CONSUMER_DEFAULT="$LIVE_SCRIPT_DIR/owner_report_consumer.py" OWNER_REPORT_CONSUMER="${WATCHDOG_B_OWNER_REPORT_CONSUMER:-$OWNER_REPORT_CONSUMER_DEFAULT}" FAILURES=0 pass() { echo "[PASS] $*"; } warn() { echo "[WARN] $*"; } fail() { echo "[FAIL] $*"; FAILURES=$((FAILURES+1)); } check_exists() { local path="$1" label="$2" if [[ -e "$path" ]]; then pass "$label: $path" else fail "$label missing: $path" fi } check_exec_path() { local raw="$1" label="$2" local resolved="" if [[ "$raw" == */* ]]; then resolved="$raw" if [[ -x "$resolved" ]]; then pass "$label executable: $resolved" else fail "$label not executable: $resolved" fi return fi if resolved="$(command -v "$raw" 2>/dev/null)"; then pass "$label on PATH: $resolved" else fail "$label not found on PATH: $raw" fi } check_systemd_user() { if ! command -v systemctl >/dev/null 2>&1; then fail "systemctl not found" return fi if systemctl --user --version >/dev/null 2>&1; then pass "systemd --user command available" else fail "systemd --user unavailable" fi if systemctl --user show-environment >/dev/null 2>&1; then pass "systemd --user bus reachable" else warn "systemd --user bus not reachable in current session" fi } check_env_target() { if [[ ! -f "$CONFIG_FILE" ]]; then warn "config file not present yet: $CONFIG_FILE" return fi local target="" target="$(awk -F= '/^WATCHDOG_B_OWNER_REPORT_TARGET=/{print $2}' "$CONFIG_FILE" | tail -n 1 | tr -d '[:space:]' || true)" if [[ -z "$target" ]]; then fail "WATCHDOG_B_OWNER_REPORT_TARGET missing in $CONFIG_FILE" elif [[ "$target" == "channel:REPLACE_ME" ]]; then fail "WATCHDOG_B_OWNER_REPORT_TARGET still placeholder in $CONFIG_FILE" elif [[ "$target" == channel:* || "$target" == user:* ]]; then pass "WATCHDOG_B_OWNER_REPORT_TARGET looks configured: $target" else warn "WATCHDOG_B_OWNER_REPORT_TARGET present but format is unusual: $target" fi } probe_runtime() { if [[ ! -f "$PROBE_SCRIPT" ]]; then fail "runtime probe missing: $PROBE_SCRIPT" return fi local probe_output="" if ! probe_output="$(python3 "$PROBE_SCRIPT" --shell 2>/dev/null)"; then fail "runtime probe failed; set WATCHDOG_B_NODE_BIN / WATCHDOG_B_OPENCLAW_MJS / WATCHDOG_B_OPENCLAW_ENTRY explicitly" return fi while IFS='=' read -r key value; do case "$key" in WATCHDOG_B_NODE_BIN) NODE_BIN_RAW="$value" ;; WATCHDOG_B_OPENCLAW_MJS) OPENCLAW_MJS="$value" ;; WATCHDOG_B_OPENCLAW_ENTRY) OPENCLAW_ENTRY="$value" ;; esac done <<< "$probe_output" pass "runtime probe resolved node/openclaw paths" } check_message_cli() { probe_runtime if [[ -n "$OPENCLAW_ENTRY" && -f "$OPENCLAW_ENTRY" ]]; then pass "openclaw entry present: $OPENCLAW_ENTRY" else fail "openclaw entry missing: ${OPENCLAW_ENTRY:-}" fi if [[ -n "$OPENCLAW_MJS" && -f "$OPENCLAW_MJS" ]]; then pass "openclaw mjs present: $OPENCLAW_MJS" else fail "openclaw mjs missing: ${OPENCLAW_MJS:-}" fi } echo "watchdog-discord-route bootstrap" echo "- skill_dir: $SKILL_DIR" echo "- workspace: $WORKSPACE" echo "- live_script_dir: $LIVE_SCRIPT_DIR" echo "- systemd_user_dir: $SYSTEMD_USER_DIR" echo "- config_file: $CONFIG_FILE" echo echo "[bundle]" check_exists "$SCRIPT_DIR/check_openclaw_state.sh" "bundled checker" check_exists "$SCRIPT_DIR/run_watchdog_b.sh" "bundled runner" check_exists "$SCRIPT_DIR/notify_watchdog_b.py" "bundled notifier" check_exists "$SCRIPT_DIR/openclaw_runtime_probe.py" "bundled runtime probe" check_exists "$SCRIPT_DIR/openclaw-watchdog-b.service" "bundled service" check_exists "$SCRIPT_DIR/openclaw-watchdog-b.timer" "bundled timer" check_exists "$SCRIPT_DIR/watchdog-b.env.example" "bundled env example" echo echo "[workspace/live paths]" check_exists "$WORKSPACE" "workspace" check_exists "$LIVE_SCRIPT_DIR" "live script dir" check_exists "$OWNER_REPORT_CONSUMER" "live owner_report_consumer.py" check_exists "$OWNER_REPORT_PRODUCER" "live owner_report_producer.py" check_exists "$OWNER_REPORT_DRIVER" "live owner_report_driver.py" echo echo "[runtime]" check_message_cli if [[ -n "$NODE_BIN_RAW" ]]; then check_exec_path "$NODE_BIN_RAW" "node" else fail "node runtime unresolved" fi check_exec_path "python3" "python3" check_systemd_user echo echo "[discord-route minimal config]" check_env_target if [[ $FAILURES -gt 0 ]]; then echo fail "bootstrap failed with $FAILURES issue(s)" exit 1 fi echo pass "bootstrap checks passed"