skillpull 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/skillpull +92 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillpull",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Sync AI agent skills from Git repositories to Claude, Codex, Kiro, and Cursor",
5
5
  "bin": {
6
6
  "skillpull": "./skillpull"
package/skillpull CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- VERSION="0.5.1"
4
+ VERSION="0.5.2"
5
5
  MANIFEST_FILE=".skillpull.json"
6
6
  TMPDIR_PREFIX="skillpull"
7
7
  CONFIG_DIR="$HOME/.config/skillpull"
@@ -445,12 +445,12 @@ _json_escape() {
445
445
  }
446
446
 
447
447
  write_manifest_entry() {
448
- local manifest="$1" skill_name="$2" repo="$3" branch="$4" commit="$5" version="$6"
448
+ local manifest="$1" skill_name="$2" repo="$3" branch="$4" commit="$5" version="$6" scope="${7:-common}"
449
449
  local ts; ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
450
450
  local esc_repo; esc_repo="$(_json_escape "$repo")"
451
451
  local entry
452
- entry=$(printf ' "%s": {"repo":"%s","branch":"%s","commit":"%s","version":"%s","pulled_at":"%s"}' \
453
- "$skill_name" "$esc_repo" "$branch" "$commit" "$version" "$ts")
452
+ entry=$(printf ' "%s": {"repo":"%s","branch":"%s","commit":"%s","version":"%s","scope":"%s","pulled_at":"%s"}' \
453
+ "$skill_name" "$esc_repo" "$branch" "$commit" "$version" "$scope" "$ts")
454
454
 
455
455
  if [[ ! -f "$manifest" ]]; then
456
456
  printf '{\n "skills": {\n%s\n }\n}\n' "$entry" > "$manifest"
@@ -577,6 +577,14 @@ cmd_pull() {
577
577
  local sn; sn="$(skill_display_name "$sd")"
578
578
  local ver; ver="$(parse_frontmatter "$sd/SKILL.md" "version")"
579
579
 
580
+ # Determine scope: common (skills/) or project-specific
581
+ local scope="common"
582
+ if [[ -n "$project" ]]; then
583
+ case "$sd" in
584
+ "$tmpdir/$project/"*) scope="$project" ;;
585
+ esac
586
+ fi
587
+
580
588
  if [[ "$fmt" == "mdc" ]]; then
581
589
  # Cursor: convert SKILL.md → .mdc file
582
590
  local dest="$target_dir/${sn}.mdc"
@@ -592,7 +600,7 @@ cmd_pull() {
592
600
  fi
593
601
 
594
602
  convert_skill_to_mdc "$sd/SKILL.md" "$dest"
595
- write_manifest_entry "$manifest" "$sn" "$repo_url" "$branch" "$commit" "${ver:-}"
603
+ write_manifest_entry "$manifest" "$sn" "$repo_url" "$branch" "$commit" "${ver:-}" "$scope"
596
604
  info "Installed: $sn -> $dest (converted to .mdc)"
597
605
  else
598
606
  # Claude/Codex/Kiro: copy skill folder as-is
@@ -616,7 +624,7 @@ cmd_pull() {
616
624
  chmod +x "$dest/scripts/"* 2>/dev/null || true
617
625
  fi
618
626
 
619
- write_manifest_entry "$manifest" "$sn" "$repo_url" "$branch" "$commit" "${ver:-}"
627
+ write_manifest_entry "$manifest" "$sn" "$repo_url" "$branch" "$commit" "${ver:-}" "$scope"
620
628
  info "Installed: $sn${ver:+ (v$ver)} -> $dest"
621
629
  fi
622
630
  installed=$((installed + 1))
@@ -862,7 +870,11 @@ cmd_push() {
862
870
 
863
871
  local branch; branch="$(git -C "$tmpdir" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "master")"
864
872
 
873
+ # Read project name from .skillpullrc
874
+ local project_name; project_name="$(read_project_rc "project")"
875
+
865
876
  # Discover local skills
877
+ local manifest="$target_dir/$MANIFEST_FILE"
866
878
  local skills=()
867
879
  if [[ "$fmt" == "mdc" ]]; then
868
880
  while IFS= read -r f; do
@@ -879,10 +891,10 @@ cmd_push() {
879
891
  return 1
880
892
  fi
881
893
 
882
- # Copy skills into the cloned repo
894
+ # Classify skills by scope
883
895
  local pushed=0
884
- local skills_subdir="$tmpdir/skills"
885
- mkdir -p "$skills_subdir"
896
+ local untracked_names=()
897
+ local untracked_dirs=()
886
898
 
887
899
  for sd in "${skills[@]}"; do
888
900
  local sn
@@ -892,14 +904,79 @@ cmd_push() {
892
904
  sn="$(skill_display_name "$sd")"
893
905
  fi
894
906
 
895
- local dest="$skills_subdir/$sn"
896
- rm -rf "$dest"
897
- cp -r "$sd" "$dest"
898
- rm -rf "$dest/.git"
899
- info "Staged: $sn"
900
- pushed=$((pushed + 1))
907
+ # Check manifest for scope
908
+ local scope; scope="$(read_manifest_entry "$manifest" "$sn" "scope")"
909
+
910
+ if [[ -n "$scope" ]]; then
911
+ # Known skill: route by scope
912
+ local dest_dir
913
+ if [[ "$scope" == "common" ]]; then
914
+ dest_dir="$tmpdir/skills/$sn"
915
+ else
916
+ dest_dir="$tmpdir/$scope/$sn"
917
+ fi
918
+ mkdir -p "$(dirname "$dest_dir")"
919
+ rm -rf "$dest_dir"
920
+ cp -r "$sd" "$dest_dir"
921
+ rm -rf "$dest_dir/.git"
922
+ info "Staged: $sn -> ${scope}/"
923
+ pushed=$((pushed + 1))
924
+ else
925
+ # Untracked skill: collect for user choice
926
+ untracked_names+=("$sn")
927
+ untracked_dirs+=("$sd")
928
+ fi
901
929
  done
902
930
 
931
+ # Handle untracked skills: let user choose destination
932
+ if [[ ${#untracked_names[@]} -gt 0 && -t 0 ]]; then
933
+ for ((idx=0; idx<${#untracked_names[@]}; idx++)); do
934
+ local sn="${untracked_names[$idx]}"
935
+ local sd="${untracked_dirs[$idx]}"
936
+ local choice_dest=""
937
+
938
+ if [[ -n "$project_name" ]]; then
939
+ printf "\n ${CYAN}New skill: %s${RESET}\n" "$sn" >&2
940
+ printf " Push to:\n" >&2
941
+ printf " ${CYAN}1${RESET}) skills/ (common)\n" >&2
942
+ printf " ${CYAN}2${RESET}) %s/ (project)\n" "$project_name" >&2
943
+ printf " Choice [1/2]: " >&2
944
+ read -r choice
945
+ case "$choice" in
946
+ 2) choice_dest="$tmpdir/$project_name/$sn" ;;
947
+ *) choice_dest="$tmpdir/skills/$sn" ;;
948
+ esac
949
+ else
950
+ choice_dest="$tmpdir/skills/$sn"
951
+ fi
952
+
953
+ mkdir -p "$(dirname "$choice_dest")"
954
+ rm -rf "$choice_dest"
955
+ cp -r "$sd" "$choice_dest"
956
+ rm -rf "$choice_dest/.git"
957
+ info "Staged: $sn"
958
+ pushed=$((pushed + 1))
959
+ done
960
+ elif [[ ${#untracked_names[@]} -gt 0 ]]; then
961
+ # Non-interactive: default to common
962
+ for ((idx=0; idx<${#untracked_names[@]}; idx++)); do
963
+ local sn="${untracked_names[$idx]}"
964
+ local sd="${untracked_dirs[$idx]}"
965
+ local dest="$tmpdir/skills/$sn"
966
+ mkdir -p "$tmpdir/skills"
967
+ rm -rf "$dest"
968
+ cp -r "$sd" "$dest"
969
+ rm -rf "$dest/.git"
970
+ info "Staged: $sn -> skills/ (default)"
971
+ pushed=$((pushed + 1))
972
+ done
973
+ fi
974
+
975
+ if [[ "$pushed" -eq 0 ]]; then
976
+ dim "No skills to push."
977
+ return 0
978
+ fi
979
+
903
980
  # Commit and push
904
981
  git -C "$tmpdir" add -A
905
982
  if git -C "$tmpdir" diff --cached --quiet 2>/dev/null; then