agent-skill-manager 0.1.3__py3-none-any.whl → 0.2.1__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-skill-manager
3
- Version: 0.1.3
3
+ Version: 0.2.1
4
4
  Summary: CLI tool for managing AI agent skills across multiple platforms
5
5
  Project-URL: Homepage, https://github.com/ackness/skill-manager
6
6
  Project-URL: Repository, https://github.com/ackness/skill-manager
@@ -36,28 +36,69 @@ A comprehensive CLI tool for managing AI agent skills across multiple platforms.
36
36
  ## Features
37
37
 
38
38
  - 📥 **Download** skills from GitHub with metadata tracking
39
- - 🚀 **Deploy** skills to multiple AI agents (global or project-level)
40
- - 🔄 **Update** skills automatically from GitHub sources
39
+ - **Discover** all skills in a repository automatically
40
+ - **Deploy** skills to multiple AI agents (global or project-level)
41
+ - � **Symlink** support - save disk space with symbolic links
42
+ - � **Update** skills automatically from GitHub sources
41
43
  - 🗑️ **Uninstall** with safe deletion (move to trash) or hard delete
42
44
  - ♻️ **Restore** deleted skills from trash
43
45
  - 📋 **List** all installed skills with version information
46
+ - ⚡ **CLI-first** - full command-line parameter support for automation
44
47
 
45
48
  ## Supported AI Agents
46
49
 
47
- - Claude Code
48
- - Cursor
49
- - Windsurf
50
- - OpenCode
51
- - GitHub Copilot
52
- - Goose
53
- - Gemini CLI
54
- - Roo Code
55
- - Kilo Code
56
- - Amp
57
- - Codex
58
- - Antigravity
59
- - Clawdbot
60
- - Droid
50
+ <!-- supported-agents:start -->
51
+ | Agent | `--agent` | Project Path | Global Path |
52
+ |-------|-----------|--------------|-------------|
53
+ | Amp, Kimi Code CLI | `amp`, `kimi-cli` | `.agents/skills/` | `~/.config/agents/skills/` |
54
+ | Antigravity | `antigravity` | `.agent/skills/` | `~/.gemini/antigravity/skills/` |
55
+ | Augment | `augment` | `.augment/rules/` | `~/.augment/rules/` |
56
+ | Claude Code | `claude-code` | `.claude/skills/` | `~/.claude/skills/` |
57
+ | OpenClaw | `openclaw` | `skills/` | `~/.moltbot/skills/` |
58
+ | Cline | `cline` | `.cline/skills/` | `~/.cline/skills/` |
59
+ | CodeBuddy | `codebuddy` | `.codebuddy/skills/` | `~/.codebuddy/skills/` |
60
+ | Codex | `codex` | `.agents/skills/` | `~/.codex/skills/` |
61
+ | Command Code | `command-code` | `.commandcode/skills/` | `~/.commandcode/skills/` |
62
+ | Continue | `continue` | `.continue/skills/` | `~/.continue/skills/` |
63
+ | Crush | `crush` | `.crush/skills/` | `~/.config/crush/skills/` |
64
+ | Cursor | `cursor` | `.cursor/skills/` | `~/.cursor/skills/` |
65
+ | Droid | `droid` | `.factory/skills/` | `~/.factory/skills/` |
66
+ | Gemini CLI | `gemini-cli` | `.agents/skills/` | `~/.gemini/skills/` |
67
+ | GitHub Copilot | `github-copilot` | `.agents/skills/` | `~/.copilot/skills/` |
68
+ | Goose | `goose` | `.goose/skills/` | `~/.config/goose/skills/` |
69
+ | Junie | `junie` | `.junie/skills/` | `~/.junie/skills/` |
70
+ | iFlow CLI | `iflow-cli` | `.iflow/skills/` | `~/.iflow/skills/` |
71
+ | Kilo Code | `kilo` | `.kilocode/skills/` | `~/.kilocode/skills/` |
72
+ | Kiro CLI | `kiro-cli` | `.kiro/skills/` | `~/.kiro/skills/` |
73
+ | Kode | `kode` | `.kode/skills/` | `~/.kode/skills/` |
74
+ | MCPJam | `mcpjam` | `.mcpjam/skills/` | `~/.mcpjam/skills/` |
75
+ | Mistral Vibe | `mistral-vibe` | `.vibe/skills/` | `~/.vibe/skills/` |
76
+ | Mux | `mux` | `.mux/skills/` | `~/.mux/skills/` |
77
+ | OpenCode | `opencode` | `.agents/skills/` | `~/.config/opencode/skills/` |
78
+ | OpenHands | `openhands` | `.openhands/skills/` | `~/.openhands/skills/` |
79
+ | Pi | `pi` | `.pi/skills/` | `~/.pi/agent/skills/` |
80
+ | Qoder | `qoder` | `.qoder/skills/` | `~/.qoder/skills/` |
81
+ | Qwen Code | `qwen-code` | `.qwen/skills/` | `~/.qwen/skills/` |
82
+ | Replit | `replit` | `.agents/skills/` | N/A (project-only) |
83
+ | Roo Code | `roo` | `.roo/skills/` | `~/.roo/skills/` |
84
+ | Trae | `trae` | `.trae/skills/` | `~/.trae/skills/` |
85
+ | Trae CN | `trae-cn` | `.trae/skills/` | `~/.trae-cn/skills/` |
86
+ | Windsurf | `windsurf` | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
87
+ | Zencoder | `zencoder` | `.zencoder/skills/` | `~/.zencoder/skills/` |
88
+ | Neovate | `neovate` | `.neovate/skills/` | `~/.neovate/skills/` |
89
+ | Pochi | `pochi` | `.pochi/skills/` | `~/.pochi/skills/` |
90
+ | AdaL | `adal` | `.adal/skills/` | `~/.adal/skills/` |
91
+ <!-- supported-agents:end -->
92
+
93
+ > [!NOTE]
94
+ > **Kiro CLI users:** After installing skills, manually add them to your custom agent's `resources` in
95
+ > `.kiro/agents/<agent>.json`:
96
+ >
97
+ > ```json
98
+ > {
99
+ > "resources": ["skill://.kiro/skills/**/SKILL.md"]
100
+ > }
101
+ > ```
61
102
 
