Files
skills/cli/install.sh
T

313 lines
8.7 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
MODE="all"
RESTART_GATEWAY=0
SKILLS_PREF="default"
while [[ $# -gt 0 ]]; do
case "$1" in
--cli-only)
MODE="cli"
shift
;;
--skill-only)
MODE="skill"
shift
;;
--plugin-only)
MODE="plugin"
shift
;;
--restart-gateway)
RESTART_GATEWAY=1
shift
;;
--no-skills)
SKILLS_PREF="off"
shift
;;
--with-skills)
SKILLS_PREF="on"
shift
;;
-h|--help)
cat <<'USAGE'
Usage: install.sh [--cli-only|--skill-only|--plugin-only] [--no-skills|--with-skills] [--restart-gateway]
Installs the skillhub CLI.
Default mode installs CLI + workspace skill (find-skill style).
Use --plugin-only only when you explicitly want legacy plugin injection.
Use --no-skills to skip installing workspace skills and persist this preference
for OTA self-upgrade migrations.
USAGE
exit 0
;;
*)
echo "Error: unknown argument: $1" >&2
exit 1
;;
esac
done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Supports two archive layouts:
# 1) install.sh at kit root: ./install.sh + ./cli + ./plugin + ./skill
# 2) install.sh inside cli folder: ./cli/install.sh + ./cli/plugin + ./cli/skill + cli files
if [[ -d "${SCRIPT_DIR}/cli" ]]; then
CLI_SRC_DIR="${SCRIPT_DIR}/cli"
PLUGIN_SRC_DIR="${SCRIPT_DIR}/plugin"
SKILL_SRC_DIR="${SCRIPT_DIR}/skill"
else
CLI_SRC_DIR="${SCRIPT_DIR}"
PLUGIN_SRC_DIR="${SCRIPT_DIR}/plugin"
SKILL_SRC_DIR="${SCRIPT_DIR}/skill"
fi
INSTALL_BASE="${HOME}/.skillhub"
BIN_DIR="${HOME}/.local/bin"
CLI_TARGET="${INSTALL_BASE}/skills_store_cli.py"
UPGRADE_MODULE_TARGET="${INSTALL_BASE}/skills_upgrade.py"
VERSION_TARGET="${INSTALL_BASE}/version.json"
METADATA_TARGET="${INSTALL_BASE}/metadata.json"
INDEX_TARGET="${INSTALL_BASE}/skills_index.local.json"
CONFIG_TARGET="${INSTALL_BASE}/config.json"
WRAPPER_TARGET="${BIN_DIR}/skillhub"
LEGACY_WRAPPER_TARGET="${BIN_DIR}/oc-skills"
PLUGIN_TARGET_DIR="${HOME}/.openclaw/extensions/skillhub"
FIND_SKILL_TARGET_DIR="${HOME}/.openclaw/workspace/skills/find-skills"
PREFERENCE_SKILL_TARGET_DIR="${HOME}/.openclaw/workspace/skills/skillhub-preference"
find_openclaw_bin() {
if command -v openclaw >/dev/null 2>&1; then
command -v openclaw
return 0
fi
if [[ -x "${HOME}/.local/share/pnpm/openclaw" ]]; then
echo "${HOME}/.local/share/pnpm/openclaw"
return 0
fi
return 1
}
install_cli() {
if ! command -v python3 >/dev/null 2>&1; then
echo "Error: python3 is required for skillhub." >&2
exit 1
fi
mkdir -p "${INSTALL_BASE}" "${BIN_DIR}"
cp "${CLI_SRC_DIR}/skills_store_cli.py" "${CLI_TARGET}"
cp "${CLI_SRC_DIR}/skills_upgrade.py" "${UPGRADE_MODULE_TARGET}"
cp "${CLI_SRC_DIR}/version.json" "${VERSION_TARGET}"
cp "${CLI_SRC_DIR}/metadata.json" "${METADATA_TARGET}"
if [[ -f "${CLI_SRC_DIR}/skills_index.local.json" ]]; then
cp "${CLI_SRC_DIR}/skills_index.local.json" "${INDEX_TARGET}"
fi
chmod +x "${CLI_TARGET}"
if [[ ! -f "${CONFIG_TARGET}" ]]; then
cat > "${CONFIG_TARGET}" <<'JSON'
{
"self_update_url": "https://skillhub-1388575217.cos.ap-guangzhou.myqcloud.com/version.json"
}
JSON
fi
cat > "${WRAPPER_TARGET}" <<'WRAPPER'
#!/usr/bin/env bash
set -euo pipefail
BASE="${HOME}/.skillhub"
CLI="${BASE}/skills_store_cli.py"
if [[ ! -f "${CLI}" ]]; then
echo "Error: CLI not found at ${CLI}" >&2
exit 1
fi
exec python3 "${CLI}" "$@"
WRAPPER
chmod +x "${WRAPPER_TARGET}"
cat > "${LEGACY_WRAPPER_TARGET}" <<'WRAPPER'
#!/usr/bin/env bash
set -euo pipefail
exec "${HOME}/.local/bin/skillhub" "$@"
WRAPPER
chmod +x "${LEGACY_WRAPPER_TARGET}"
}
set_workspace_skills_preference() {
local enabled="$1"
if ! command -v python3 >/dev/null 2>&1; then
echo "Warn: python3 not found; cannot persist skills preference." >&2
return 0
fi
python3 - "$CONFIG_TARGET" "$enabled" <<'PY'
import json
import sys
from pathlib import Path
config_path = Path(sys.argv[1]).expanduser()
enabled = sys.argv[2].strip().lower() == "true"
default_update_url = "https://skillhub-1388575217.cos.ap-guangzhou.myqcloud.com/version.json"
raw = {}
if config_path.exists():
try:
loaded = json.loads(config_path.read_text(encoding="utf-8"))
if isinstance(loaded, dict):
raw = loaded
except Exception:
raw = {}
if not isinstance(raw.get("self_update_url"), str) or not raw["self_update_url"].strip():
raw["self_update_url"] = default_update_url
raw["install_workspace_skills"] = enabled
config_path.parent.mkdir(parents=True, exist_ok=True)
config_path.write_text(json.dumps(raw, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
PY
}
install_plugin() {
mkdir -p "${PLUGIN_TARGET_DIR}"
cp "${PLUGIN_SRC_DIR}/index.ts" "${PLUGIN_TARGET_DIR}/index.ts"
cp "${PLUGIN_SRC_DIR}/openclaw.plugin.json" "${PLUGIN_TARGET_DIR}/openclaw.plugin.json"
}
install_skill() {
local find_skill_src="${SKILL_SRC_DIR}/SKILL.md"
local preference_skill_src="${SKILL_SRC_DIR}/SKILL.skillhub-preference.md"
local installed=0
if [[ -f "${find_skill_src}" ]]; then
mkdir -p "${FIND_SKILL_TARGET_DIR}"
cp "${find_skill_src}" "${FIND_SKILL_TARGET_DIR}/SKILL.md"
installed=1
else
echo "Warn: find-skills source not found at ${find_skill_src}; skipped." >&2
fi
if [[ -f "${preference_skill_src}" ]]; then
mkdir -p "${PREFERENCE_SKILL_TARGET_DIR}"
cp "${preference_skill_src}" "${PREFERENCE_SKILL_TARGET_DIR}/SKILL.md"
installed=1
else
echo "Warn: skillhub-preference source not found at ${preference_skill_src}; skipped." >&2
fi
if [[ "${installed}" -ne 1 ]]; then
echo "Warn: no skill templates installed." >&2
fi
}
configure_plugin() {
local openclaw_bin
if ! openclaw_bin="$(find_openclaw_bin)"; then
echo "Warn: openclaw not found on PATH; skipped plugin config." >&2
return 0
fi
"${openclaw_bin}" config set plugins.entries.skillhub.enabled true
"${openclaw_bin}" config set plugins.entries.skillhub.config.primaryCli 'skillhub'
"${openclaw_bin}" config set plugins.entries.skillhub.config.fallbackCli 'clawhub'
"${openclaw_bin}" config set plugins.entries.skillhub.config.primaryLabel 'cn-optimized'
"${openclaw_bin}" config set plugins.entries.skillhub.config.fallbackLabel 'public-registry'
}
disable_plugin_if_present() {
local openclaw_bin
if ! openclaw_bin="$(find_openclaw_bin)"; then
echo "Warn: openclaw not found on PATH; skipped plugin disable." >&2
return 0
fi
# Remove the whole config entry to avoid OpenClaw warning:
# "plugin disabled (not in allowlist) but config is present".
if ! "${openclaw_bin}" config unset plugins.entries.skillhub >/dev/null 2>&1; then
echo "Info: skillhub plugin config entry not found or already removed; skip disable."
fi
}
restart_gateway_if_needed() {
if [[ "${RESTART_GATEWAY}" -ne 1 ]]; then
return 0
fi
local openclaw_bin
if ! openclaw_bin="$(find_openclaw_bin)"; then
echo "Warn: openclaw not found on PATH; skipped gateway restart." >&2
return 0
fi
nohup "${openclaw_bin}" gateway run --bind loopback --port 18789 --force >/tmp/openclaw-gateway.log 2>&1 &
}
if [[ "${MODE}" == "all" || "${MODE}" == "cli" ]]; then
install_cli
fi
if [[ "${SKILLS_PREF}" == "off" ]]; then
set_workspace_skills_preference false
elif [[ "${SKILLS_PREF}" == "on" ]]; then
set_workspace_skills_preference true
fi
if [[ "${MODE}" == "all" || "${MODE}" == "skill" ]]; then
if [[ "${SKILLS_PREF}" != "off" ]]; then
install_skill
else
echo "Info: skipped workspace skills installation by --no-skills."
fi
disable_plugin_if_present
fi
if [[ "${MODE}" == "plugin" ]]; then
install_plugin
configure_plugin
fi
restart_gateway_if_needed
echo "Install complete."
echo " mode: ${MODE}"
if [[ "${MODE}" == "all" || "${MODE}" == "cli" ]]; then
echo " cli: ${WRAPPER_TARGET}"
if [[ -f "${INDEX_TARGET}" ]]; then
echo " index: ${INDEX_TARGET}"
fi
fi
if [[ "${MODE}" == "all" || "${MODE}" == "skill" ]]; then
if [[ "${SKILLS_PREF}" != "off" ]]; then
echo " skill: ${FIND_SKILL_TARGET_DIR}/SKILL.md"
echo " skill: ${PREFERENCE_SKILL_TARGET_DIR}/SKILL.md"
else
echo " skill: skipped (--no-skills)"
fi
fi
if [[ "${MODE}" == "plugin" ]]; then
echo " plugin: ${PLUGIN_TARGET_DIR}"
fi
echo
echo "Quick check:"
if [[ "${MODE}" == "all" || "${MODE}" == "cli" ]]; then
echo " skillhub search calendar"
fi
if [[ "${MODE}" == "all" || "${MODE}" == "skill" ]]; then
if [[ "${SKILLS_PREF}" != "off" ]]; then
echo " test -f ${FIND_SKILL_TARGET_DIR}/SKILL.md && echo find-skills-installed"
echo " test -f ${PREFERENCE_SKILL_TARGET_DIR}/SKILL.md && echo skillhub-preference-installed"
else
echo " skills install skipped by --no-skills"
fi
fi
if [[ "${MODE}" == "plugin" ]]; then
echo " If you use OpenClaw: openclaw plugins list | grep skillhub"
fi