skill-linker 4.1.2 → 4.1.4

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 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 打造的命令列介面,無需互動問答。
@@ -24,10 +36,10 @@
24
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
- # 列出已安裝的 Repos
39
+ # 列出 Skill Library 中的 Repos
28
40
  npx skill-linker list
29
- npx skill-linker list --repo skill-name
30
- npx skill-linker list --repo skill-name --json
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> 指定本地 Skill 目錄路徑(必需)
65
- --from <github-url> 從 GitHub Clone 後再進行連結
66
- -a, --agent <names> 指定 Agent 名稱(opencode, claude, cursor 等)
67
- -s, --scope <scope> 範圍:project, global, both(預設 both)
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
- # 指定路徑安裝到 opencode
90
+ # 指定本地路徑安裝到 opencode
75
91
  npx skill-linker install --skill /path/to/skill --agent opencode
76
92
 
77
- # 從 GitHub Clone 並安裝到多個 Agents
93
+ # 從 GitHub Clone 並一次安裝到多個 Agents
78
94
  npx skill-linker install --from https://github.com/anthropics/skills --agent claude cursor --scope both
79
95
 
80
- # 安裝到所有已偵測到的 Agents
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
- ### list 命令
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
- # 列出所有 Repos
116
+ # 列出 Library 中所有 Repos
98
117
  npx skill-linker list
99
118
 
100
- # 列出特定 Repo 的 Skills
101
- npx skill-linker list --repo skill-name
119
+ # 列出特定 Repo 的 Skills(名稱為 owner/repo)
120
+ npx skill-linker list --repo anthropics/skills
102
121
 
103
- # JSON 輸出
104
- npx skill-linker list --repo skill-name --json
122
+ # JSON 輸出(適合腳本處理)
123
+ npx skill-linker list --repo anthropics/skills --json
105
124
  ```
106
125
 
107
126
  ## 📂 Skill Library 管理
@@ -155,6 +174,20 @@ 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 時,請確保您有對應目錄的寫入權限。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skill-linker",
3
- "version": "4.1.2",
3
+ "version": "4.1.4",
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": {
@@ -32,6 +32,11 @@ function ensureDir(dirPath) {
32
32
  */
33
33
  function createSymlink(source, target) {
34
34
  try {
35
+ // Resolve the source to an absolute path. A relative source (e.g.
36
+ // "./my-skill") would otherwise be stored verbatim and resolved
37
+ // relative to the link's own directory, producing a broken link.
38
+ const resolvedSource = path.resolve(source);
39
+
35
40
  // Ensure parent directory exists
36
41
  ensureDir(path.dirname(target));
37
42
 
@@ -57,7 +62,7 @@ function createSymlink(source, target) {
57
62
  }
58
63
  }
59
64
 
60
- fs.symlinkSync(source, target, 'dir');
65
+ fs.symlinkSync(resolvedSource, target, 'dir');
61
66
  return true;
62
67
  } catch (error) {
63
68
  console.error(`Failed to create symlink: ${error.message}`);
package/src/utils/git.js CHANGED
@@ -13,7 +13,8 @@ const DEFAULT_LIB_PATH = path.join(os.homedir(), "Documents/AgentSkills");
13
13
  function parseGitHubUrl(url) {
14
14
  let cleanUrl = url;
15
15
  let subpath = "";
16
- let branch = "main";
16
+ // null means "no explicit branch" — let git use the remote default.
17
+ let branch = null;
17
18
 
18
19
  // Check for /tree/branch/path format
19
20
  const treeMatch = url.match(/(.+)\/tree\/([^/]+)\/(.+)$/);
@@ -39,19 +40,38 @@ function parseGitHubUrl(url) {
39
40
  };
40
41
  }
41
42
 
43
+ /**
44
+ * Build the argument list for `git clone`.
45
+ * @param {string} url - GitHub URL
46
+ * @param {string} targetPath - Target directory
47
+ * @param {Object} [opts]
48
+ * @param {boolean} [opts.shallow] - Use shallow clone (default true)
49
+ * @param {string|null} [opts.branch] - Branch to check out, or null for default
50
+ * @returns {string[]} git arguments
51
+ */
52
+ function buildCloneArgs(url, targetPath, { shallow = true, branch = null } = {}) {
53
+ const args = ["clone"];
54
+ if (shallow) {
55
+ args.push("--depth", "1");
56
+ }
57
+ if (branch) {
58
+ args.push("--branch", branch);
59
+ }
60
+ args.push(url, targetPath);
61
+ return args;
62
+ }
63
+
42
64
  /**
43
65
  * Clone a GitHub repository
44
66
  * @param {string} url - GitHub URL
45
67
  * @param {string} targetPath - Target directory
46
68
  * @param {boolean} shallow - Use shallow clone (default true)
69
+ * @param {string|null} branch - Branch to check out, or null for default
47
70
  * @returns {Promise<void>}
48
71
  */
49
- async function cloneRepo(url, targetPath, shallow = true) {
72
+ async function cloneRepo(url, targetPath, shallow = true, branch = null) {
50
73
  try {
51
- const args = shallow
52
- ? ["clone", "--depth", "1", url, targetPath]
53
- : ["clone", url, targetPath];
54
- await execa("git", args);
74
+ await execa("git", buildCloneArgs(url, targetPath, { shallow, branch }));
55
75
  } catch (error) {
56
76
  throw new Error(`Failed to clone repository: ${error.message}`);
57
77
  }
@@ -85,8 +105,8 @@ async function cloneOrUpdateRepo(url) {
85
105
  // Repo exists, ask if user wants to update
86
106
  needsUpdate = true;
87
107
  } else {
88
- // Clone new repo
89
- await cloneRepo(parsed.cleanUrl, targetPath);
108
+ // Clone new repo (honour an explicit branch from /tree/<branch>/ URLs)
109
+ await cloneRepo(parsed.cleanUrl, targetPath, true, parsed.branch);
90
110
  }
91
111
 
92
112
  // Determine final skill path
@@ -106,6 +126,7 @@ async function cloneOrUpdateRepo(url) {
106
126
  module.exports = {
107
127
  DEFAULT_LIB_PATH,
108
128
  parseGitHubUrl,
129
+ buildCloneArgs,
109
130
  cloneRepo,
110
131
  pullRepo,
111
132
  cloneOrUpdateRepo,