skill-linker 4.1.1 → 4.1.3
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 +55 -20
- package/package.json +2 -2
- package/src/cli.js +1 -4
- package/src/commands/install.js +25 -1
- package/src/utils/file-system.js +21 -3
package/README.md
CHANGED
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
一個現代化的 CLI 工具,用於將 AI Agent Skills 快速連結(Symlink)到各種 AI Agent 的專案或全域目錄中。
|
|
8
8
|
|
|
9
|
+
## 🤔 這是什麼?
|
|
10
|
+
|
|
11
|
+
**AI Agent Skill** 是一包能擴充 AI 助手能力的檔案(例如讓 Claude 會處理 PDF、Word、Excel)。各家 AI 工具(Claude Code、Cursor、Gemini…)都會去自己的 `skills/` 目錄尋找這些技能。
|
|
12
|
+
|
|
13
|
+
`skill-linker` 幫你把一份 Skill 一次**連結(symlink)**到一個或多個 AI 工具的 skills 目錄,免去手動複製、也讓日後更新一處即可同步生效。
|
|
14
|
+
|
|
15
|
+
> 💡 **最快上手**:幫你的 Claude Code 安裝官方 Skills(PDF / Word / Excel / PPT 等),複製這行即可:
|
|
16
|
+
>
|
|
17
|
+
> ```bash
|
|
18
|
+
> npx skill-linker install --from https://github.com/anthropics/skills --agent claude
|
|
19
|
+
> ```
|
|
20
|
+
|
|
9
21
|
## ✨ 功能特色
|
|
10
22
|
|
|
11
23
|
- **CLI 優先設計**:專為 AI Agent 打造的命令列介面,無需互動問答。
|
|
@@ -21,13 +33,13 @@
|
|
|
21
33
|
|
|
22
34
|
```bash
|
|
23
35
|
# 安裝技能(需要 --skill 或 --from)
|
|
24
|
-
npx
|
|
36
|
+
npx skill-linker install --skill <路徑> --agent opencode --scope both --yes
|
|
25
37
|
npx skill-linker install --from https://github.com/anthropics/skills --agent claude --scope both
|
|
26
38
|
|
|
27
|
-
#
|
|
39
|
+
# 列出 Skill Library 中的 Repos
|
|
28
40
|
npx skill-linker list
|
|
29
|
-
npx skill-linker list --repo
|
|
30
|
-
npx skill-linker list --repo
|
|
41
|
+
npx skill-linker list --repo anthropics/skills
|
|
42
|
+
npx skill-linker list --repo anthropics/skills --json
|
|
31
43
|
```
|
|
32
44
|
|
|
33
45
|
### 方式 2:本地開發/安裝
|
|
@@ -58,50 +70,57 @@ Options:
|
|
|
58
70
|
### install 命令
|
|
59
71
|
|
|
60
72
|
```
|
|
61
|
-
Usage: skill-linker install --skill <path>
|
|
73
|
+
Usage: skill-linker install [--skill <path> | --from <github-url>] [options]
|
|
62
74
|
|
|
63
75
|
Options:
|
|
64
|
-
--skill <path>
|
|
65
|
-
--from <github-url>
|
|
66
|
-
-a, --agent <names
|
|
67
|
-
-s, --scope <scope>
|
|
68
|
-
-y, --yes
|
|
76
|
+
--skill <path> 指定本地 Skill 目錄路徑
|
|
77
|
+
--from <github-url> 從 GitHub Clone 後再進行連結
|
|
78
|
+
-a, --agent <names...> 指定一個或多個 Agent 名稱(opencode claude cursor …)
|
|
79
|
+
-s, --scope <scope> 範圍:project, global, both(預設 both)
|
|
80
|
+
-y, --yes 自動覆寫已存在的連結,並在 repo 已存在時更新
|
|
69
81
|
```
|
|
70
82
|
|
|
83
|
+
> `--skill` 與 `--from` 至少要提供一個(兩者皆可省略其一)。
|
|
84
|
+
>
|
|
85
|
+
> **`--agent` 省略時**:會自動安裝到所有「已偵測到」的 Agent —— 也就是那些全域目錄(如 `~/.claude`、`~/.cursor`)已存在於你系統上的工具。
|
|
86
|
+
|
|
71
87
|
範例:
|
|
72
88
|
|
|
73
89
|
```bash
|
|
74
|
-
#
|
|
90
|
+
# 指定本地路徑安裝到 opencode
|
|
75
91
|
npx skill-linker install --skill /path/to/skill --agent opencode
|
|
76
92
|
|
|
77
|
-
# 從 GitHub Clone
|
|
93
|
+
# 從 GitHub Clone 並一次安裝到多個 Agents
|
|
78
94
|
npx skill-linker install --from https://github.com/anthropics/skills --agent claude cursor --scope both
|
|
79
95
|
|
|
80
|
-
#
|
|
96
|
+
# 省略 --agent:安裝到所有已偵測到的 Agents
|
|
81
97
|
npx skill-linker install --skill /path/to/skill --scope both --yes
|
|
98
|
+
|
|
99
|
+
# 只安裝 multi-skill repo 中的「單一」子技能(用 GitHub 的 /tree/<branch>/<子路徑> 連結)
|
|
100
|
+
npx skill-linker install --from https://github.com/anthropics/skills/tree/main/skills/pdf --agent claude
|
|
82
101
|
```
|
|
83
102
|
|
|
84
|
-
|
|
103
|
+
`list` 會掃描你的 Skill Library(`~/Documents/AgentSkills`,由 `--from` 自動建立),顯示曾經 Clone 過的 repos 與其中的 skills。
|
|
85
104
|
|
|
86
105
|
```
|
|
87
106
|
Usage: skill-linker list [options]
|
|
88
107
|
|
|
89
108
|
Options:
|
|
90
|
-
-r, --repo <name> 指定 Repository
|
|
109
|
+
-r, --repo <name> 指定 Repository 名稱(格式為 owner/repo)
|
|
91
110
|
--json JSON 輸出格式
|
|
92
111
|
```
|
|
93
112
|
|
|
94
113
|
範例:
|
|
95
114
|
|
|
96
115
|
```bash
|
|
97
|
-
#
|
|
116
|
+
# 列出 Library 中所有 Repos
|
|
98
117
|
npx skill-linker list
|
|
99
118
|
|
|
100
|
-
# 列出特定 Repo 的 Skills
|
|
101
|
-
npx skill-linker list --repo
|
|
119
|
+
# 列出特定 Repo 的 Skills(名稱為 owner/repo)
|
|
120
|
+
npx skill-linker list --repo anthropics/skills
|
|
102
121
|
|
|
103
|
-
# JSON
|
|
104
|
-
npx skill-linker list --repo
|
|
122
|
+
# JSON 輸出(適合腳本處理)
|
|
123
|
+
npx skill-linker list --repo anthropics/skills --json
|
|
105
124
|
```
|
|
106
125
|
|
|
107
126
|
## 📂 Skill Library 管理
|
|
@@ -155,10 +174,26 @@ npx skill-linker install --from https://github.com/moltbot/skills --agent openco
|
|
|
155
174
|
npx skill-linker install --from https://github.com/obra/superpowers --agent claude cursor
|
|
156
175
|
```
|
|
157
176
|
|
|
177
|
+
## 🗑️ 移除已安裝的 Skill
|
|
178
|
+
|
|
179
|
+
本工具目前沒有 `uninstall` 命令。由於安裝動作只是建立一個 **symlink**,要移除時直接刪掉對應 Agent skills 目錄中的那個連結即可,**不會**影響到原始的 Skill 來源:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# 例如移除 Claude Code 專案目錄中名為 pdf 的 skill
|
|
183
|
+
rm .claude/skills/pdf
|
|
184
|
+
|
|
185
|
+
# 或移除全域安裝
|
|
186
|
+
rm ~/.claude/skills/pdf
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
各 Agent 的 skills 目錄位置請參考上方[支援的 Agent 與路徑](#-支援的-agent-與路徑)。若要刪除整份已 Clone 的來源,移除 `~/Documents/AgentSkills/<owner>/<repo>` 即可。
|
|
190
|
+
|
|
158
191
|
## ⚠️ 注意事項
|
|
159
192
|
|
|
160
193
|
1. **權限問題**:在建立 Symlink 時,請確保您有對應目錄的寫入權限。
|
|
161
194
|
2. **環境需求**:需安裝 Node.js 18.0.0 以上版本。
|
|
195
|
+
3. **Windows**:建立 Symlink 需開啟「開發者模式」或以系統管理員權限執行,否則 `fs.symlinkSync` 會失敗。
|
|
196
|
+
4. **覆寫保護**:`--yes` 只會覆寫既有的 Symlink;若目標是「真實目錄/檔案」,工具會拒絕刪除以保護資料。
|
|
162
197
|
|
|
163
198
|
## 授權
|
|
164
199
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skill-linker",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
4
4
|
"description": "CLI to link AI Agent Skills to various agents (Claude, Copilot, Antigravity, Cursor, etc.)",
|
|
5
5
|
"main": "bin/cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"skill-linker": "bin/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"test": "
|
|
10
|
+
"test": "node --test"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
13
13
|
"ai",
|
package/src/cli.js
CHANGED
|
@@ -19,10 +19,7 @@ program
|
|
|
19
19
|
program
|
|
20
20
|
.command("install")
|
|
21
21
|
.description("Install a skill to specified agents")
|
|
22
|
-
.
|
|
23
|
-
"--skill <path>",
|
|
24
|
-
"Path to skill directory or --from clone URL",
|
|
25
|
-
)
|
|
22
|
+
.option("--skill <path>", "Path to a local skill directory")
|
|
26
23
|
.option("--from <github-url>", "Clone skill from GitHub URL first, then link")
|
|
27
24
|
.option(
|
|
28
25
|
"-a, --agent <names...>",
|
package/src/commands/install.js
CHANGED
|
@@ -75,6 +75,15 @@ async function install(options) {
|
|
|
75
75
|
skillPaths = [options.skill];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// Require at least one source: --skill or --from
|
|
79
|
+
if (skillPaths.length === 0) {
|
|
80
|
+
console.error(
|
|
81
|
+
chalk.red("[ERROR]"),
|
|
82
|
+
"No skill source provided. Use --skill <path> or --from <github-url>.",
|
|
83
|
+
);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
// Validate skill paths
|
|
79
88
|
for (const p of skillPaths) {
|
|
80
89
|
if (!dirExists(p)) {
|
|
@@ -147,6 +156,9 @@ async function install(options) {
|
|
|
147
156
|
}
|
|
148
157
|
console.log(chalk.blue("[INFO]"), `Scope: ${scope}`);
|
|
149
158
|
|
|
159
|
+
let linkedCount = 0;
|
|
160
|
+
let failedCount = 0;
|
|
161
|
+
|
|
150
162
|
// Process each selected agent
|
|
151
163
|
for (const agentIndex of selectedAgents) {
|
|
152
164
|
const agent = agents[agentIndex];
|
|
@@ -189,15 +201,27 @@ async function install(options) {
|
|
|
189
201
|
|
|
190
202
|
if (createSymlink(sPath, targetLink)) {
|
|
191
203
|
console.log(chalk.green("[SUCCESS]"), `Linked ${sName}`);
|
|
204
|
+
linkedCount++;
|
|
192
205
|
} else {
|
|
193
206
|
console.error(chalk.red("[ERROR]"), `Failed to link ${sName}`);
|
|
207
|
+
failedCount++;
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
210
|
}
|
|
197
211
|
}
|
|
198
212
|
|
|
199
213
|
console.log("");
|
|
200
|
-
|
|
214
|
+
if (failedCount > 0) {
|
|
215
|
+
console.error(
|
|
216
|
+
chalk.red("[ERROR]"),
|
|
217
|
+
`Completed with errors: ${linkedCount} linked, ${failedCount} failed.`,
|
|
218
|
+
);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
console.log(
|
|
222
|
+
chalk.green("[SUCCESS]"),
|
|
223
|
+
`All operations completed (${linkedCount} linked).`,
|
|
224
|
+
);
|
|
201
225
|
}
|
|
202
226
|
|
|
203
227
|
module.exports = install;
|
package/src/utils/file-system.js
CHANGED
|
@@ -35,9 +35,27 @@ function createSymlink(source, target) {
|
|
|
35
35
|
// Ensure parent directory exists
|
|
36
36
|
ensureDir(path.dirname(target));
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
// Inspect the target itself without following symlinks.
|
|
39
|
+
let stat = null;
|
|
40
|
+
try {
|
|
41
|
+
stat = fs.lstatSync(target);
|
|
42
|
+
} catch {
|
|
43
|
+
// Target does not exist — nothing to remove.
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (stat) {
|
|
47
|
+
if (stat.isSymbolicLink()) {
|
|
48
|
+
// Safe: we are replacing a link, not real content.
|
|
49
|
+
fs.rmSync(target, { force: true });
|
|
50
|
+
} else {
|
|
51
|
+
// A real file or directory lives here. Refuse to delete it so
|
|
52
|
+
// we never destroy user data that we did not create.
|
|
53
|
+
console.error(
|
|
54
|
+
`Refusing to overwrite non-symlink target: ${target}`,
|
|
55
|
+
);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
41
59
|
|
|
42
60
|
fs.symlinkSync(source, target, 'dir');
|
|
43
61
|
return true;
|