diff --git a/bin/opc-skills b/bin/opc-skills index c37566b..4ef213d 100755 --- a/bin/opc-skills +++ b/bin/opc-skills @@ -95,6 +95,119 @@ cmd_disable() { fi } +# disable all active skills (with confirmation; -y/--yes to skip prompt) +cmd_disable_all() { + require_dirs + local force=0 + if [ "${1:-}" = "-y" ] || [ "${1:-}" = "--yes" ]; then + force=1 + fi + local -a actives + mapfile -t actives < <(skill_dirs_in "$ACTIVE") + [ "${#actives[@]}" -gt 0 ] || { echo "no active skills"; exit 0; } + echo "Will disable ${#actives[@]} active skill(s):" + printf ' %s\n' "${actives[@]}" + if [ "$force" -ne 1 ]; then + printf "Proceed? [y/N] " + read -r ans " >&2; exit 2; } + local -a matches + mapfile -t matches < <(skill_dirs_in "$ACTIVE" | awk -v p="$prefix" '$0 ~ "^" p "(-|$)"') + [ "${#matches[@]}" -gt 0 ] || { echo "no active skills match prefix: $prefix" >&2; exit 1; } + echo "Active matches (${#matches[@]}):" + local selection + selection=$(printf '%s\n' "${matches[@]}" | fzf --multi --height=70% \ + --prompt="disable-category $prefix > " \ + --header="TAB: toggle | ENTER: confirm | ESC: cancel") + [ -n "$selection" ] || { echo "cancelled"; exit 0; } + local n + while IFS= read -r n; do + [ -z "$n" ] && continue + cmd_disable "$n" || true + done <<< "$selection" +} + +# interactive pick (active only): category → multi-select skills to disable +cmd_disable_pick() { + require_dirs + ensure_fzf + local active_count + active_count=$(skill_dirs_in "$ACTIVE" | wc -l) + [ "$active_count" -gt 0 ] || { echo "no active skills"; exit 0; } + # Active categories (by prefix) + local cats + cats=$(skill_dirs_in "$ACTIVE" | awk -F'-' '{print $1}' | sort | uniq -c | sort -rn) + local category + category=$(printf '%s\n' "$cats" | fzf --prompt="active-category > " --height=50% \ + --header="Pick a category of ACTIVE skills to disable" \ + | awk '{print $2}') + [ -n "$category" ] || { echo "cancelled"; exit 0; } + local selection + selection=$(skill_dirs_in "$ACTIVE" \ + | awk -v p="$category" '$0 ~ "^" p "(-|$)"' \ + | fzf --multi --height=80% \ + --prompt="disable $category > " \ + --header="TAB: toggle | ENTER: disable selected" \ + --preview="sed -n '1,40p' \"$ACTIVE/{}/SKILL.md\" 2>/dev/null || echo '(no SKILL.md)'" \ + --preview-window=right:60%:wrap) + [ -n "$selection" ] || { echo "cancelled"; exit 0; } + local n + while IFS= read -r n; do + [ -z "$n" ] && continue + cmd_disable "$n" || true + done <<< "$selection" +} + +# fzf search across active skills (uses INDEX.json filtered by status active|both) +cmd_disable_search() { + require_dirs + ensure_fzf + command -v jq >/dev/null || { echo "jq is required" >&2; exit 1; } + [ -f "$INDEX_JSON" ] || { echo "INDEX.json missing — run: opc-skills reindex" >&2; exit 1; } + local query="${1:-}" + local tmp + tmp=$(mktemp) + # Only active or both + jq -r '.[] | select(.status=="active" or .status=="both") | "\(.folder)\t\(.description)"' "$INDEX_JSON" > "$tmp" + [ -s "$tmp" ] || { rm -f "$tmp"; echo "no active skills indexed (try: opc-skills reindex)"; exit 0; } + local selection + if [ -n "$query" ]; then + selection=$(fzf --query="$query" --multi --height=80% \ + --delimiter='\t' --with-nth=1,2 \ + --prompt="disable-search > " \ + --header="TAB: toggle | ENTER: disable selected" \ + --preview="sed -n '1,40p' \"$ACTIVE/{1}/SKILL.md\" 2>/dev/null || echo '(no SKILL.md)'" \ + --preview-window=right:60%:wrap < "$tmp") + else + selection=$(fzf --multi --height=80% \ + --delimiter='\t' --with-nth=1,2 \ + --prompt="disable-search > " \ + --header="TAB: toggle | ENTER: disable selected" \ + --preview="sed -n '1,40p' \"$ACTIVE/{1}/SKILL.md\" 2>/dev/null || echo '(no SKILL.md)'" \ + --preview-window=right:60%:wrap < "$tmp") + fi + rm -f "$tmp" + [ -n "$selection" ] || { echo "cancelled"; exit 0; } + local folder + while IFS=$'\t' read -r folder _; do + [ -z "$folder" ] && continue + cmd_disable "$folder" || true + done <<< "$selection" +} + # batch enable by prefix/category (first word before '-') cmd_enable_category() { require_dirs @@ -260,11 +373,19 @@ opc-skills — opencode skill manager categories prefix-based category counts enable enable single skill (copy parked → active) disable disable single skill (remove from active; keep parked) + disable-all [-y|--yes] disable every active skill (asks for confirmation) enable-category fzf multi-pick within a prefix, then enable + disable-category fzf multi-pick of ACTIVE skills with prefix, then disable pick fzf: choose category → multi-select → enable - search [query] fzf fuzzy search across name+description + disable-pick fzf: choose ACTIVE category → multi-select → disable + search [query] fzf fuzzy search across name+description (enable) + disable-search [query] fzf fuzzy search ACTIVE skills only (disable) reindex rebuild INDEX.json / INDEX.md +Notes: + disable* commands never delete data — they remove the active copy and keep + (or restore) the parked copy. To re-enable: opc-skills enable . + Environment: OPC_PARKED override parked dir (default: ~/Documents/opencode-skills-parked) OPC_ACTIVE override active dir (default: ~/.config/opencode/skills) @@ -281,9 +402,13 @@ main() { categories|cats) cmd_categories "$@" ;; enable) cmd_enable "$@" ;; disable) cmd_disable "$@" ;; - enable-category|enable-cat) cmd_enable_category "$@" ;; + disable-all) cmd_disable_all "$@" ;; + enable-category|enable-cat) cmd_enable_category "$@" ;; + disable-category|disable-cat) cmd_disable_category "$@" ;; pick) cmd_pick "$@" ;; + disable-pick) cmd_disable_pick "$@" ;; search) cmd_search "$@" ;; + disable-search) cmd_disable_search "$@" ;; reindex) cmd_reindex "$@" ;; -h|--help|help) usage ;; *) echo "unknown command: $cmd" >&2; usage; exit 2 ;;