skill-linker 1.0.0 → 2.0.0
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.
- package/README.md +52 -5
- package/link-skill.sh +163 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,24 +41,71 @@ Usage: link-skill.sh [OPTIONS] [SKILL_PATH]
|
|
|
41
41
|
|
|
42
42
|
Options:
|
|
43
43
|
--from <github_url> 從 GitHub Clone Skill 後再連結
|
|
44
|
+
--list 列出已 Clone 的 Repos 並選擇 Skills
|
|
44
45
|
--help 顯示說明
|
|
45
46
|
|
|
46
47
|
Examples:
|
|
47
48
|
./link-skill.sh # 互動式選擇
|
|
49
|
+
./link-skill.sh --list # 瀏覽已 Clone 的 Repos
|
|
48
50
|
./link-skill.sh /path/to/skill # 指定本地 Skill
|
|
49
51
|
./link-skill.sh --from https://github.com/user/my-skill
|
|
52
|
+
./link-skill.sh --from https://github.com/anthropics/skills/tree/main/skills/pdf
|
|
50
53
|
```
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
### Multi-Skill Repo 支援
|
|
56
|
+
|
|
57
|
+
對於包含多個 Skills 的 Repo(如 `anthropics/skills`),腳本會:
|
|
58
|
+
1. 自動偵測 `skills/` 子目錄
|
|
59
|
+
2. 列出所有可用的 Skills 讓您選擇
|
|
60
|
+
3. 或者您可以直接在 URL 中指定子路徑(如 `/tree/main/skills/pdf`)
|
|
61
|
+
|
|
62
|
+
### 📋 List Mode - 瀏覽已 Clone 的 Repos
|
|
63
|
+
|
|
64
|
+
使用 `--list` 參數可以瀏覽 Skill Library 中已 clone 的所有 repos:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx skill-linker --list
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
操作流程:
|
|
71
|
+
1. 顯示所有已 clone 的 repos(以 `owner/repo` 格式)
|
|
72
|
+
2. 選擇要使用的 repo
|
|
73
|
+
3. 如果該 repo 包含多個 skills,會列出讓您選擇
|
|
74
|
+
4. 選擇後繼續正常的 Agent 安裝流程
|
|
75
|
+
|
|
76
|
+
這對於管理多個已下載的 skill repos 特別有用!
|
|
53
77
|
|
|
54
|
-
|
|
78
|
+
## 📦 推薦的 Public Skill Repos
|
|
79
|
+
|
|
80
|
+
| Repo | 說明 |
|
|
81
|
+
|------|------|
|
|
82
|
+
| [anthropics/skills](https://github.com/anthropics/skills) | Claude 官方 Skills (pdf, docx, pptx, xlsx...) |
|
|
83
|
+
| [obra/superpowers](https://github.com/obra/superpowers) | 開發流程 Skills (TDD, debugging, code-review...) |
|
|
55
84
|
|
|
56
85
|
```bash
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
86
|
+
# 安裝 Anthropic 的 PDF Skill
|
|
87
|
+
npx skill-linker --from https://github.com/anthropics/skills/tree/main/skills/pdf
|
|
88
|
+
|
|
89
|
+
# 安裝 obra 的所有開發 Skills (可互動選擇)
|
|
90
|
+
npx skill-linker --from https://github.com/obra/superpowers
|
|
60
91
|
```
|
|
61
92
|
|
|
93
|
+
## 📂 Skill Library
|
|
94
|
+
|
|
95
|
+
使用 `--from` 參數時,Skills 會自動存放到 `~/Documents/AgentSkills`,並以 **owner/repo** 結構分層:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
~/Documents/AgentSkills/
|
|
99
|
+
├── anthropics/
|
|
100
|
+
│ └── skills/ # https://github.com/anthropics/skills
|
|
101
|
+
├── obra/
|
|
102
|
+
│ └── superpowers/ # https://github.com/obra/superpowers
|
|
103
|
+
└── your-org/
|
|
104
|
+
└── your-skill/ # https://github.com/your-org/your-skill
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
這種命名空間結構可避免不同帳號擁有相同 repo 名稱時的衝突。
|
|
108
|
+
|
|
62
109
|
腳本會自動偵測此目錄並列出可用的 Skills。
|
|
63
110
|
|
|
64
111
|
## 🛠️ 支援的 Agent 與路徑
|
package/link-skill.sh
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
DEFAULT_LIB_PATH="$HOME/Documents/AgentSkills"
|
|
6
6
|
SKILL_PATH=""
|
|
7
7
|
FROM_URL=""
|
|
8
|
+
LIST_MODE=false
|
|
8
9
|
|
|
9
10
|
# Helper function for colored output
|
|
10
11
|
print_info() { echo -e "\033[1;34m[INFO]\033[0m $1"; }
|
|
@@ -18,16 +19,95 @@ show_help() {
|
|
|
18
19
|
echo ""
|
|
19
20
|
echo "Options:"
|
|
20
21
|
echo " --from <github_url> Clone skill from GitHub URL first, then link"
|
|
22
|
+
echo " --list List cloned repos and select skills to link"
|
|
21
23
|
echo " --help Show this help message"
|
|
22
24
|
echo ""
|
|
23
25
|
echo "Examples:"
|
|
24
26
|
echo " ./link-skill.sh # Interactive selection from library"
|
|
25
27
|
echo " ./link-skill.sh /path/to/skill # Link specific local skill"
|
|
26
28
|
echo " ./link-skill.sh --from https://github.com/user/my-skill"
|
|
29
|
+
echo " ./link-skill.sh --from https://github.com/anthropics/skills/tree/main/skills/pdf"
|
|
30
|
+
echo ""
|
|
31
|
+
echo "Notes:"
|
|
32
|
+
echo " - If the cloned repo has a 'skills/' subdirectory, you can pick a specific skill"
|
|
33
|
+
echo " - GitHub URLs with /tree/branch/path are supported for direct subpath access"
|
|
27
34
|
echo ""
|
|
28
35
|
exit 0
|
|
29
36
|
}
|
|
30
37
|
|
|
38
|
+
# List repos function
|
|
39
|
+
list_repos() {
|
|
40
|
+
if [ ! -d "$DEFAULT_LIB_PATH" ]; then
|
|
41
|
+
print_error "Skill Library not found: $DEFAULT_LIB_PATH"
|
|
42
|
+
print_info "Use --from <github_url> to clone skills first."
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Find all repos (owner/repo structure)
|
|
47
|
+
repos=()
|
|
48
|
+
repo_paths=()
|
|
49
|
+
for owner_dir in "$DEFAULT_LIB_PATH"/*/; do
|
|
50
|
+
[ -d "$owner_dir" ] || continue
|
|
51
|
+
owner=$(basename "$owner_dir")
|
|
52
|
+
for repo_dir in "$owner_dir"*/; do
|
|
53
|
+
[ -d "$repo_dir" ] || continue
|
|
54
|
+
repo=$(basename "$repo_dir")
|
|
55
|
+
repos+=("$owner/$repo")
|
|
56
|
+
repo_paths+=("$repo_dir")
|
|
57
|
+
done
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
if [ ${#repos[@]} -eq 0 ]; then
|
|
61
|
+
print_warning "No repos found in $DEFAULT_LIB_PATH"
|
|
62
|
+
print_info "Use --from <github_url> to clone skills first."
|
|
63
|
+
exit 0
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
echo ""
|
|
67
|
+
print_info "Cloned Repos in Skill Library:"
|
|
68
|
+
echo ""
|
|
69
|
+
select repo_name in "${repos[@]}"; do
|
|
70
|
+
if [ -n "$repo_name" ]; then
|
|
71
|
+
idx=$((REPLY - 1))
|
|
72
|
+
selected_repo_path="${repo_paths[$idx]}"
|
|
73
|
+
break
|
|
74
|
+
else
|
|
75
|
+
echo "Invalid selection. Please try again."
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
# Check for skills/ subdirectory
|
|
80
|
+
SKILLS_DIR="${selected_repo_path}skills"
|
|
81
|
+
if [ -d "$SKILLS_DIR" ]; then
|
|
82
|
+
print_info "Skills in $repo_name:"
|
|
83
|
+
sub_skills=("$SKILLS_DIR"/*/)
|
|
84
|
+
if [ ${#sub_skills[@]} -gt 0 ]; then
|
|
85
|
+
sub_skill_names=()
|
|
86
|
+
for s in "${sub_skills[@]}"; do
|
|
87
|
+
[ -d "$s" ] && sub_skill_names+=("$(basename "$s")")
|
|
88
|
+
done
|
|
89
|
+
|
|
90
|
+
echo ""
|
|
91
|
+
select sub_skill_name in "${sub_skill_names[@]}" "Link entire repo"; do
|
|
92
|
+
if [ -n "$sub_skill_name" ]; then
|
|
93
|
+
if [ "$sub_skill_name" == "Link entire repo" ]; then
|
|
94
|
+
SKILL_PATH="${selected_repo_path%/}"
|
|
95
|
+
else
|
|
96
|
+
SKILL_PATH="$SKILLS_DIR/$sub_skill_name"
|
|
97
|
+
fi
|
|
98
|
+
break
|
|
99
|
+
else
|
|
100
|
+
echo "Invalid selection. Please try again."
|
|
101
|
+
fi
|
|
102
|
+
done
|
|
103
|
+
else
|
|
104
|
+
SKILL_PATH="${selected_repo_path%/}"
|
|
105
|
+
fi
|
|
106
|
+
else
|
|
107
|
+
SKILL_PATH="${selected_repo_path%/}"
|
|
108
|
+
fi
|
|
109
|
+
}
|
|
110
|
+
|
|
31
111
|
# Parse arguments
|
|
32
112
|
while [[ $# -gt 0 ]]; do
|
|
33
113
|
case $1 in
|
|
@@ -35,6 +115,10 @@ while [[ $# -gt 0 ]]; do
|
|
|
35
115
|
FROM_URL="$2"
|
|
36
116
|
shift 2
|
|
37
117
|
;;
|
|
118
|
+
--list|-l)
|
|
119
|
+
LIST_MODE=true
|
|
120
|
+
shift
|
|
121
|
+
;;
|
|
38
122
|
--help|-h)
|
|
39
123
|
show_help
|
|
40
124
|
;;
|
|
@@ -45,11 +129,42 @@ while [[ $# -gt 0 ]]; do
|
|
|
45
129
|
esac
|
|
46
130
|
done
|
|
47
131
|
|
|
132
|
+
# Handle --list mode
|
|
133
|
+
if [ "$LIST_MODE" = true ]; then
|
|
134
|
+
list_repos
|
|
135
|
+
fi
|
|
136
|
+
|
|
48
137
|
# 1. Handle --from flag: Clone from GitHub
|
|
49
138
|
if [ -n "$FROM_URL" ]; then
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
|
|
139
|
+
# Parse GitHub URL - check for /tree/branch/path format
|
|
140
|
+
SUBPATH=""
|
|
141
|
+
CLEAN_URL="$FROM_URL"
|
|
142
|
+
|
|
143
|
+
if [[ "$FROM_URL" =~ (.+)/tree/([^/]+)/(.+)$ ]]; then
|
|
144
|
+
# URL contains /tree/branch/path - extract subpath
|
|
145
|
+
BASE_REPO="${BASH_REMATCH[1]}"
|
|
146
|
+
BRANCH="${BASH_REMATCH[2]}"
|
|
147
|
+
SUBPATH="${BASH_REMATCH[3]}"
|
|
148
|
+
CLEAN_URL="$BASE_REPO"
|
|
149
|
+
print_info "Detected subpath: $SUBPATH (branch: $BRANCH)"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# Extract owner/repo from URL for namespaced storage
|
|
153
|
+
# Supports: https://github.com/owner/repo or https://github.com/owner/repo.git
|
|
154
|
+
if [[ "$CLEAN_URL" =~ github\.com[/:]([^/]+)/([^/]+)(\.git)?$ ]]; then
|
|
155
|
+
REPO_OWNER="${BASH_REMATCH[1]}"
|
|
156
|
+
REPO_NAME="${BASH_REMATCH[2]%.git}"
|
|
157
|
+
else
|
|
158
|
+
# Fallback: just use basename
|
|
159
|
+
REPO_OWNER=""
|
|
160
|
+
REPO_NAME=$(basename "$CLEAN_URL" .git)
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
if [ -n "$REPO_OWNER" ]; then
|
|
164
|
+
TARGET_CLONE_PATH="$DEFAULT_LIB_PATH/$REPO_OWNER/$REPO_NAME"
|
|
165
|
+
else
|
|
166
|
+
TARGET_CLONE_PATH="$DEFAULT_LIB_PATH/$REPO_NAME"
|
|
167
|
+
fi
|
|
53
168
|
|
|
54
169
|
# Ensure library directory exists
|
|
55
170
|
mkdir -p "$DEFAULT_LIB_PATH"
|
|
@@ -62,8 +177,8 @@ if [ -n "$FROM_URL" ]; then
|
|
|
62
177
|
git -C "$TARGET_CLONE_PATH" pull
|
|
63
178
|
fi
|
|
64
179
|
else
|
|
65
|
-
print_info "Cloning $
|
|
66
|
-
git clone "$
|
|
180
|
+
print_info "Cloning $CLEAN_URL to $TARGET_CLONE_PATH..."
|
|
181
|
+
git clone "$CLEAN_URL" "$TARGET_CLONE_PATH"
|
|
67
182
|
if [ $? -ne 0 ]; then
|
|
68
183
|
print_error "Failed to clone repository"
|
|
69
184
|
exit 1
|
|
@@ -71,7 +186,49 @@ if [ -n "$FROM_URL" ]; then
|
|
|
71
186
|
print_success "Clone completed!"
|
|
72
187
|
fi
|
|
73
188
|
|
|
74
|
-
|
|
189
|
+
# If subpath was specified in URL, use it directly
|
|
190
|
+
if [ -n "$SUBPATH" ]; then
|
|
191
|
+
SKILL_PATH="$TARGET_CLONE_PATH/$SUBPATH"
|
|
192
|
+
if [ ! -d "$SKILL_PATH" ]; then
|
|
193
|
+
print_error "Subpath not found: $SKILL_PATH"
|
|
194
|
+
exit 1
|
|
195
|
+
fi
|
|
196
|
+
else
|
|
197
|
+
# Check if this is a multi-skill repo (has skills/ subdirectory)
|
|
198
|
+
SKILLS_DIR="$TARGET_CLONE_PATH/skills"
|
|
199
|
+
if [ -d "$SKILLS_DIR" ]; then
|
|
200
|
+
print_info "Detected multi-skill repository. Listing available skills..."
|
|
201
|
+
|
|
202
|
+
sub_skills=("$SKILLS_DIR"/*/)
|
|
203
|
+
if [ ${#sub_skills[@]} -eq 0 ]; then
|
|
204
|
+
print_warning "No skills found in $SKILLS_DIR, using repo root"
|
|
205
|
+
SKILL_PATH="$TARGET_CLONE_PATH"
|
|
206
|
+
else
|
|
207
|
+
# Extract skill names for display
|
|
208
|
+
sub_skill_names=()
|
|
209
|
+
for s in "${sub_skills[@]}"; do
|
|
210
|
+
sub_skill_names+=("$(basename "$s")")
|
|
211
|
+
done
|
|
212
|
+
|
|
213
|
+
echo ""
|
|
214
|
+
echo "Available Skills in this repo:"
|
|
215
|
+
select sub_skill_name in "${sub_skill_names[@]}" "Link entire repo"; do
|
|
216
|
+
if [ -n "$sub_skill_name" ]; then
|
|
217
|
+
if [ "$sub_skill_name" == "Link entire repo" ]; then
|
|
218
|
+
SKILL_PATH="$TARGET_CLONE_PATH"
|
|
219
|
+
else
|
|
220
|
+
SKILL_PATH="$SKILLS_DIR/$sub_skill_name"
|
|
221
|
+
fi
|
|
222
|
+
break
|
|
223
|
+
else
|
|
224
|
+
echo "Invalid selection. Please try again."
|
|
225
|
+
fi
|
|
226
|
+
done
|
|
227
|
+
fi
|
|
228
|
+
else
|
|
229
|
+
SKILL_PATH="$TARGET_CLONE_PATH"
|
|
230
|
+
fi
|
|
231
|
+
fi
|
|
75
232
|
fi
|
|
76
233
|
|
|
77
234
|
# 2. Determine Source Skill Path (if not already set by --from)
|