From 7078a903526277e5dfb449cda5053b2b44753002 Mon Sep 17 00:00:00 2001 From: Matteo Bolognini <90386956+matteo-bolognini@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:12:33 +0000 Subject: [PATCH] 1st --- support/openclaw_detection.sh | 229 +++++++++++++++++++++++++++ support/openclaw_skills_detection.sh | 75 +++++++++ 2 files changed, 304 insertions(+) create mode 100644 support/openclaw_detection.sh create mode 100644 support/openclaw_skills_detection.sh diff --git a/support/openclaw_detection.sh b/support/openclaw_detection.sh new file mode 100644 index 0000000..4050161 --- /dev/null +++ b/support/openclaw_detection.sh @@ -0,0 +1,229 @@ +#!/bin/bash + +########################################################################################################################### +# +# Copyright 2026, Jamf Software LLC. +# This work is licensed under the terms of the Jamf Source Available License +# https://github.com/jamf/scripts/blob/main/LICENCE.md +# +########################################################################################################################### + +################################################################################ +# Detects OpenClaw installations including: +# - CLI binary (npm/pnpm global install) +# - LaunchAgent services (current and legacy) +# - macOS companion app +# - Configuration directories +# - Running processes/gateway +# - Docker containers +################################################################################ + +# Initialize detection arrays +declare -a findings + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Function to check Docker containers +check_docker() { + if command_exists docker; then + # Check for running OpenClaw containers + if docker ps --format '{{.Names}}' 2>/dev/null | grep -qi openclaw; then + container_names=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -i openclaw | tr '\n' ', ' | sed 's/,$//') + findings+=("Docker-Running:${container_names}") + fi + + # Check for stopped OpenClaw containers + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -qi openclaw; then + all_containers=$(docker ps -a --format '{{.Names}}' 2>/dev/null | grep -i openclaw | wc -l | tr -d ' ') + if [[ $all_containers -gt 0 ]]; then + findings+=("Docker-Containers:${all_containers}") + fi + fi + fi +} + +# Function to check for CLI installation +check_cli() { + # Check common npm global bin locations + local npm_prefix="" + + if command_exists npm; then + npm_prefix=$(npm prefix -g 2>/dev/null) + if [[ -f "${npm_prefix}/bin/openclaw" ]]; then + # Get version if possible + local version=$("${npm_prefix}/bin/openclaw" --version 2>/dev/null | head -1) + findings+=("CLI-NPM:${npm_prefix}/bin/openclaw") + [[ -n "$version" ]] && findings+=("Version:${version}") + fi + fi + + # Check standard locations + if [[ -f "/usr/local/bin/openclaw" ]]; then + findings+=("CLI-Binary:/usr/local/bin/openclaw") + fi + + # Check if openclaw command is available in PATH + if command_exists openclaw && [[ ! " ${findings[@]} " =~ " CLI-" ]]; then + local openclaw_path=$(which openclaw 2>/dev/null) + findings+=("CLI-Path:${openclaw_path}") + fi +} + +# Function to check macOS app +check_macos_app() { + if [[ -d "/Applications/OpenClaw.app" ]]; then + # Get app version from Info.plist if available + local app_version="" + if [[ -f "/Applications/OpenClaw.app/Contents/Info.plist" ]]; then + app_version=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "/Applications/OpenClaw.app/Contents/Info.plist" 2>/dev/null) + fi + findings+=("App:/Applications/OpenClaw.app") + [[ -n "$app_version" ]] && findings+=("AppVersion:${app_version}") + fi + + # Check user Applications folders + for user_home in /Users/*; do + [[ ! -d "$user_home" ]] && continue + [[ "$user_home" == "/Users/Shared" ]] && continue + + if [[ -d "${user_home}/Applications/OpenClaw.app" ]]; then + local username=$(basename "$user_home") + findings+=("App-User:${username}") + fi + done +} + +# Function to check LaunchAgents +check_launch_agents() { + for user_home in /Users/*; do + [[ ! -d "$user_home" ]] && continue + [[ "$user_home" == "/Users/Shared" ]] && continue + + local username=$(basename "$user_home") + local launch_agents_dir="${user_home}/Library/LaunchAgents" + + # Check current naming convention + if [[ -f "${launch_agents_dir}/bot.molt.gateway.plist" ]]; then + # Check if it's loaded + local is_loaded=$(sudo -u "$username" launchctl list 2>/dev/null | grep -c "bot.molt.gateway") + if [[ $is_loaded -gt 0 ]]; then + findings+=("LaunchAgent-Active:${username}") + else + findings+=("LaunchAgent-Installed:${username}") + fi + fi + + # Check legacy naming convention + if [[ -f "${launch_agents_dir}/com.openclaw.gateway.plist" ]]; then + findings+=("LaunchAgent-Legacy:${username}") + fi + + # Check for profile-based agents (bot.molt.*) + local profile_agents=$(find "${launch_agents_dir}" -name "bot.molt.*.plist" 2>/dev/null | wc -l | tr -d ' ') + if [[ $profile_agents -gt 0 ]]; then + findings+=("LaunchAgent-Profiles:${username}:${profile_agents}") + fi + done +} + +# Function to check configuration directories +check_config_dirs() { + local found_configs=0 + + for user_home in /Users/*; do + [[ ! -d "$user_home" ]] && continue + [[ "$user_home" == "/Users/Shared" ]] && continue + + local username=$(basename "$user_home") + local config_dir="${user_home}/.openclaw" + + if [[ -d "$config_dir" ]]; then + found_configs=$((found_configs + 1)) + + # Check for main config file + if [[ -f "${config_dir}/openclaw.json" ]]; then + findings+=("Config:${username}") + + # Check workspace + if [[ -d "${config_dir}/workspace" ]]; then + findings+=("Workspace:${username}") + fi + + # Check for credentials + if [[ -f "${config_dir}/credentials/profiles.json" ]]; then + findings+=("Credentials:${username}") + fi + fi + fi + + # Check for workspace directory (could be separate) + if [[ -d "${user_home}/openclaw/workspace" ]]; then + findings+=("Workspace-Alt:${username}") + fi + done + + [[ $found_configs -gt 0 ]] && findings+=("ConfigDirs:${found_configs}") +} + +# Function to check running processes +check_processes() { + # Check for openclaw processes + if pgrep -f "openclaw" >/dev/null 2>&1; then + local process_count=$(pgrep -f "openclaw" | wc -l | tr -d ' ') + findings+=("Process-Running:${process_count}") + + # Check if Gateway is running on default port + if lsof -i :18789 >/dev/null 2>&1; then + findings+=("Gateway-Port:18789") + fi + fi + + # Check for node processes that might be running openclaw + if pgrep -f "node.*openclaw" >/dev/null 2>&1; then + local node_count=$(pgrep -f "node.*openclaw" | wc -l | tr -d ' ') + [[ $node_count -gt 0 ]] && findings+=("Node-Process:${node_count}") + fi +} + +# Function to check for source installation +check_source_install() { + for user_home in /Users/*; do + [[ ! -d "$user_home" ]] && continue + [[ "$user_home" == "/Users/Shared" ]] && continue + + local username=$(basename "$user_home") + + # Check common locations for git clone + for dir in "${user_home}/openclaw" "${user_home}/Documents/openclaw" "${user_home}/Projects/openclaw" "${user_home}/src/openclaw"; do + if [[ -d "$dir" ]] && [[ -f "$dir/package.json" ]]; then + # Verify it's actually openclaw by checking package.json + if grep -q '"name": "openclaw"' "$dir/package.json" 2>/dev/null; then + findings+=("Source:${username}:${dir}") + fi + fi + done + done +} + +# Run all checks +check_docker +check_cli +check_macos_app +check_launch_agents +check_config_dirs +check_processes +check_source_install + +# Format and return results +if [[ ${#findings[@]} -eq 0 ]]; then + echo "Not Installed" +else + # Join findings with semicolon separator + result=$(IFS=';'; echo "${findings[*]}") + echo "${result}" +fi + +exit 0 diff --git a/support/openclaw_skills_detection.sh b/support/openclaw_skills_detection.sh new file mode 100644 index 0000000..9cab132 --- /dev/null +++ b/support/openclaw_skills_detection.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +########################################################################################################################### +# +# Copyright 2026, Jamf Software LLC. +# This work is licensed under the terms of the Jamf Source Available License +# https://github.com/jamf/scripts/blob/main/LICENCE.md +# +########################################################################################################################### + +# Function to find openclaw directory +find_openclaw_dir() { + # Get the current console user + CURRENT_USER=$(stat -f "%Su" /dev/console 2>/dev/null || who | awk '/console/ {print $1}' | head -n 1) + + # If we can't determine user, try logname or $USER + if [ -z "$CURRENT_USER" ]; then + CURRENT_USER=$(logname 2>/dev/null || echo "$USER") + fi + + # Get user's home directory + if [ -n "$CURRENT_USER" ]; then + USER_HOME=$(eval echo "~$CURRENT_USER") + else + USER_HOME="$HOME" + fi + + # Define openclaw config path + OPENCLAW_DIR="${USER_HOME}/.openclaw" + + echo "$OPENCLAW_DIR" +} + +# Main execution +OPENCLAW_DIR=$(find_openclaw_dir) +OPENCLAW_JSON="${OPENCLAW_DIR}/openclaw.json" + +# Check if openclaw is installed +if [ ! -d "$OPENCLAW_DIR" ]; then + echo "Not Installed" + exit 0 +fi + +# Check if config file exists +if [ ! -f "$OPENCLAW_JSON" ]; then + echo "Config File Not Found" + exit 0 +fi + +# Check if jq is available +if ! command -v jq &> /dev/null; then + echo "jq Not Available" + exit 0 +fi + +# Extract enabled skills +ENABLED_SKILLS=$(cat "$OPENCLAW_JSON" | jq -r '.skills.entries | to_entries | .[] | select(.value.enabled).key' 2>/dev/null) + +# Check if extraction was successful +if [ $? -ne 0 ]; then + echo "Error Parsing JSON" + exit 0 +fi + +# Check if any skills were found +if [ -z "$ENABLED_SKILLS" ]; then + echo "No Enabled Skills" + exit 0 +fi + +# Format output: Convert newline-separated skills to comma-separated +SKILLS_LIST=$(echo "$ENABLED_SKILLS" | tr '\n' ',' | sed 's/,$//') + +echo "$SKILLS_LIST" +exit 0