skill-linker 1.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 ADDED
@@ -0,0 +1,84 @@
1
+ # AI Agent Skill Installer
2
+
3
+ 一個互動式 CLI 工具,用於將 AI Agent Skills 快速連結(Symlink)到各種 AI Agent 的專案或全域目錄中。
4
+
5
+ ## ✨ 功能特色
6
+
7
+ - **多 Agent 支援**:支援 Claude Code, GitHub Copilot, Antigravity, Cursor, Windsurf, OpenCode 等。
8
+ - **雙重範圍 (Scope)**:可選擇安裝到當前 `專案目錄 (Project)` 或 `全域目錄 (Global)`。
9
+ - **自動 Clone**:使用 `--from` 參數可直接從 GitHub Clone Skill。
10
+ - **Skill Library 支援**:自動偵測統一的 Skill 存放區。
11
+
12
+ ## 🚀 快速開始
13
+
14
+ ### 方式 1:使用 npx (推薦)
15
+
16
+ 無需安裝,直接執行:
17
+
18
+ ```bash
19
+ # 互動式選擇本地 Skill
20
+ npx skill-linker
21
+
22
+ # 從 GitHub Clone 並安裝
23
+ npx skill-linker --from https://github.com/user/my-skill
24
+
25
+ # 指定本地路徑
26
+ npx skill-linker /path/to/my-skill
27
+ ```
28
+
29
+ ### 方式 2:Clone 此專案
30
+
31
+ ```bash
32
+ git clone https://github.com/user/skill-installer.git
33
+ cd skill-installer
34
+ ./link-skill.sh
35
+ ```
36
+
37
+ ## 🛠️ 命令說明
38
+
39
+ ```
40
+ Usage: link-skill.sh [OPTIONS] [SKILL_PATH]
41
+
42
+ Options:
43
+ --from <github_url> 從 GitHub Clone Skill 後再連結
44
+ --help 顯示說明
45
+
46
+ Examples:
47
+ ./link-skill.sh # 互動式選擇
48
+ ./link-skill.sh /path/to/skill # 指定本地 Skill
49
+ ./link-skill.sh --from https://github.com/user/my-skill
50
+ ```
51
+
52
+ ## 📂 Skill Library
53
+
54
+ 建議將您的 Public Skills 統一存放在 `~/Documents/AgentSkills`:
55
+
56
+ ```bash
57
+ mkdir -p ~/Documents/AgentSkills
58
+ cd ~/Documents/AgentSkills
59
+ git clone https://github.com/user/my-awesome-skill.git
60
+ ```
61
+
62
+ 腳本會自動偵測此目錄並列出可用的 Skills。
63
+
64
+ ## 🛠️ 支援的 Agent 與路徑
65
+
66
+ | 平台 / 工具 | 專案目錄 | 全域目錄 |
67
+ |------------|---------|---------|
68
+ | **Claude Code** | `.claude/skills/` | `~/.claude/skills/` |
69
+ | **GitHub Copilot** | `.github/skills/` | `~/.copilot/skills/` |
70
+ | **Google Antigravity** | `.agent/skills/` | `~/.gemini/antigravity/skills/` |
71
+ | **Cursor** | `.cursor/skills/` | `~/.cursor/skills/` |
72
+ | **OpenCode** | `.opencode/skill/` | `~/.config/opencode/skill/` |
73
+ | **OpenAI Codex** | `.codex/skills/` | `~/.codex/skills/` |
74
+ | **Gemini CLI** | `.gemini/skills/` | `~/.gemini/skills/` |
75
+ | **Windsurf** | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
76
+
77
+ ## ⚠️ 注意事項
78
+
79
+ 1. **Windows 使用者**:請使用 WSL 或 Git Bash 執行此工具。
80
+ 2. **Git Clone First**:`--from` 參數會自動處理 clone,但如果不使用該參數,請確保 Skill 已在本地。
81
+
82
+ ## 授權
83
+
84
+ MIT License
package/bin/cli.js ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * skill-linker CLI
5
+ * Node.js wrapper for link-skill.sh
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+
12
+ // Get the path to the shell script
13
+ const scriptPath = path.join(__dirname, '..', 'link-skill.sh');
14
+
15
+ // Check if bash is available
16
+ const isWindows = process.platform === 'win32';
17
+
18
+ if (isWindows) {
19
+ console.error('\x1b[31m[ERROR]\x1b[0m This tool requires Bash.');
20
+ console.error('On Windows, please use WSL (Windows Subsystem for Linux) or Git Bash.');
21
+ console.error('');
22
+ console.error('Example with WSL:');
23
+ console.error(' wsl npx skill-linker');
24
+ process.exit(1);
25
+ }
26
+
27
+ // Check if script exists
28
+ if (!fs.existsSync(scriptPath)) {
29
+ console.error('\x1b[31m[ERROR]\x1b[0m Shell script not found:', scriptPath);
30
+ process.exit(1);
31
+ }
32
+
33
+ // Forward all arguments to the shell script
34
+ const args = process.argv.slice(2);
35
+
36
+ const child = spawn('bash', [scriptPath, ...args], {
37
+ stdio: 'inherit',
38
+ cwd: process.cwd()
39
+ });
40
+
41
+ child.on('error', (err) => {
42
+ console.error('\x1b[31m[ERROR]\x1b[0m Failed to run script:', err.message);
43
+ process.exit(1);
44
+ });
45
+
46
+ child.on('close', (code) => {
47
+ process.exit(code || 0);
48
+ });
package/link-skill.sh ADDED
@@ -0,0 +1,256 @@
1
+ #!/bin/bash
2
+
3
+ # link-skill.sh
4
+ # Interactive script to link AI Agent Skills to various AI agents
5
+ DEFAULT_LIB_PATH="$HOME/Documents/AgentSkills"
6
+ SKILL_PATH=""
7
+ FROM_URL=""
8
+
9
+ # Helper function for colored output
10
+ print_info() { echo -e "\033[1;34m[INFO]\033[0m $1"; }
11
+ print_success() { echo -e "\033[1;32m[SUCCESS]\033[0m $1"; }
12
+ print_warning() { echo -e "\033[1;33m[WARNING]\033[0m $1"; }
13
+ print_error() { echo -e "\033[1;31m[ERROR]\033[0m $1"; }
14
+
15
+ # Show help
16
+ show_help() {
17
+ echo "Usage: link-skill.sh [OPTIONS] [SKILL_PATH]"
18
+ echo ""
19
+ echo "Options:"
20
+ echo " --from <github_url> Clone skill from GitHub URL first, then link"
21
+ echo " --help Show this help message"
22
+ echo ""
23
+ echo "Examples:"
24
+ echo " ./link-skill.sh # Interactive selection from library"
25
+ echo " ./link-skill.sh /path/to/skill # Link specific local skill"
26
+ echo " ./link-skill.sh --from https://github.com/user/my-skill"
27
+ echo ""
28
+ exit 0
29
+ }
30
+
31
+ # Parse arguments
32
+ while [[ $# -gt 0 ]]; do
33
+ case $1 in
34
+ --from)
35
+ FROM_URL="$2"
36
+ shift 2
37
+ ;;
38
+ --help|-h)
39
+ show_help
40
+ ;;
41
+ *)
42
+ SKILL_PATH="$1"
43
+ shift
44
+ ;;
45
+ esac
46
+ done
47
+
48
+ # 1. Handle --from flag: Clone from GitHub
49
+ if [ -n "$FROM_URL" ]; then
50
+ # Extract repo name from URL
51
+ REPO_NAME=$(basename "$FROM_URL" .git)
52
+ TARGET_CLONE_PATH="$DEFAULT_LIB_PATH/$REPO_NAME"
53
+
54
+ # Ensure library directory exists
55
+ mkdir -p "$DEFAULT_LIB_PATH"
56
+
57
+ if [ -d "$TARGET_CLONE_PATH" ]; then
58
+ print_warning "Directory already exists: $TARGET_CLONE_PATH"
59
+ read -p "Update with git pull? (y/N): " do_pull
60
+ if [[ "$do_pull" =~ ^[yY]$ ]]; then
61
+ print_info "Pulling latest changes..."
62
+ git -C "$TARGET_CLONE_PATH" pull
63
+ fi
64
+ else
65
+ print_info "Cloning $FROM_URL to $TARGET_CLONE_PATH..."
66
+ git clone "$FROM_URL" "$TARGET_CLONE_PATH"
67
+ if [ $? -ne 0 ]; then
68
+ print_error "Failed to clone repository"
69
+ exit 1
70
+ fi
71
+ print_success "Clone completed!"
72
+ fi
73
+
74
+ SKILL_PATH="$TARGET_CLONE_PATH"
75
+ fi
76
+
77
+ # 2. Determine Source Skill Path (if not already set by --from)
78
+ if [ -z "$SKILL_PATH" ]; then
79
+ # Check if default library exists
80
+ if [ -d "$DEFAULT_LIB_PATH" ]; then
81
+ print_info "No skill path provided. Checking default library: $DEFAULT_LIB_PATH"
82
+ skills=("$DEFAULT_LIB_PATH"/*/)
83
+
84
+ if [ ${#skills[@]} -eq 0 ]; then
85
+ print_error "No skills found in $DEFAULT_LIB_PATH"
86
+ print_info "Please provide a skill path: ./link-skill.sh <path_to_skill>"
87
+ exit 1
88
+ fi
89
+
90
+ # Extract skill names for display
91
+ skill_names=()
92
+ for s in "${skills[@]}"; do
93
+ skill_names+=("$(basename "$s")")
94
+ done
95
+
96
+ echo "Available Skills:"
97
+ select skill_name in "${skill_names[@]}"; do
98
+ if [ -n "$skill_name" ]; then
99
+ SKILL_PATH="${DEFAULT_LIB_PATH}/${skill_name}"
100
+ break
101
+ else
102
+ echo "Invalid selection. Please try again."
103
+ fi
104
+ done
105
+ else
106
+ # Fallback to current directory prompt
107
+ read -p "Enter path to skill directory (default: current dir): " input_path
108
+ input_path=${input_path:-.}
109
+ SKILL_PATH=$(realpath "$input_path")
110
+ fi
111
+ elif [ -n "$SKILL_PATH" ] && [ -z "$FROM_URL" ]; then
112
+ # Path provided directly as argument
113
+ SKILL_PATH=$(realpath "$SKILL_PATH")
114
+ fi
115
+
116
+ if [ ! -d "$SKILL_PATH" ]; then
117
+ print_error "Skill directory not found: $SKILL_PATH"
118
+ exit 1
119
+ fi
120
+
121
+ SKILL_NAME=$(basename "$SKILL_PATH")
122
+ print_info "Selected Skill: \033[1;36m$SKILL_NAME\033[0m ($SKILL_PATH)"
123
+
124
+ # 2. Define Supported Agents
125
+ # Format: "Name:ProjectDir:GlobalDir"
126
+ AGENTS=(
127
+ "Claude Code:.claude/skills:$HOME/.claude/skills"
128
+ "GitHub Copilot:.github/skills:$HOME/.copilot/skills"
129
+ "Google Antigravity:.agent/skills:$HOME/.gemini/antigravity/skills"
130
+ "Cursor:.cursor/skills:$HOME/.cursor/skills"
131
+ "OpenCode:.opencode/skill:$HOME/.config/opencode/skill"
132
+ "OpenAI Codex:.codex/skills:$HOME/.codex/skills"
133
+ "Gemini CLI:.gemini/skills:$HOME/.gemini/skills"
134
+ "Windsurf:.windsurf/skills:$HOME/.codeium/windsurf/skills"
135
+ )
136
+
137
+ # 3. Agent Selection
138
+ echo ""
139
+ echo "Select Agents to install to (Space to select, Enter to confirm):"
140
+ # Simple multi-select implementation using arrays
141
+ selected_indices=()
142
+ while true; do
143
+ for i in "${!AGENTS[@]}"; do
144
+ agent_info="${AGENTS[$i]}"
145
+ agent_name="${agent_info%%:*}"
146
+
147
+ # Check if selected
148
+ if [[ " ${selected_indices[*]} " =~ " $i " ]]; then
149
+ mark="[*]"
150
+ else
151
+ mark="[ ]"
152
+ fi
153
+ echo "$i) $mark $agent_name"
154
+ done
155
+
156
+ echo "a) Select All"
157
+ echo "d) Done"
158
+ read -p "Select option: " choice
159
+
160
+ if [[ "$choice" == "d" ]]; then
161
+ break
162
+ elif [[ "$choice" == "a" ]]; then
163
+ selected_indices=()
164
+ for i in "${!AGENTS[@]}"; do
165
+ selected_indices+=("$i")
166
+ done
167
+ elif [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 0 ] && [ "$choice" -lt "${#AGENTS[@]}" ]; then
168
+ if [[ " ${selected_indices[*]} " =~ " $choice " ]]; then
169
+ # Deselect
170
+ new_indices=()
171
+ for idx in "${selected_indices[@]}"; do
172
+ [[ "$idx" != "$choice" ]] && new_indices+=("$idx")
173
+ done
174
+ selected_indices=("${new_indices[@]}")
175
+ else
176
+ # Select
177
+ selected_indices+=("$choice")
178
+ fi
179
+ else
180
+ echo "Invalid choice."
181
+ fi
182
+ echo "------------------------"
183
+ done
184
+
185
+ if [ ${#selected_indices[@]} -eq 0 ]; then
186
+ print_warning "No agents selected. Exiting."
187
+ exit 0
188
+ fi
189
+
190
+ # 4. Process Each Selected Agent
191
+ for idx in "${selected_indices[@]}"; do
192
+ agent_raw="${AGENTS[$idx]}"
193
+ IFS=':' read -r agent_name project_dir global_dir <<< "$agent_raw"
194
+
195
+ echo ""
196
+ print_info "Configuring for \033[1;36m$agent_name\033[0m..."
197
+
198
+ # Scope Selection
199
+ echo "Select Scope:"
200
+ echo "1) Project ($project_dir)"
201
+ echo "2) Global ($global_dir)"
202
+ echo "3) Both"
203
+ echo "s) Skip"
204
+ read -p "Choice [1-3]: " scope_choice
205
+
206
+ targets=()
207
+ case $scope_choice in
208
+ 1) targets+=("$project_dir") ;;
209
+ 2) targets+=("$global_dir") ;;
210
+ 3) targets+=("$project_dir" "$global_dir") ;;
211
+ s|S) continue ;;
212
+ *) print_warning "Invalid choice, skipping $agent_name"; continue ;;
213
+ esac
214
+
215
+ for target_base in "${targets[@]}"; do
216
+ # Resolve path expansion if needed (already expanded in definition for Global, Project is relative)
217
+ if [[ "$target_base" == /* ]]; then
218
+ # Absolute path (Global)
219
+ target_dir="$target_base"
220
+ else
221
+ # Relative path (Project) - assume current dir is project root
222
+ target_dir="$(pwd)/$target_base"
223
+ fi
224
+
225
+ # Ensure target parent directory exists
226
+ if [ ! -d "$target_dir" ]; then
227
+ print_info "Creating directory: $target_dir"
228
+ mkdir -p "$target_dir"
229
+ fi
230
+
231
+ target_link="$target_dir/$SKILL_NAME"
232
+
233
+ # Check for existing link or directory
234
+ if [ -e "$target_link" ] || [ -L "$target_link" ]; then
235
+ print_warning "$target_link already exists."
236
+ read -p "Overwrite? (y/N): " overwrite
237
+ if [[ "$overwrite" =~ ^[yY]$ ]]; then
238
+ rm -rf "$target_link"
239
+ else
240
+ print_info "Skipping..."
241
+ continue
242
+ fi
243
+ fi
244
+
245
+ # Create Symlink
246
+ ln -s "$SKILL_PATH" "$target_link"
247
+ if [ $? -eq 0 ]; then
248
+ print_success "Linked to $target_link"
249
+ else
250
+ print_error "Failed to link to $target_link"
251
+ fi
252
+ done
253
+ done
254
+
255
+ echo ""
256
+ print_success "All operations completed."
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "skill-linker",
3
+ "version": "1.0.0",
4
+ "description": "Interactive CLI to link AI Agent Skills to various agents (Claude, Copilot, Antigravity, Cursor, etc.)",
5
+ "main": "bin/cli.js",
6
+ "bin": {
7
+ "skill-linker": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"No tests yet\""
11
+ },
12
+ "keywords": [
13
+ "ai",
14
+ "agent",
15
+ "skill",
16
+ "claude",
17
+ "copilot",
18
+ "cursor",
19
+ "antigravity",
20
+ "windsurf",
21
+ "opencode",
22
+ "codex",
23
+ "gemini",
24
+ "cli"
25
+ ],
26
+ "author": "",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/raybird/skill-installer.git"
31
+ },
32
+ "engines": {
33
+ "node": ">=14.0.0"
34
+ },
35
+ "files": [
36
+ "bin/",
37
+ "link-skill.sh",
38
+ "README.md"
39
+ ]
40
+ }