Files
Fulfilled-Knowledge/Understand-Anything-main/install.sh
2026-05-27 15:40:32 +08:00

281 lines
7.7 KiB
Bash

#!/usr/bin/env bash
# Understand-Anything installer (macOS / Linux)
#
# Usage:
# ./install.sh Prompt for platform
# ./install.sh <platform> Install for <platform>
# ./install.sh --update Pull latest changes
# ./install.sh --uninstall <plat> Remove links for <plat>
# ./install.sh --help
#
# Curl-pipe usage:
# curl -fsSL https://raw.githubusercontent.com/Lum1104/Understand-Anything/main/install.sh | bash
# curl -fsSL https://raw.githubusercontent.com/Lum1104/Understand-Anything/main/install.sh | bash -s codex
#
# Environment:
# UA_REPO_URL Override clone URL (default: official GitHub repo)
# UA_DIR Override clone destination (default: $HOME/.understand-anything/repo)
set -euo pipefail
REPO_URL="${UA_REPO_URL:-https://github.com/Lum1104/Understand-Anything.git}"
REPO_DIR="${UA_DIR:-$HOME/.understand-anything/repo}"
PLUGIN_LINK="$HOME/.understand-anything-plugin"
# Platform table — id|skills-target-dir|style
# style "per-skill": one symlink per skill into the target dir
# style "folder": one symlink for the whole skills/ dir into the target,
# named "understand-anything"
platforms_table() {
cat <<EOF
gemini|$HOME/.agents/skills|per-skill
codex|$HOME/.agents/skills|per-skill
opencode|$HOME/.agents/skills|per-skill
pi|$HOME/.agents/skills|per-skill
openclaw|$HOME/.openclaw/skills|folder
antigravity|$HOME/.gemini/antigravity/skills|folder
vibe|$HOME/.vibe/skills|per-skill
vscode|$HOME/.copilot/skills|per-skill
hermes|$HOME/.hermes/skills|folder
cline|$HOME/.cline/skills|folder
kimi|$HOME/.kimi/skills|folder
trae|$HOME/.trae/skills|per-skill
EOF
}
platform_ids() { platforms_table | cut -d'|' -f1; }
resolve_platform() {
local id="$1"
local row
row="$(platforms_table | awk -F'|' -v id="$id" '$1==id {print; exit}')"
if [[ -z "$row" ]]; then
printf 'Unknown platform: %s\n' "$id" >&2
printf 'Supported: %s\n' "$(platform_ids | tr '\n' ' ')" >&2
exit 1
fi
printf '%s\n' "$row"
}
prompt_platform() {
local ids=()
while IFS= read -r id; do ids+=("$id"); done < <(platform_ids)
printf 'Which platform are you installing for?\n' >&2
local i=1
for id in "${ids[@]}"; do
printf ' %d) %s\n' "$i" "$id" >&2
i=$((i+1))
done
printf 'Choose [1-%d]: ' "${#ids[@]}" >&2
local choice=""
if { exec 3</dev/tty; } 2>/dev/null; then
read -r choice <&3 || true
exec 3<&-
else
read -r choice || true
fi
if [[ -z "$choice" ]]; then
printf '\nNo input received. Pass the platform as an argument instead, e.g.:\n' >&2
printf ' install.sh codex\n' >&2
exit 1
fi
if ! [[ "$choice" =~ ^[0-9]+$ ]] || (( choice < 1 || choice > ${#ids[@]} )); then
printf 'Invalid choice: %s\n' "$choice" >&2
exit 1
fi
printf '%s\n' "${ids[$((choice-1))]}"
}
clone_or_update() {
if [[ -d "$REPO_DIR/.git" ]]; then
printf -- '→ Updating existing checkout at %s\n' "$REPO_DIR"
git -C "$REPO_DIR" pull --ff-only
else
printf -- '→ Cloning %s → %s\n' "$REPO_URL" "$REPO_DIR"
mkdir -p "$(dirname "$REPO_DIR")"
git clone "$REPO_URL" "$REPO_DIR"
fi
}
skills_root() { printf '%s\n' "$REPO_DIR/understand-anything-plugin/skills"; }
list_skills() {
local root
root="$(skills_root)"
if [[ ! -d "$root" ]]; then
printf 'Skills directory not found: %s\n' "$root" >&2
exit 1
fi
local d
for d in "$root"/*/; do
[[ -d "$d" ]] || continue
basename "$d"
done
}
link_skills() {
local target="$1" style="$2"
local root
root="$(skills_root)"
mkdir -p "$target"
case "$style" in
per-skill)
local skill
while IFS= read -r skill; do
ln -sfn "$root/$skill" "$target/$skill"
printf ' ✓ %s → %s\n' "$target/$skill" "$root/$skill"
done < <(list_skills)
;;
folder)
ln -sfn "$root" "$target/understand-anything"
printf ' ✓ %s → %s\n' "$target/understand-anything" "$root"
;;
*)
printf 'Unknown style: %s\n' "$style" >&2
exit 1
;;
esac
}
unlink_skills() {
local target="$1" style="$2"
[[ -d "$target" ]] || return 0
case "$style" in
per-skill)
if [[ -d "$(skills_root)" ]]; then
local skill
while IFS= read -r skill; do
[[ -L "$target/$skill" ]] && rm -f "$target/$skill"
done < <(list_skills)
else
# Checkout is gone — scan the target dir for stale links pointing into
# our plugin tree so we can still clean up.
local link resolved
for link in "$target"/*; do
[[ -L "$link" ]] || continue
resolved="$(readlink "$link" 2>/dev/null || true)"
[[ "$resolved" == *"/understand-anything-plugin/skills/"* ]] || continue
rm -f "$link"
done
fi
;;
folder)
[[ -L "$target/understand-anything" ]] && rm -f "$target/understand-anything"
;;
esac
}
link_plugin_root() {
if [[ -L "$PLUGIN_LINK" || -e "$PLUGIN_LINK" ]]; then
printf ' • %s already exists, leaving as-is\n' "$PLUGIN_LINK"
else
ln -s "$REPO_DIR/understand-anything-plugin" "$PLUGIN_LINK"
printf ' ✓ %s → %s\n' "$PLUGIN_LINK" "$REPO_DIR/understand-anything-plugin"
fi
}
cmd_install() {
local id="$1"
local row target style
row="$(resolve_platform "$id")"
target="$(printf '%s\n' "$row" | cut -d'|' -f2)"
style="$(printf '%s\n' "$row" | cut -d'|' -f3)"
clone_or_update
printf -- '→ Linking skills for %s (%s → %s)\n' "$id" "$style" "$target"
link_skills "$target" "$style"
printf -- '→ Linking universal plugin root\n'
link_plugin_root
printf '\n✓ Installed Understand-Anything for %s\n' "$id"
printf ' Restart your CLI or IDE to pick up the skills.\n'
if [[ "$id" == "vscode" ]]; then
printf '\n Tip: VS Code can also auto-discover the plugin by opening this repo\n'
printf ' directly (it reads .copilot-plugin/plugin.json), no symlinks needed.\n'
fi
}
cmd_uninstall() {
local id="$1"
local row target style
row="$(resolve_platform "$id")"
target="$(printf '%s\n' "$row" | cut -d'|' -f2)"
style="$(printf '%s\n' "$row" | cut -d'|' -f3)"
printf -- '→ Removing skill links for %s\n' "$id"
unlink_skills "$target" "$style"
if [[ -L "$PLUGIN_LINK" ]]; then
rm -f "$PLUGIN_LINK"
printf ' ✓ removed %s\n' "$PLUGIN_LINK"
fi
if [[ -d "$REPO_DIR" ]]; then
printf '\nThe checkout at %s was kept (other platforms may still use it).\n' "$REPO_DIR"
printf 'To remove it: rm -rf "%s"\n' "$REPO_DIR"
fi
}
cmd_update() {
if [[ ! -d "$REPO_DIR/.git" ]]; then
printf 'No installation found at %s. Run install first.\n' "$REPO_DIR" >&2
exit 1
fi
git -C "$REPO_DIR" pull --ff-only
printf '✓ Updated.\n'
}
usage() {
cat <<USAGE
Understand-Anything installer
Usage:
install.sh [<platform>] Install for <platform> (or prompt if omitted)
install.sh --update Pull latest changes (skills update through symlinks)
install.sh --uninstall <platform> Remove links for <platform>
install.sh --help
Supported platforms:
$(platform_ids | sed 's/^/ - /')
Environment:
UA_REPO_URL Override clone URL (default: official repo)
UA_DIR Override clone destination (default: \$HOME/.understand-anything/repo)
USAGE
}
main() {
case "${1:-}" in
-h|--help)
usage
;;
--update)
cmd_update
;;
--uninstall)
shift
if [[ -z "${1:-}" ]]; then
printf '%s\n' '--uninstall requires a platform argument' >&2
usage >&2
exit 1
fi
cmd_uninstall "$1"
;;
"")
local id
id="$(prompt_platform)"
cmd_install "$id"
;;
-*)
printf 'Unknown option: %s\n' "$1" >&2
usage >&2
exit 1
;;
*)
cmd_install "$1"
;;
esac
}
main "$@"