62
103
  ## Installation
63
104
 
@@ -128,34 +169,78 @@ uvx --from agent-skill-manager sm install
128
169
  uvx --from agent-skill-manager sm list
129
170
 
130
171
  # Or after installation, use sm command directly:
131
- sm install # Install a skill from GitHub
132
- sm list # List installed skills
133
- sm update --all # Update all skills
134
- sm deploy # Deploy local skills to agents
135
- sm uninstall # Uninstall a skill (safe delete)
172
+ sm install # Install a skill from GitHub (interactive)
173
+ sm list # List installed skills
174
+ sm update --all # Update all skills
175
+ sm deploy # Deploy local skills to agents
176
+ sm uninstall # Uninstall a skill (safe delete)
177
+ sm agents # List all supported agents
136
178
  ```
137
179
 
138
180
  ## Commands
139
181
 
140
182
  | Command | Description |
141
183
  |---------|-------------|
142
- | `sm download` | Download a skill from GitHub |
184
+ | `sm install [url]` | Download and deploy skills (with discovery) |
185
+ | `sm download [url]` | Download a skill from GitHub |
143
186
  | `sm deploy` | Deploy local skills to agents |
144
- | `sm install` | Download and deploy in one step |
187
+ | `sm discover [url]` | Discover all skills in a repository |
145
188
  | `sm uninstall` | Remove skills (safe delete/hard delete) |
146
189
  | `sm restore` | Restore deleted skills from trash |
147
- | `sm update` | Update selected skills from GitHub |
148
- | `sm update --all` | Update all GitHub-sourced skills |
190
+ | `sm update [--all]` | Update skills from GitHub |
149
191
  | `sm list` | Show installed skills with versions |
192
+ | `sm agents` | List all supported agents |
150
193
  | `sm --version` / `sm -v` | Show version information |
151
194
 
195
+ ## CLI Options
196
+
197
+ | Option | Description |
198
+ |--------|-------------|
199
+ | `-a, --agent AGENT` | Target agent(s), can be specified multiple times |
200
+ | `-t, --type TYPE` | Deployment type: `global` (default) or `project` |
201
+ | `-d, --dest PATH` | Custom destination directory for downloads |
202
+ | `--no-symlink` | Disable symlinks, copy files instead (symlinks on by default) |
203
+ | `--no-discover` | Disable auto-discovery (on by default) |
204
+ | `--no-deploy` | Download only, skip deployment |
205
+ | `-y, --yes` | Skip confirmation prompts |
206
+
152
207
  ## Usage Examples
153
208
 
154
- ### Install a skill from GitHub
209
+ ### Install all skills from a repository
210
+
211
+ ```bash
212
+ # Install all skills from a repo (auto-discovery and symlinks enabled by default)
213
+ sm install https://github.com/cloudflare/skills -a windsurf -a cursor
214
+
215
+ # Use symlinks to save disk space (enabled by default, use --no-symlink to disable)
216
+ sm install https://github.com/cloudflare/skills -a claude-code
217
+
218
+ # Full CLI mode - no prompts
219
+ sm install https://github.com/user/repo/tree/main/skills/my-skill -a claude-code -t global
220
+
221
+ # Disable auto-discovery to install only the specific path
222
+ sm install https://github.com/user/repo/tree/main/skills/my-skill --no-discover -a cursor
223
+
224
+ # Disable symlinks, copy files instead
225
+ sm install https://github.com/cloudflare/skills --no-symlink -a windsurf
226
+
227
+ # Download to custom location
228
+ sm install https://github.com/user/repo/tree/main/skills/my-skill -d ./my-skills -a cursor
229
+ ```
230
+
231
+ ### Discover skills in a repository
232
+
233
+ ```bash
234
+ # Scan a repository to find all skills
235
+ sm discover https://github.com/cloudflare/skills
236
+ # Shows a table of all found skills with their paths
237
+ ```
238
+
239
+ ### Interactive mode (legacy)
155
240
 
156
241
  ```bash
