skill-linker 4.1.0 → 4.1.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.
- package/README.md +3 -1
- package/package.json +3 -2
- package/skills/skill-linker/SKILL.md +59 -0
- 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
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
# 安裝技能(需要 --skill 或 --from)
|
|
24
|
-
npx
|
|
24
|
+
npx skill-linker install --skill <路徑> --agent opencode --scope both --yes
|
|
25
25
|
npx skill-linker install --from https://github.com/anthropics/skills --agent claude --scope both
|
|
26
26
|
|
|
27
27
|
# 列出已安裝的 Repos
|
|
@@ -159,6 +159,8 @@ npx skill-linker install --from https://github.com/obra/superpowers --agent clau
|
|
|
159
159
|
|
|
160
160
|
1. **權限問題**:在建立 Symlink 時,請確保您有對應目錄的寫入權限。
|
|
161
161
|
2. **環境需求**:需安裝 Node.js 18.0.0 以上版本。
|
|
162
|
+
3. **Windows**:建立 Symlink 需開啟「開發者模式」或以系統管理員權限執行,否則 `fs.symlinkSync` 會失敗。
|
|
163
|
+
4. **覆寫保護**:`--yes` 只會覆寫既有的 Symlink;若目標是「真實目錄/檔案」,工具會拒絕刪除以保護資料。
|
|
162
164
|
|
|
163
165
|
## 授權
|
|
164
166
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skill-linker",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.2",
|
|
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",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"files": [
|
|
41
41
|
"bin/",
|
|
42
42
|
"src/",
|
|
43
|
+
"skills/",
|
|
43
44
|
"README.md"
|
|
44
45
|
]
|
|
45
46
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-linker
|
|
3
|
+
description: Install and manage AI Agent Skills for Claude, Cursor, OpenCode, Gemini, Windsurf and other AI coding assistants. Use when you need to add new capabilities to your AI agent.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: skill-linker
|
|
7
|
+
|
|
8
|
+
A CLI tool to install and manage AI Agent Skills.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
Use this skill when:
|
|
13
|
+
|
|
14
|
+
- Installing new AI Agent Skills from GitHub or local directories
|
|
15
|
+
- Adding capabilities to Claude, Cursor, OpenCode or other AI assistants
|
|
16
|
+
- Managing skill installations (project or global)
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Install from GitHub
|
|
22
|
+
npx skill-linker install --from <url> --agent <agent> --scope both
|
|
23
|
+
|
|
24
|
+
# Install from local directory
|
|
25
|
+
npx skill-linker install --skill <path> --agent <agent> --scope both --yes
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Supported Agents
|
|
29
|
+
|
|
30
|
+
| Agent | Skill Directory |
|
|
31
|
+
| -------- | ------------------- |
|
|
32
|
+
| opencode | `.opencode/skills/` |
|
|
33
|
+
| claude | `.claude/skills/` |
|
|
34
|
+
| cursor | `.cursor/skills/` |
|
|
35
|
+
| gemini | `.gemini/skills/` |
|
|
36
|
+
| windsurf | `.windsurf/skills/` |
|
|
37
|
+
|
|
38
|
+
## Parameters
|
|
39
|
+
|
|
40
|
+
| Parameter | Description |
|
|
41
|
+
| ---------------- | --------------------------- |
|
|
42
|
+
| `--from <url>` | GitHub repository URL |
|
|
43
|
+
| `--skill <path>` | Local skill directory |
|
|
44
|
+
| `-a, --agent` | Target agent |
|
|
45
|
+
| `-s, --scope` | Scope (project/global/both) |
|
|
46
|
+
| `-y, --yes` | Auto overwrite |
|
|
47
|
+
|
|
48
|
+
## Examples
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Install for OpenCode
|
|
52
|
+
npx skill-linker install --from https://github.com/user/repo --agent opencode --scope both
|
|
53
|
+
|
|
54
|
+
# Install for Claude
|
|
55
|
+
npx skill-linker install --from https://github.com/org/skills --agent claude --scope project
|
|
56
|
+
|
|
57
|
+
# Update existing skill
|
|
58
|
+
npx skill-linker install --from https://github.com/org/skills --agent opencode --scope both --yes
|
|
59
|
+
```
|
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;
|