Instead of just exporting env vars (which are ephemeral), the script now calls 'openclaw config set' to persist each plugin's sensitive fields (apiKey, tokens, ports, etc.) under plugins.entries.<id>.config. Config key mapping per plugin is derived from each plugin's openclaw.plugin.json configSchema. .env.example updated with all available variables and their corresponding plugin IDs.
270 lines
8.6 KiB
Bash
Executable File
270 lines
8.6 KiB
Bash
Executable File
#!/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" "$*"; }
|
|
|
|
oc_set_str() {
|
|
local key="$1" val="$2"
|
|
if [[ -n "$val" ]]; then
|
|
openclaw config set "$key" "\"$val\"" --json
|
|
ok "config: $key"
|
|
fi
|
|
}
|
|
|
|
oc_set_num() {
|
|
local key="$1" val="$2"
|
|
if [[ -n "$val" ]]; then
|
|
openclaw config set "$key" "$val" --json
|
|
ok "config: $key = $val"
|
|
fi
|
|
}
|
|
|
|
oc_set_bool() {
|
|
local key="$1" val="$2"
|
|
if [[ -n "$val" ]]; then
|
|
openclaw config set "$key" "$val" --json
|
|
ok "config: $key = $val"
|
|
fi
|
|
}
|
|
|
|
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
|
|
--skip-config Skip openclaw config set 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)
|
|
and written to openclaw config via 'openclaw config set'.
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
# ── Parse args ───────────────────────────────────────────────────────────────
|
|
|
|
UNINSTALL=false
|
|
SKIP_DEPS=false
|
|
SKIP_CONFIG=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 ;;
|
|
--skip-config) SKIP_CONFIG=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 helpers ───────────────────────────────────────────────────────
|
|
|
|
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_install_script() {
|
|
local name="$1" dir="$2" action="$3"
|
|
local script
|
|
script=$(find_install_script "$dir")
|
|
if [[ -n "$script" ]]; then
|
|
log " Running $(basename "$script") --$action"
|
|
node "$script" "--$action" || {
|
|
err "$name script failed"
|
|
return 1
|
|
}
|
|
return 0
|
|
fi
|
|
if [[ "$action" == "install" ]] && [[ -f "$dir/package.json" ]]; then
|
|
if grep -q "\"install-plugin\"" "$dir/package.json" 2>/dev/null; then
|
|
log " Running npm run install-plugin"
|
|
(cd "$dir" && npm run install-plugin)
|
|
return $?
|
|
elif grep -q "\"postinstall\"" "$dir/package.json" 2>/dev/null; then
|
|
log " Running npm run postinstall"
|
|
(cd "$dir" && npm run postinstall)
|
|
return $?
|
|
fi
|
|
fi
|
|
warn "No install script found for $name"
|
|
return 0
|
|
}
|
|
|
|
# ── Plugin config mapping ────────────────────────────────────────────────────
|
|
# Maps .env variables → openclaw config keys via 'openclaw config set'.
|
|
# Each plugin's config lives under plugins.entries.<id>.config.*
|
|
|
|
configure_plugin() {
|
|
local name="$1"
|
|
if [[ "$SKIP_CONFIG" == true ]]; then return; fi
|
|
|
|
log " Writing openclaw config"
|
|
case "$name" in
|
|
HarborForge.OpenclawPlugin)
|
|
local P="plugins.entries.harbor-forge.config"
|
|
oc_set_str "$P.backendUrl" "${HF_BACKEND_URL:-}"
|
|
oc_set_str "$P.apiKey" "${HF_API_KEY:-}"
|
|
oc_set_str "$P.identifier" "${HF_MONITOR_IDENTIFIER:-}"
|
|
oc_set_num "$P.monitor_port" "${HF_MONITOR_PORT:-}"
|
|
oc_set_num "$P.reportIntervalSec" "${HF_REPORT_INTERVAL:-}"
|
|
oc_set_str "$P.calendarApiKey" "${HF_CALENDAR_API_KEY:-}"
|
|
oc_set_bool "$P.enabled" "true"
|
|
;;
|
|
|
|
ContractorAgent)
|
|
local P="plugins.entries.contractor-agent.config"
|
|
oc_set_num "$P.bridgePort" "${CONTRACTOR_BRIDGE_PORT:-}"
|
|
oc_set_str "$P.bridgeApiKey" "${CONTRACTOR_BRIDGE_API_KEY:-}"
|
|
;;
|
|
|
|
Dirigent)
|
|
local P="plugins.entries.dirigent.config"
|
|
oc_set_str "$P.moderatorBotToken" "${DIRIGENT_MODERATOR_BOT_TOKEN:-}"
|
|
oc_set_num "$P.sideCarPort" "${DIRIGENT_SIDECAR_PORT:-}"
|
|
oc_set_str "$P.noReplyProvider" "${DIRIGENT_NO_REPLY_PROVIDER:-}"
|
|
oc_set_str "$P.noReplyModel" "${DIRIGENT_NO_REPLY_MODEL:-}"
|
|
oc_set_str "$P.scheduleIdentifier" "${DIRIGENT_SCHEDULE_IDENTIFIER:-}"
|
|
;;
|
|
|
|
PaddedCell)
|
|
local P="plugins.entries.padded-cell.config"
|
|
oc_set_str "$P.secretMgrPath" "${PADDEDCELL_SECRET_MGR_PATH:-}"
|
|
oc_set_str "$P.openclawProfilePath" "${PADDEDCELL_OPENCLAW_PATH:-}"
|
|
oc_set_bool "$P.enabled" "true"
|
|
;;
|
|
|
|
Yonexus.Server)
|
|
local P="plugins.entries.yonexus-server.config"
|
|
oc_set_str "$P.notifyBotToken" "${YONEXUS_NOTIFY_BOT_TOKEN:-}"
|
|
oc_set_str "$P.adminUserId" "${YONEXUS_ADMIN_USER_ID:-}"
|
|
oc_set_num "$P.listenPort" "${YONEXUS_PORT:-}"
|
|
oc_set_str "$P.publicWsUrl" "${YONEXUS_PUBLIC_WS_URL:-}"
|
|
;;
|
|
|
|
*)
|
|
warn "No config mapping for $name"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# ── Main loop ────────────────────────────────────────────────────────────────
|
|
|
|
run_plugin() {
|
|
local name="$1"
|
|
local dir="$PLUGINS_DIR/$name"
|
|
|
|
echo
|
|
if [[ "$UNINSTALL" == true ]]; then
|
|
log "[uninstall] $name"
|
|
run_install_script "$name" "$dir" "uninstall"
|
|
return $?
|
|
fi
|
|
|
|
log "[install] $name"
|
|
install_deps "$dir"
|
|
run_install_script "$name" "$dir" "install" || return $?
|
|
configure_plugin "$name"
|
|
ok "$name done"
|
|
}
|
|
|
|
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
|