feat: add plugin setup script and env template
scripts/setup-plugins.sh reads sensitive config from .env (gitignored), initialises submodules, installs npm deps, and runs each plugin's own install script. Supports --uninstall, --skip-deps, and per-plugin selection. .env.example documents all available variables.
This commit is contained in:
18
.env.example
Normal file
18
.env.example
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# HangmanLab.Server.T2 — Plugin Configuration
|
||||||
|
# Copy to .env and fill in values. This file is gitignored.
|
||||||
|
|
||||||
|
# ── OpenClaw ─────────────────────────────────────────────────────────────────
|
||||||
|
OPENCLAW_PATH=~/.openclaw
|
||||||
|
|
||||||
|
# ── HarborForge Plugin ───────────────────────────────────────────────────────
|
||||||
|
HF_BACKEND_URL=https://hf-api.hangman-lab.top
|
||||||
|
HF_API_KEY=
|
||||||
|
HF_MONITOR_IDENTIFIER=
|
||||||
|
|
||||||
|
# ── Yonexus.Server ───────────────────────────────────────────────────────────
|
||||||
|
YONEXUS_PORT=18900
|
||||||
|
YONEXUS_SECRET=
|
||||||
|
|
||||||
|
# ── ContractorAgent ──────────────────────────────────────────────────────────
|
||||||
|
CONTRACTOR_BRIDGE_PORT=18800
|
||||||
|
CONTRACTOR_BRIDGE_API_KEY=
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
211
scripts/setup-plugins.sh
Executable file
211
scripts/setup-plugins.sh
Executable file
@@ -0,0 +1,211 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
PLUGINS_DIR="$PROJECT_ROOT/plugins"
|
||||||
|
ENV_FILE="$PROJECT_ROOT/.env"
|
||||||
|
|
||||||
|
# ── Helpers ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'
|
||||||
|
CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
|
|
||||||
|
log() { printf "${CYAN}[setup]${NC} %s\n" "$*"; }
|
||||||
|
ok() { printf "${GREEN} ✓${NC} %s\n" "$*"; }
|
||||||
|
warn() { printf "${YELLOW} ⚠${NC} %s\n" "$*"; }
|
||||||
|
err() { printf "${RED} ✗${NC} %s\n" "$*"; }
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $(basename "$0") [options] [plugin ...]
|
||||||
|
|
||||||
|
Install and configure OpenClaw plugins from the plugins/ directory.
|
||||||
|
If no plugin names are given, all plugins are processed.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--env <path> Path to .env file (default: <project-root>/.env)
|
||||||
|
--list List available plugins and exit
|
||||||
|
--uninstall Uninstall plugins instead of installing
|
||||||
|
--skip-deps Skip npm install step
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Plugins: PaddedCell, ContractorAgent, Dirigent, HarborForge.OpenclawPlugin, Yonexus.Server
|
||||||
|
|
||||||
|
Sensitive configuration is read from .env (see .env.example for reference).
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Parse args ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
UNINSTALL=false
|
||||||
|
SKIP_DEPS=false
|
||||||
|
SELECTED_PLUGINS=()
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--env) ENV_FILE="$2"; shift 2 ;;
|
||||||
|
--list) ls "$PLUGINS_DIR"; exit 0 ;;
|
||||||
|
--uninstall) UNINSTALL=true; shift ;;
|
||||||
|
--skip-deps) SKIP_DEPS=true; shift ;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
-*) err "Unknown option: $1"; usage ;;
|
||||||
|
*) SELECTED_PLUGINS+=("$1"); shift ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── Load .env ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if [[ -f "$ENV_FILE" ]]; then
|
||||||
|
log "Loading env from $ENV_FILE"
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$ENV_FILE"
|
||||||
|
set +a
|
||||||
|
ok "Loaded $(grep -cE '^[A-Z_]+=' "$ENV_FILE") variables"
|
||||||
|
else
|
||||||
|
warn "No .env file found at $ENV_FILE — proceeding with current environment"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Submodules ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
log "Ensuring git submodules are initialised"
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
git submodule update --init --recursive
|
||||||
|
ok "Submodules ready"
|
||||||
|
|
||||||
|
# ── Resolve plugin list ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
ALL_PLUGINS=()
|
||||||
|
for d in "$PLUGINS_DIR"/*/; do
|
||||||
|
ALL_PLUGINS+=("$(basename "$d")")
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#SELECTED_PLUGINS[@]} -eq 0 ]]; then
|
||||||
|
SELECTED_PLUGINS=("${ALL_PLUGINS[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
for p in "${SELECTED_PLUGINS[@]}"; do
|
||||||
|
if [[ ! -d "$PLUGINS_DIR/$p" ]]; then
|
||||||
|
err "Plugin not found: $p"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── Per-plugin install/uninstall ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
install_deps() {
|
||||||
|
local dir="$1"
|
||||||
|
if [[ "$SKIP_DEPS" == true ]]; then return; fi
|
||||||
|
if [[ -f "$dir/package.json" ]]; then
|
||||||
|
log " npm install (root)"
|
||||||
|
(cd "$dir" && npm install --no-audit --no-fund 2>&1 | tail -3)
|
||||||
|
fi
|
||||||
|
if [[ -f "$dir/plugin/package.json" ]]; then
|
||||||
|
log " npm install (plugin/)"
|
||||||
|
(cd "$dir/plugin" && npm install --no-audit --no-fund 2>&1 | tail -3)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
find_install_script() {
|
||||||
|
local dir="$1"
|
||||||
|
for candidate in \
|
||||||
|
"$dir/scripts/install.mjs" \
|
||||||
|
"$dir/install.mjs" \
|
||||||
|
"$dir/scripts/install.js" \
|
||||||
|
"$dir/install.js"; do
|
||||||
|
if [[ -f "$candidate" ]]; then
|
||||||
|
echo "$candidate"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
run_plugin() {
|
||||||
|
local name="$1"
|
||||||
|
local dir="$PLUGINS_DIR/$name"
|
||||||
|
local action="install"
|
||||||
|
[[ "$UNINSTALL" == true ]] && action="uninstall"
|
||||||
|
|
||||||
|
echo
|
||||||
|
log "[$action] $name"
|
||||||
|
|
||||||
|
if [[ "$UNINSTALL" == true ]]; then
|
||||||
|
local script
|
||||||
|
script=$(find_install_script "$dir")
|
||||||
|
if [[ -n "$script" ]]; then
|
||||||
|
node "$script" --uninstall || warn "$name uninstall script returned non-zero"
|
||||||
|
else
|
||||||
|
warn "No install script found for $name — skipping"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
install_deps "$dir"
|
||||||
|
|
||||||
|
# Plugin-specific env setup (pass through to install scripts via env)
|
||||||
|
case "$name" in
|
||||||
|
HarborForge.OpenclawPlugin)
|
||||||
|
export HF_BACKEND_URL="${HF_BACKEND_URL:-}"
|
||||||
|
export HF_API_KEY="${HF_API_KEY:-}"
|
||||||
|
export HF_MONITOR_IDENTIFIER="${HF_MONITOR_IDENTIFIER:-}"
|
||||||
|
;;
|
||||||
|
Yonexus.Server)
|
||||||
|
export YONEXUS_PORT="${YONEXUS_PORT:-}"
|
||||||
|
export YONEXUS_SECRET="${YONEXUS_SECRET:-}"
|
||||||
|
;;
|
||||||
|
ContractorAgent)
|
||||||
|
export CONTRACTOR_BRIDGE_PORT="${CONTRACTOR_BRIDGE_PORT:-18800}"
|
||||||
|
export CONTRACTOR_BRIDGE_API_KEY="${CONTRACTOR_BRIDGE_API_KEY:-}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Run install script
|
||||||
|
local script
|
||||||
|
script=$(find_install_script "$dir")
|
||||||
|
if [[ -n "$script" ]]; then
|
||||||
|
log " Running $(basename "$script")"
|
||||||
|
node "$script" --install || {
|
||||||
|
err "$name install script failed"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
ok "$name installed"
|
||||||
|
else
|
||||||
|
# Some plugins (like PaddedCell) may have a different layout
|
||||||
|
if [[ -f "$dir/package.json" ]] && grep -q '"install-plugin"' "$dir/package.json" 2>/dev/null; then
|
||||||
|
log " Running npm run install-plugin"
|
||||||
|
(cd "$dir" && npm run install-plugin) || {
|
||||||
|
err "$name install failed"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
ok "$name installed"
|
||||||
|
elif [[ -f "$dir/package.json" ]] && grep -q '"postinstall"' "$dir/package.json" 2>/dev/null; then
|
||||||
|
log " Running npm run postinstall"
|
||||||
|
(cd "$dir" && npm run postinstall) || {
|
||||||
|
err "$name install failed"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
ok "$name installed"
|
||||||
|
else
|
||||||
|
warn "No install script found for $name — submodule present but not auto-installable"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Main ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
FAILURES=0
|
||||||
|
|
||||||
|
for plugin in "${SELECTED_PLUGINS[@]}"; do
|
||||||
|
run_plugin "$plugin" || ((FAILURES++)) || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
if [[ $FAILURES -gt 0 ]]; then
|
||||||
|
err "$FAILURES plugin(s) had errors"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
ok "All plugins processed successfully"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user