292 lines
11 KiB
Bash
292 lines
11 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# ============================================================================
|
|
# OpenClaw Market — One-click installer
|
|
# Usage: bash <(curl -fsSL https://kymr.top/install.sh) --token <TOKEN>
|
|
# ============================================================================
|
|
|
|
VERSION="1.0.0"
|
|
API_ENDPOINT="https://kymr.top/api/v1"
|
|
CONFIG_DIR="$HOME/.openclaw"
|
|
CONFIG_FILE="$CONFIG_DIR/config.json"
|
|
HEARTBEAT_SCRIPT="$CONFIG_DIR/heartbeat-check.sh"
|
|
TRACK_TOKENS_SCRIPT="$CONFIG_DIR/track-tokens.sh"
|
|
REPORT_TOKENS_SCRIPT="$CONFIG_DIR/report-tokens.sh"
|
|
TOKEN_USAGE_FILE="$CONFIG_DIR/token-usage.json"
|
|
CRON_TAG="# openclaw-market"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
info() { echo -e "${GREEN}[✓]${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
|
error() { echo -e "${RED}[✗]${NC} $1"; }
|
|
step() { echo -e "${CYAN}[→]${NC} $1"; }
|
|
|
|
# ── Parse arguments ─────────────────────────────────────────────────────────
|
|
TOKEN=""
|
|
UNINSTALL=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--token) TOKEN="$2"; shift 2 ;;
|
|
--token=*) TOKEN="${1#*=}"; shift ;;
|
|
--uninstall) UNINSTALL=true; shift ;;
|
|
--help|-h)
|
|
echo "Usage: bash install.sh --token <TOKEN>"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --token <TOKEN> Your OpenClaw token (get it from https://kymr.top)"
|
|
echo " --uninstall Remove OpenClaw and all cron jobs"
|
|
echo " --help Show this help"
|
|
exit 0
|
|
;;
|
|
*) error "Unknown option: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
# ── Uninstall ───────────────────────────────────────────────────────────────
|
|
if [ "$UNINSTALL" = true ]; then
|
|
step "Uninstalling OpenClaw..."
|
|
|
|
# Remove cron jobs
|
|
crontab -l 2>/dev/null | grep -v "$CRON_TAG" | crontab - 2>/dev/null || true
|
|
info "Cron jobs removed"
|
|
|
|
# Remove config directory
|
|
if [ -d "$CONFIG_DIR" ]; then
|
|
rm -rf "$CONFIG_DIR"
|
|
info "Config directory removed: $CONFIG_DIR"
|
|
fi
|
|
|
|
# Optionally remove CLI
|
|
if command -v claw-market &>/dev/null; then
|
|
warn "CLI 'claw-market' is still installed. Run 'npm uninstall -g @ricardweii/claw-market' to remove it."
|
|
fi
|
|
|
|
info "OpenClaw uninstalled successfully!"
|
|
exit 0
|
|
fi
|
|
|
|
# ── Validate token ──────────────────────────────────────────────────────────
|
|
if [ -z "$TOKEN" ]; then
|
|
error "Token is required. Usage: bash install.sh --token <YOUR_TOKEN>"
|
|
echo ""
|
|
echo "Get your token at https://kymr.top"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${CYAN}🦞 OpenClaw Market Installer v${VERSION}${NC}"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
|
|
# ── Check prerequisites ────────────────────────────────────────────────────
|
|
step "Checking prerequisites..."
|
|
|
|
if ! command -v node &>/dev/null; then
|
|
error "Node.js is required but not installed."
|
|
echo " Install it from https://nodejs.org/ or use nvm:"
|
|
echo " curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash"
|
|
exit 1
|
|
fi
|
|
info "Node.js $(node --version) found"
|
|
|
|
if ! command -v npm &>/dev/null; then
|
|
error "npm is required but not installed."
|
|
exit 1
|
|
fi
|
|
info "npm $(npm --version) found"
|
|
|
|
# ── Install CLI ─────────────────────────────────────────────────────────────
|
|
step "Installing claw-market CLI..."
|
|
|
|
if command -v claw-market &>/dev/null; then
|
|
info "claw-market CLI already installed"
|
|
else
|
|
npm install -g @ricardweii/claw-market 2>/dev/null || {
|
|
warn "Global install failed, trying with sudo..."
|
|
sudo npm install -g @ricardweii/claw-market
|
|
}
|
|
info "claw-market CLI installed"
|
|
fi
|
|
|
|
# ── Fetch claw info from server ─────────────────────────────────────────────
|
|
step "Verifying token with server..."
|
|
|
|
CLAW_INFO=$(curl -sf -H "Authorization: Bearer $TOKEN" "${API_ENDPOINT}/heartbeat" \
|
|
-X POST -H "Content-Type: application/json" -d '{}' 2>/dev/null) || {
|
|
error "Invalid token or server unreachable."
|
|
echo " Check your token and try again."
|
|
exit 1
|
|
}
|
|
info "Token verified successfully"
|
|
|
|
# ── Write config ────────────────────────────────────────────────────────────
|
|
step "Writing configuration..."
|
|
|
|
mkdir -p "$CONFIG_DIR"
|
|
chmod 700 "$CONFIG_DIR"
|
|
|
|
cat > "$CONFIG_FILE" << EOF
|
|
{
|
|
"apiKey": "$TOKEN",
|
|
"endpoint": "$API_ENDPOINT"
|
|
}
|
|
EOF
|
|
chmod 600 "$CONFIG_FILE"
|
|
info "Config written to $CONFIG_FILE"
|
|
|
|
# ── Create heartbeat check script ──────────────────────────────────────────
|
|
step "Setting up heartbeat checker..."
|
|
|
|
cat > "$HEARTBEAT_SCRIPT" << 'HEARTBEAT_EOF'
|
|
#!/usr/bin/env bash
|
|
# OpenClaw heartbeat checker — runs every 5 minutes via cron
|
|
# Checks if openclaw process is running, sends heartbeat if so
|
|
|
|
export PATH="$HOME/.nvm/versions/node/$(ls "$HOME/.nvm/versions/node/" 2>/dev/null | tail -1)/bin:$HOME/.local/bin:/usr/local/bin:$PATH"
|
|
|
|
if pgrep -f "openclaw" > /dev/null 2>&1; then
|
|
claw-market heartbeat 2>/dev/null || true
|
|
fi
|
|
HEARTBEAT_EOF
|
|
chmod +x "$HEARTBEAT_SCRIPT"
|
|
info "Heartbeat checker created"
|
|
|
|
# ── Create token tracking script ───────────────────────────────────────────
|
|
step "Setting up token tracker..."
|
|
|
|
cat > "$TRACK_TOKENS_SCRIPT" << 'TRACK_EOF'
|
|
#!/usr/bin/env bash
|
|
# OpenClaw token tracker — call with: track-tokens.sh <input> <output>
|
|
# Accumulates daily token usage in ~/.openclaw/token-usage.json
|
|
|
|
CONFIG_DIR="$HOME/.openclaw"
|
|
TOKEN_FILE="$CONFIG_DIR/token-usage.json"
|
|
TODAY=$(date +%Y-%m-%d)
|
|
|
|
INPUT=${1:-0}
|
|
OUTPUT=${2:-0}
|
|
|
|
# Validate numeric
|
|
if ! [[ "$INPUT" =~ ^[0-9]+$ ]] || ! [[ "$OUTPUT" =~ ^[0-9]+$ ]]; then
|
|
echo "Usage: track-tokens.sh <input_tokens> <output_tokens>"
|
|
exit 1
|
|
fi
|
|
|
|
# Read existing data or init
|
|
if [ -f "$TOKEN_FILE" ]; then
|
|
EXISTING_DATE=$(python3 -c "import json; d=json.load(open('$TOKEN_FILE')); print(d.get('date',''))" 2>/dev/null || echo "")
|
|
if [ "$EXISTING_DATE" = "$TODAY" ]; then
|
|
EXISTING_INPUT=$(python3 -c "import json; d=json.load(open('$TOKEN_FILE')); print(d.get('inputTokens',0))" 2>/dev/null || echo "0")
|
|
EXISTING_OUTPUT=$(python3 -c "import json; d=json.load(open('$TOKEN_FILE')); print(d.get('outputTokens',0))" 2>/dev/null || echo "0")
|
|
INPUT=$((INPUT + EXISTING_INPUT))
|
|
OUTPUT=$((OUTPUT + EXISTING_OUTPUT))
|
|
fi
|
|
fi
|
|
|
|
# Write updated data
|
|
cat > "$TOKEN_FILE" << EOF
|
|
{
|
|
"date": "$TODAY",
|
|
"inputTokens": $INPUT,
|
|
"outputTokens": $OUTPUT,
|
|
"updatedAt": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
}
|
|
EOF
|
|
|
|
echo "Token usage updated: input=$INPUT, output=$OUTPUT (date=$TODAY)"
|
|
TRACK_EOF
|
|
chmod +x "$TRACK_TOKENS_SCRIPT"
|
|
info "Token tracker created"
|
|
|
|
# ── Create token reporter script ───────────────────────────────────────────
|
|
step "Setting up token reporter..."
|
|
|
|
cat > "$REPORT_TOKENS_SCRIPT" << 'REPORT_EOF'
|
|
#!/usr/bin/env bash
|
|
# OpenClaw token reporter — runs every 2 hours via cron
|
|
# Reads accumulated token usage and reports to server
|
|
|
|
export PATH="$HOME/.nvm/versions/node/$(ls "$HOME/.nvm/versions/node/" 2>/dev/null | tail -1)/bin:$HOME/.local/bin:/usr/local/bin:$PATH"
|
|
|
|
CONFIG_DIR="$HOME/.openclaw"
|
|
TOKEN_FILE="$CONFIG_DIR/token-usage.json"
|
|
TODAY=$(date +%Y-%m-%d)
|
|
|
|
# Check if token usage file exists
|
|
if [ ! -f "$TOKEN_FILE" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Read data
|
|
DATE=$(python3 -c "import json; d=json.load(open('$TOKEN_FILE')); print(d.get('date',''))" 2>/dev/null || echo "")
|
|
INPUT=$(python3 -c "import json; d=json.load(open('$TOKEN_FILE')); print(d.get('inputTokens',0))" 2>/dev/null || echo "0")
|
|
OUTPUT=$(python3 -c "import json; d=json.load(open('$TOKEN_FILE')); print(d.get('outputTokens',0))" 2>/dev/null || echo "0")
|
|
|
|
# Only report if there's data and it's for today
|
|
if [ "$INPUT" = "0" ] && [ "$OUTPUT" = "0" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Report via CLI
|
|
if [ -n "$DATE" ]; then
|
|
claw-market token "$INPUT" "$OUTPUT" --date "$DATE" 2>/dev/null || true
|
|
else
|
|
claw-market token "$INPUT" "$OUTPUT" 2>/dev/null || true
|
|
fi
|
|
REPORT_EOF
|
|
chmod +x "$REPORT_TOKENS_SCRIPT"
|
|
info "Token reporter created"
|
|
|
|
# ── Set up cron jobs ────────────────────────────────────────────────────────
|
|
step "Setting up scheduled tasks..."
|
|
|
|
# Remove existing openclaw cron jobs
|
|
EXISTING_CRON=$(crontab -l 2>/dev/null | grep -v "$CRON_TAG" || true)
|
|
|
|
# Add new cron jobs
|
|
NEW_CRON="$EXISTING_CRON
|
|
*/5 * * * * $HEARTBEAT_SCRIPT $CRON_TAG
|
|
7 */2 * * * $REPORT_TOKENS_SCRIPT $CRON_TAG"
|
|
|
|
echo "$NEW_CRON" | crontab -
|
|
info "Cron jobs installed:"
|
|
echo " - Heartbeat check: every 5 minutes"
|
|
echo " - Token report: every 2 hours"
|
|
|
|
# ── Send initial heartbeat ──────────────────────────────────────────────────
|
|
step "Sending initial heartbeat..."
|
|
|
|
claw-market heartbeat 2>/dev/null && {
|
|
info "Initial heartbeat sent"
|
|
} || {
|
|
warn "Initial heartbeat failed (non-blocking)"
|
|
}
|
|
|
|
# ── Done ────────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${GREEN}🦞 OpenClaw installed successfully!${NC}"
|
|
echo ""
|
|
echo " Your claw is now active on the heatmap."
|
|
echo " View it at: https://kymr.top"
|
|
echo ""
|
|
echo " Scripts installed:"
|
|
echo " $HEARTBEAT_SCRIPT — heartbeat (every 5 min)"
|
|
echo " $TRACK_TOKENS_SCRIPT — track token usage"
|
|
echo " $REPORT_TOKENS_SCRIPT — report tokens (every 2 hr)"
|
|
echo ""
|
|
echo " To track tokens manually:"
|
|
echo " ~/.openclaw/track-tokens.sh <input> <output>"
|
|
echo ""
|
|
echo " To uninstall:"
|
|
echo " bash <(curl -fsSL https://kymr.top/install.sh) --uninstall"
|
|
echo ""
|