#!/usr/bin/env bash # OpenClaw WeChat Skill Deploy v1.2.0 (Bash, Linux/Mac) # # Usage: # ./deploy-to-openclaw.sh # normal deploy # ./deploy-to-openclaw.sh --dry-run # preview # SKILLS_ROOT=/custom/path ./deploy-to-openclaw.sh set -euo pipefail DRY_RUN=0 for arg in "$@"; do case "$arg" in --dry-run|-DryRun) DRY_RUN=1 ;; esac done SOURCE_ROOT="${SOURCE_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}" SKILLS_ROOT="${SKILLS_ROOT:-$HOME/.openclaw/skills}" CATEGORIES=("wechat") # Colors (disabled if not TTY) if [ -t 1 ]; then CYAN=$'\e[36m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m'; RED=$'\e[31m'; NC=$'\e[0m' else CYAN=""; GREEN=""; YELLOW=""; RED=""; NC="" fi echo "=== OpenClaw WeChat Skill Deploy v1.2.0 ===" echo "Source: $SOURCE_ROOT" echo "Target: $SKILLS_ROOT" [ "$DRY_RUN" -eq 1 ] && echo "${YELLOW}[DRY RUN]${NC}" [ "$DRY_RUN" -eq 0 ] && mkdir -p "$SKILLS_ROOT" deployed=0; skipped=0; errors=0 # JSON validator: prefer python3, fallback to node, else skip validation validate_json() { local file="$1" if command -v python3 >/dev/null 2>&1; then python3 -c "import json,sys; json.load(open(sys.argv[1],encoding='utf-8'))" "$file" >/dev/null 2>&1 elif command -v node >/dev/null 2>&1; then node -e "JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'))" "$file" >/dev/null 2>&1 else return 0 fi } for cat in "${CATEGORIES[@]}"; do cat_path="$SOURCE_ROOT/$cat" [ -d "$cat_path" ] || continue echo "${CYAN}--- $cat ---${NC}" for skill_dir in "$cat_path"/*/; do [ -d "$skill_dir" ] || continue name=$(basename "$skill_dir") sm="$skill_dir/SKILL.md" ac="$skill_dir/api-config.json" if [ ! -f "$sm" ]; then skipped=$((skipped+1)); continue fi # api-config.json is optional reference material in v1.1.0+ if [ -f "$ac" ] && ! validate_json "$ac"; then echo " ${RED}[ERR] $name: invalid api-config.json${NC}" errors=$((errors+1)); continue fi dest="$SKILLS_ROOT/$name" if [ "$DRY_RUN" -eq 1 ]; then if [ -d "$dest" ]; then echo " [UPDATE] $name"; else echo " [NEW] $name"; fi else rm -rf "$dest" mkdir -p "$dest" # copy files (non-recursive, skill files only) find "$skill_dir" -maxdepth 1 -type f -exec cp {} "$dest/" \; echo " ${GREEN}[OK] $name${NC}" fi deployed=$((deployed+1)) done done echo "Result: $deployed deployed, $skipped skipped, $errors errors" # ---- Workflows ---- wf_source="$SOURCE_ROOT/workflows" wf_target="$(dirname "$SKILLS_ROOT")/workflows" if [ -d "$wf_source" ]; then echo "${CYAN}--- workflows ---${NC}" if [ "$DRY_RUN" -eq 0 ]; then mkdir -p "$wf_target" find "$wf_source" -maxdepth 1 -type f | while read -r f; do cp "$f" "$wf_target/" echo " ${GREEN}[OK] $(basename "$f")${NC}" done else find "$wf_source" -maxdepth 1 -type f | while read -r f; do echo " [WORKFLOW] $(basename "$f")" done fi fi # ---- Credentials ---- parent="$(dirname "$SKILLS_ROOT")" if [ "$DRY_RUN" -eq 0 ]; then tpl="$SOURCE_ROOT/__config/wechat-credentials.template.json" if [ -f "$tpl" ]; then cp "$tpl" "$parent/wechat-credentials.template.json" echo "Template: $parent/wechat-credentials.template.json" cred_file="$parent/wechat-credentials.json" if [ ! -f "$cred_file" ]; then cp "$tpl" "$cred_file" echo "${YELLOW}[!] Created $cred_file - please edit wechatApiBase to your server address${NC}" fi fi fi # ---- Auto-reply daemon + config ---- daemon_src="$SOURCE_ROOT/daemon/auto-reply-daemon.js" daemon_dst="$parent/auto-reply-daemon.js" cfg_tpl_src="$SOURCE_ROOT/daemon/wechat-auto-reply-config.template.json" cfg_tpl_dst="$parent/wechat-auto-reply-config.template.json" cfg_dst="$parent/wechat-auto-reply-config.json" if [ -f "$daemon_src" ]; then echo "${CYAN}--- auto-reply daemon ---${NC}" if [ "$DRY_RUN" -eq 1 ]; then echo " [DAEMON] $daemon_dst" echo " [CONFIG-TEMPLATE] $cfg_tpl_dst" [ ! -f "$cfg_dst" ] && echo " [CONFIG-DEFAULT] $cfg_dst" else cp "$daemon_src" "$daemon_dst" chmod +x "$daemon_dst" 2>/dev/null || true echo " ${GREEN}[OK] $daemon_dst${NC}" if [ -f "$cfg_tpl_src" ]; then cp "$cfg_tpl_src" "$cfg_tpl_dst" echo " ${GREEN}[OK] $cfg_tpl_dst${NC}" if [ ! -f "$cfg_dst" ]; then cp "$cfg_tpl_src" "$cfg_dst" echo " ${YELLOW}[!] Created default config: $cfg_dst (edit to customize reply rules)${NC}" fi fi fi fi [ "$DRY_RUN" -eq 0 ] && echo "${GREEN}Done!${NC}" exit $([ "$errors" -gt 0 ] && echo 1 || echo 0)