157
242
  sm install
158
- # Enter URL: https://github.com/user/repo/tree/main/skills/example-skill
243
+ # Enter URL when prompted
159
244
  # Follow the prompts to save locally and deploy
160
245
  ```
161
246
 
@@ -187,6 +272,21 @@ sm uninstall
187
272
  sm restore
188
273
  ```
189
274
 
275
+ ### Using symlinks
276
+
277
+ Symlinks allow you to maintain a single copy of skills while deploying to multiple agents:
278
+
279
+ ```bash
280
+ # Download skills to a central location and symlink to agents (default behavior)
281
+ sm install https://github.com/cloudflare/skills -d ~/skills -a windsurf -a cursor -a claude-code
282
+
283
+ # Disable symlinks if needed
284
+ sm install https://github.com/cloudflare/skills --no-symlink -a windsurf
285
+ ```
286
+
287
+ > [!NOTE]
288
+ > On Windows, symlinks require Developer Mode or administrator privileges. If symlinks are not supported, the tool will automatically fall back to copying.
289
+
190
290
  ## Version Tracking
191
291
 
192
292
  The tool uses two methods for version identification:
@@ -0,0 +1,12 @@
1
+ skill_manager/__init__.py,sha256=l5Bfi0z6Vd5LEtgjsbP-zOYBifhKUWQGsj8DhzeTdFE,2137
2
+ skill_manager/agents.py,sha256=fGdYBREM5Kw_Djx8z_0pbe2V_-mSYngZRdJ86s8W-PU,8157
3
+ skill_manager/cli.py,sha256=4wbQFY0AUK81MFMQ7BXje2QPsJH7yMd12Y-rHgAvaDk,55647
4
+ skill_manager/deployment.py,sha256=YitXCJO8tje2mq34qS9qyxDrfQJbth9GiM3-3UPWT8I,10878
5
+ skill_manager/github.py,sha256=n2A6zId3T4lR-C5JKF9OTPQ9ptnnCWsWL2C8s2ziB2I,9232
6
+ skill_manager/metadata.py,sha256=PZrKsGMyBDEqrV93lXlc5z9xXRxxI24FhSHmWCvXltU,3503
7
+ skill_manager/removal.py,sha256=WeVdTszBVX8shnVP_ueuAAuZOYjoSHLNDfNCR1haakc,8042
8
+ skill_manager/validation.py,sha256=fRUJDs4TiuKlH3doey31SPJfe671JJQcBFSAhJwoSIE,1970
9
+ agent_skill_manager-0.2.1.dist-info/METADATA,sha256=HJLy4t8RMzAk4QJzO8slQ2zuE-iZnFjVIDOtLqn7Y_Q,12776
10
+ agent_skill_manager-0.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
11
+ agent_skill_manager-0.2.1.dist-info/entry_points.txt,sha256=ac3L07OC98p1llk259d9PUhDp-cl3ifV2nmYHGb3WO8,85
12
+ agent_skill_manager-0.2.1.dist-info/RECORD,,
skill_manager/__init__.py CHANGED
@@ -5,18 +5,25 @@ This package provides functionality to download, deploy, and manage
5
5
  skills across different AI agent platforms.
