Add Ink skills and symlink installer
This commit is contained in:
Executable
+151
@@ -0,0 +1,151 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
usage: ink-skills list
|
||||
ink-skills install [--user | --project DIR] [SKILL ...]
|
||||
|
||||
Install Ink skills from this checkout as symlinks.
|
||||
|
||||
Commands:
|
||||
list List available skill names and source paths as TSV.
|
||||
install Link named skills; with no names, link every skill.
|
||||
|
||||
Targets:
|
||||
--user $INK_SKILLS_HOME or $HOME/.ink/skills (default)
|
||||
--project DIR DIR/.ink/skills
|
||||
|
||||
Output:
|
||||
TSV with SKILL, TARGET, and ACTION columns.
|
||||
|
||||
Exit status:
|
||||
0 success; 2 usage error; 3 target collision or invalid skill.
|
||||
|
||||
Examples:
|
||||
ink-skills list
|
||||
ink-skills install ink-cli configure-ink-agent
|
||||
ink-skills install --project . create-ink-agent-cli-tool
|
||||
EOF
|
||||
}
|
||||
|
||||
die() {
|
||||
printf '%s\n' "ink-skills: $*" >&2
|
||||
exit 3
|
||||
}
|
||||
|
||||
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
|
||||
repo_dir=$(CDPATH= cd -- "$script_dir/.." && pwd -P)
|
||||
skills_dir=$repo_dir/skills
|
||||
|
||||
list_skills() {
|
||||
printf 'SKILL\tSOURCE\n'
|
||||
for path in "$skills_dir"/*; do
|
||||
[ -d "$path" ] || continue
|
||||
[ -f "$path/SKILL.md" ] || continue
|
||||
printf '%s\t%s\n' "$(basename -- "$path")" "$path"
|
||||
done
|
||||
}
|
||||
|
||||
[ "$#" -gt 0 ] || {
|
||||
usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
command=$1
|
||||
shift
|
||||
case $command in
|
||||
-h|--help|help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
list)
|
||||
[ "$#" -eq 0 ] || {
|
||||
usage >&2
|
||||
exit 2
|
||||
}
|
||||
list_skills
|
||||
exit 0
|
||||
;;
|
||||
install) ;;
|
||||
*)
|
||||
usage >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
target_mode=user
|
||||
target_arg=
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case $1 in
|
||||
--user)
|
||||
target_mode=user
|
||||
shift
|
||||
;;
|
||||
--project)
|
||||
[ "$#" -ge 2 ] || {
|
||||
usage >&2
|
||||
exit 2
|
||||
}
|
||||
target_mode=project
|
||||
target_arg=$2
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
usage >&2
|
||||
exit 2
|
||||
;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
case $target_mode in
|
||||
user)
|
||||
if [ -n "${INK_SKILLS_HOME:-}" ]; then
|
||||
target=$INK_SKILLS_HOME
|
||||
else
|
||||
[ -n "${HOME:-}" ] || die 'HOME is unset; set HOME or INK_SKILLS_HOME'
|
||||
target=$HOME/.ink/skills
|
||||
fi
|
||||
;;
|
||||
project)
|
||||
project=$(CDPATH= cd -- "$target_arg" 2>/dev/null && pwd -P) || die "project directory not found: $target_arg"
|
||||
target=$project/.ink/skills
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p -- "$target"
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
set --
|
||||
for path in "$skills_dir"/*; do
|
||||
[ -d "$path" ] || continue
|
||||
[ -f "$path/SKILL.md" ] || continue
|
||||
set -- "$@" "$(basename -- "$path")"
|
||||
done
|
||||
fi
|
||||
|
||||
printf 'SKILL\tTARGET\tACTION\n'
|
||||
for skill do
|
||||
case $skill in
|
||||
''|.*|*/*) die "invalid skill name: $skill" ;;
|
||||
esac
|
||||
source=$skills_dir/$skill
|
||||
[ -d "$source" ] && [ -f "$source/SKILL.md" ] || die "unknown skill: $skill"
|
||||
destination=$target/$skill
|
||||
if [ -L "$destination" ]; then
|
||||
linked=$(readlink "$destination")
|
||||
[ "$linked" = "$source" ] || die "refusing foreign symlink: $destination -> $linked"
|
||||
action=unchanged
|
||||
elif [ -e "$destination" ]; then
|
||||
die "refusing existing path: $destination"
|
||||
else
|
||||
ln -s -- "$source" "$destination"
|
||||
action=linked
|
||||
fi
|
||||
printf '%s\t%s\t%s\n' "$skill" "$destination" "$action"
|
||||
done
|
||||
Reference in New Issue
Block a user