#!/bin/sh # Instalador do repositório de skills — https://skills.bassi.engineer # # Uso: curl -fsSL https://skills.bassi.engineer/install.sh | sh -s [...] # curl -fsSL https://skills.bassi.engineer/install.sh | sh -s -- --list # # O `--` antes de `--list` não é enfeite: sem ele o próprio `sh` tenta # interpretar a flag e responde `invalid option`, sem nunca chegar a este # script. Nome de skill não precisa dele porque não começa com hífen. # # Grava em ~/.claude/skills//. Não sobrescreve sem avisar: se o diretório # já existir, o script diz e pula — skill editada à mão é trabalho de alguém. set -eu BASE="https://skills.bassi.engineer" DEST="${SKILLS_DIR:-$HOME/.claude/skills}" fetch() { curl -fsSL "$1"; } if [ "$#" -eq 0 ] || [ "$1" = "--list" ] || [ "$1" = "list" ]; then echo "skills disponíveis em $BASE:" fetch "$BASE/manifest.json" | sed -n 's/.*"name": "\([^"]*\)".*/ \1/p' echo echo "instale com: curl -fsSL $BASE/install.sh | sh -s " exit 0 fi INSTALLED=0 SKIPPED=0 for NAME in "$@"; do TARGET="$DEST/$NAME" # `-e` e não `-d`: uma skill instalada por outro gerenciador costuma ser um # SYMLINK para fora (ex.: ~/.agents/skills/), e `-d` segue o link e # acerta — mas um link QUEBRADO não é diretório, e o script sobrescreveria # sem avisar. `-e` cobre os dois; `-L` pega o link morto. if [ -e "$TARGET" ] || [ -L "$TARGET" ]; then WHAT="diretório" [ -L "$TARGET" ] && WHAT="symlink para $(readlink "$TARGET")" echo "· $NAME já existe ($WHAT) — pulando" SKIPPED=$((SKIPPED + 1)) continue fi echo "▸ $NAME" # `files.txt` existe para este laço: uma skill com scripts traz os scripts, # e ler a lista de lá evita exigir `jq` ou um parser de JSON em `sh`. FILES=$(fetch "$BASE/s/$NAME/files.txt") for FILE in $FILES; do mkdir -p "$TARGET/$(dirname "$FILE")" fetch "$BASE/s/$NAME/$FILE" > "$TARGET/$FILE" case "$FILE" in *.sh|*.py) chmod +x "$TARGET/$FILE" ;; esac echo " $FILE" done INSTALLED=$((INSTALLED + 1)) # Skill que é parte de um plugin: o arquivo sozinho não liga o # comportamento. Avisar aqui, e não só no site, porque é aqui que a pessoa # está olhando — e porque o silêncio faria parecer que já está funcionando. NOTE=$(fetch "$BASE/s/$NAME/needs.txt" 2>/dev/null || true) case "$NOTE" in "<"*) NOTE="" ;; esac if [ -n "$NOTE" ]; then echo " ⚠️ $NOTE" fi done # O relatório final diz o que ACONTECEU, não o que a execução pretendia. # Antes ele imprimia "✅ instalado" mesmo quando tudo tinha sido pulado — e # quem rodou ficava sem saber se a skill veio do site ou já estava lá. echo if [ "$INSTALLED" -gt 0 ]; then echo "✅ $INSTALLED skill(s) instalada(s) em $DEST" echo " reinicie a sessão do agente para ela aparecer no catálogo" fi if [ "$SKIPPED" -gt 0 ]; then echo "· $SKIPPED pulada(s): já existiam. Nada foi baixado nem sobrescrito." echo " para reinstalar do zero: rm -rf $DEST/ e rode de novo" fi [ "$INSTALLED" -eq 0 ] && [ "$SKIPPED" -eq 0 ] && echo "nenhuma skill processada"