6
6
  """
7
7
 
8
- __version__ = "0.1.3"
8
+ __version__ = "0.2.1"
9
9
 
10
- from .agents import AGENTS, detect_existing_agents, get_agent_name, get_agent_path
10
+ from .agents import AGENTS, detect_existing_agents, get_agent_name, get_agent_path, supports_global_deployment
11
11
  from .deployment import (
12
+ create_symlink,
12
13
  deploy_multiple_skills,
13
14
  deploy_skill,
14
15
  deploy_skill_to_agents,
16
+ is_skill_symlink,
17
+ is_symlink_supported,
18
+ remove_symlink,
15
19
  update_all_skills,
16
20
  update_skill,
17
21
  )
18
22
  from .github import (
23
+ discover_skills_in_repo,
24
+ download_multiple_skills,
19
25
  download_skill_from_github,
26
+ get_system_temp_dir,
20
27
  parse_github_url,
21
28
  )
22
29
  from .metadata import (
@@ -49,14 +56,22 @@ __all__ = [
49
56
  "detect_existing_agents",
50
57
  "get_agent_name",
51
58
  "get_agent_path",
59
+ "supports_global_deployment",
52
60
  # Deployment
53
61
  "deploy_skill",
54
62
  "deploy_skill_to_agents",
55
63
  "deploy_multiple_skills",
56
64
  "update_skill",
57
65
  "update_all_skills",
66
+ "is_symlink_supported",
67
+ "create_symlink",
68
+ "remove_symlink",
69
+ "is_skill_symlink",
58
70
  # GitHub
59
71
  "download_skill_from_github",
72
+ "download_multiple_skills",
73
+ "discover_skills_in_repo",
74
+ "get_system_temp_dir",
60
75
  "parse_github_url",
61
76
  # Metadata
62
77
  "save_skill_metadata",
skill_manager/agents.py CHANGED
@@ -8,77 +8,241 @@ from pathlib import Path
8
8
 
9
9
  # Agent configuration mapping
10
10
  # Each agent has a name, project-level path, and global path
11
+ # Note: global=None means project-only (no global installation supported)
11
12
  AGENTS = {
12
- "opencode": {
13
- "name": "OpenCode",
14
- "project": ".opencode/skills/",
15
- "global": "~/.config/opencode/skills/",
13
+ # Amp, Kimi Code CLI
14
+ "amp": {
15
+ "name": "Amp",
16
+ "project": ".agents/skills/",
17
+ "global": "~/.config/agents/skills/",
18
+ },
19
+ "kimi-cli": {
20
+ "name": "Kimi Code CLI",
21
+ "project": ".agents/skills/",
22
+ "global": "~/.config/agents/skills/",
23
+ },
24
+ # Antigravity
25
+ "antigravity": {
26
+ "name": "Antigravity",
27
+ "project": ".agent/skills/",
28
+ "global": "~/.gemini/antigravity/skills/",
16
29
  },
30
+ # Augment
31
+ "augment": {
32
+ "name": "Augment",
33
+ "project": ".augment/rules/",
34
+ "global": "~/.augment/rules/",
35
+ },
36
+ # Claude Code
17
37
  "claude-code": {
18
38
  "name": "Claude Code",
19
39
  "project": ".claude/skills/",
20
40
  "global": "~/.claude/skills/",
21
41
  },
42
+ # OpenClaw
43
+ "openclaw": {
44
+ "name": "OpenClaw",
45
+ "project": "skills/",
46
+ "global": "~/.moltbot/skills/",
47
+ },
48
+ # Cline
49
+ "cline": {
50
+ "name": "Cline",
51
+ "project": ".cline/skills/",
52
+ "global": "~/.cline/skills/",
53
+ },
54
+ # CodeBuddy
55
+ "codebuddy": {
56
+ "name": "CodeBuddy",
57
+ "project": ".codebuddy/skills/",
58
+ "global": "~/.codebuddy/skills/",
59
+ },
60
+ # Codex
22
61
  "codex": {
23
62
  "name": "Codex",
24
- "project": ".codex/skills/",
63
+ "project": ".agents/skills/",
25
64
  "global": "~/.codex/skills/",
26
65
  },
66
+ # Command Code
67
+ "command-code": {
68
+ "name": "Command Code",
69
+ "project": ".commandcode/skills/",
70
+ "global": "~/.commandcode/skills/",
71
+ },
72
+ # Continue
73
+ "continue": {
74
+ "name": "Continue",
75
+ "project": ".continue/skills/",
76
+ "global": "~/.continue/skills/",
77
+ },
78
+ # Crush
79
+ "crush": {
80
+ "name": "Crush",
81
+ "project": ".crush/skills/",
82
+ "global": "~/.config/crush/skills/",
83
+ },
84
+ # Cursor
27
85
  "cursor": {
28
86
  "name": "Cursor",
29
87
  "project": ".cursor/skills/",
30
88
  "global": "~/.cursor/skills/",
31
89
  },
32
- "amp": {
33
- "name": "Amp",
90
+ # Droid
91
+ "droid": {
92
+ "name": "Droid",
93
+ "project": ".factory/skills/",
94
+ "global": "~/.factory/skills/",
95
+ },
96
+ # Gemini CLI
97
+ "gemini-cli": {
98
+ "name": "Gemini CLI",
34
99
  "project": ".agents/skills/",
35
- "global": "~/.config/agents/skills/",
100
+ "global": "~/.gemini/skills/",
36
101
  },
102
+ # GitHub Copilot
103
+ "github-copilot": {
104
+ "name": "GitHub Copilot",
105
+ "project": ".agents/skills/",
106
+ "global": "~/.copilot/skills/",
107
+ },
108
+ # Goose
109
+ "goose": {
110
+ "name": "Goose",
111
+ "project": ".goose/skills/",
112
+ "global": "~/.config/goose/skills/",
113
+ },
114
+ # Junie
115
+ "junie": {
116
+ "name": "Junie",
117
+ "project": ".junie/skills/",
118
+ "global": "~/.junie/skills/",
119
+ },
120
+ # iFlow CLI
121
+ "iflow-cli": {
122
+ "name": "iFlow CLI",
123
+ "project": ".iflow/skills/",
124
+ "global": "~/.iflow/skills/",
125
+ },
126
+ # Kilo Code
37
127
  "kilo": {
38
128
  "name": "Kilo Code",
39
129
  "project": ".kilocode/skills/",
40
130
  "global": "~/.kilocode/skills/",
41
131
  },
42
- "roo": {
43
- "name": "Roo Code",
44
- "project": ".roo/skills/",
45
- "global": "~/.roo/skills/",
132
+ # Kiro CLI
133
+ "kiro-cli": {
134
+ "name": "Kiro CLI",
135
+ "project": ".kiro/skills/",
136
+ "global": "~/.kiro/skills/",
46
137
  },
47
- "goose": {
48
- "name": "Goose",
49
- "project": ".goose/skills/",
50
- "global": "~/.config/goose/skills/",
138
+ # Kode
139
+ "kode": {
140
+ "name": "Kode",
141
+ "project": ".kode/skills/",
142
+ "global": "~/.kode/skills/",
51
143
  },
52
- "gemini-cli": {
53
- "name": "Gemini CLI",
54
- "project": ".gemini/skills/",
55
- "global": "~/.gemini/skills/",
144
+ # MCPJam
145
+ "mcpjam": {
146
+ "name": "MCPJam",
147
+ "project": ".mcpjam/skills/",
148
+ "global": "~/.mcpjam/skills/",
56
149
  },
57
- "antigravity": {
58
- "name": "Antigravity",
59
- "project": ".agent/skills/",
60
- "global": "~/.gemini/antigravity/skills/",
150
+ # Mistral Vibe
151
+ "mistral-vibe": {
152
+ "name": "Mistral Vibe",
153
+ "project": ".vibe/skills/",
154
+ "global": "~/.vibe/skills/",
61
155
  },
62
- "github-copilot": {
63
- "name": "GitHub Copilot",
64
- "project": ".github/skills/",
65
- "global": "~/.copilot/skills/",
156
+ # Mux
157
+ "mux": {
158
+ "name": "Mux",
159
+ "project": ".mux/skills/",
160
+ "global": "~/.mux/skills/",
66
161
  },
67
- "clawdbot": {
68
- "name": "Clawdbot",
69
- "project": "skills/",
70
- "global": "~/.clawdbot/skills/",
162
+ # OpenCode
163
+ "opencode": {
164
+ "name": "OpenCode",
165
+ "project": ".agents/skills/",
166
+ "global": "~/.config/opencode/skills/",
71
167
  },
72
- "droid": {
73
- "name": "Droid",
74
- "project": ".factory/skills/",
75
- "global": "~/.factory/skills/",
168
+ # OpenHands
169
+ "openhands": {
170
+ "name": "OpenHands",
171
+ "project": ".openhands/skills/",
172
+ "global": "~/.openhands/skills/",
173
+ },
174
+ # Pi
175
+ "pi": {
176
+ "name": "Pi",
177
+ "project": ".pi/skills/",
178
+ "global": "~/.pi/agent/skills/",
179
+ },
180
+ # Qoder
181
+ "qoder": {
182
+ "name": "Qoder",
183
+ "project": ".qoder/skills/",
184
+ "global": "~/.qoder/skills/",
185
+ },
186
+ # Qwen Code
187
+ "qwen-code": {
188
+ "name": "Qwen Code",
189
+ "project": ".qwen/skills/",
190
+ "global": "~/.qwen/skills/",
76
191
  },
192
+ # Replit (project-only)
193
+ "replit": {
194
+ "name": "Replit",
195
+ "project": ".agents/skills/",
196
+ "global": None,
197
+ },
198
+ # Roo Code
199
+ "roo": {
200
+ "name": "Roo Code",
201
+ "project": ".roo/skills/",
202
+ "global": "~/.roo/skills/",
203
+ },
204
+ # Trae
205
+ "trae": {
206
+ "name": "Trae",
207
+ "project": ".trae/skills/",
208
+ "global": "~/.trae/skills/",
209
+ },
210
+ # Trae CN
211
+ "trae-cn": {
212
+ "name": "Trae CN",
213
+ "project": ".trae/skills/",
214
+ "global": "~/.trae-cn/skills/",
215
+ },
216
+ # Windsurf
77
217
  "windsurf": {
78
218
  "name": "Windsurf",
79
219
  "project": ".windsurf/skills/",
80
220
  "global": "~/.codeium/windsurf/skills/",
81
221
  },
222
+ # Zencoder
223
+ "zencoder": {
224
+ "name": "Zencoder",
225
+ "project": ".zencoder/skills/",
226
+ "global": "~/.zencoder/skills/",
227
+ },
228
+ # Neovate
229
+ "neovate": {
230
+ "name": "Neovate",
231
+ "project": ".neovate/skills/",
232
+ "global": "~/.neovate/skills/",
233
+ },
234
+ # Pochi
235
+ "pochi": {
236
+ "name": "Pochi",
237
+ "project": ".pochi/skills/",
238
+ "global": "~/.pochi/skills/",
239
+ },
240
+ # AdaL
241
+ "adal": {
242
+ "name": "AdaL",
243
+ "project": ".adal/skills/",
244
+ "global": "~/.adal/skills/",
245
+ },
82
246
  }
83
247
 
84
248
 
@@ -91,7 +255,10 @@ def detect_existing_agents() -> dict[str, Path]:
91
255
  """
92
256
  existing = {}
93
257
  for agent_id, info in AGENTS.items():
94
- global_path = Path(info["global"]).expanduser()
258
+ global_path = info.get("global")
259
+ if global_path is None:
260
+ continue
261
+ global_path = Path(global_path).expanduser()
95
262
  if global_path.exists():
96
263
  existing[agent_id] = global_path
97
264
  return existing
@@ -108,6 +275,9 @@ def get_agent_path(agent_id: str, deployment_type: str = "global", project_root:
108
275
 
109
276
  Returns:
110
277
  The target path for the agent
278
+
279
+ Raises:
280
+ ValueError: If the agent doesn't support global deployment (global=None)
111
281
  """
112
282
  if agent_id not in AGENTS:
113
283
  raise ValueError(f"Unknown agent: {agent_id}")
@@ -115,13 +285,31 @@ def get_agent_path(agent_id: str, deployment_type: str = "global", project_root:
115
285
  info = AGENTS[agent_id]
116
286
 
117
287
  if deployment_type == "global":
118
- return Path(info["global"]).expanduser()
288
+ global_path = info.get("global")
289
+ if global_path is None:
290
+ raise ValueError(f"Agent '{agent_id}' does not support global deployment (project-only)")
291
+ return Path(global_path).expanduser()
119
292
  else:
120
293
  if project_root is None:
121
294
  project_root = Path.cwd()
122
295
  return project_root / info["project"]
123
296
 
124
297
 
298
+ def supports_global_deployment(agent_id: str) -> bool:
299
+ """
300
+ Check if an agent supports global deployment.
301
+
302
+ Args:
303
+ agent_id: The agent identifier
304
+
305
+ Returns:
306
+ True if the agent supports global deployment, False otherwise
307
+ """
308
+ if agent_id not in AGENTS:
309
+ raise ValueError(f"Unknown agent: {agent_id}")
310
+ return AGENTS[agent_id].get("global") is not None
311
+
312
+
125
313
  def get_agent_name(agent_id: str) -> str:
126
314
  """
127
315
  Get the display name for an agent.