Install downloads and installs a skill from a registry. If fromRegistry is non-empty, only that registry is used. If multiple registries have the skill, the user is prompted to choose. Supported invocations: /skill install frontend-design → auto-detect or disambiguate /skill i
(ctx context.Context, name string, fromRegistry string)
| 298 | // /skill install frontend-design --from skills.sh → explicit registry |
| 299 | // /skill install anthropics/skills/frontend-design → skills.sh slug (unambiguous) |
| 300 | func (sh *SkillHandler) Install(ctx context.Context, name string, fromRegistry string) { |
| 301 | ctx, cancel := context.WithTimeout(ctx, 60*time.Second) |
| 302 | defer cancel() |
| 303 | |
| 304 | // Gather metadata from all registries |
| 305 | allMeta := sh.registryMgr.GetAllSkillMeta(ctx, name) |
| 306 | |
| 307 | // Filter by --from registry if specified |
| 308 | if fromRegistry != "" { |
| 309 | var filtered []*registry.SkillMeta |
| 310 | for _, m := range allMeta { |
| 311 | if m.RegistryName == fromRegistry { |
| 312 | filtered = append(filtered, m) |
| 313 | } |
| 314 | } |
| 315 | if len(filtered) == 0 { |
| 316 | fmt.Printf("\n %s %q %s %q\n", |
| 317 | colorize(i18n.T("skill.install.not_found_in")+":", ColorYellow), |
| 318 | name, i18n.T("skill.install.in_registry"), fromRegistry) |
| 319 | if len(allMeta) > 0 { |
| 320 | fmt.Printf(" %s:", i18n.T("skill.install.available_in")) |
| 321 | for _, m := range allMeta { |
| 322 | fmt.Printf(" %s", colorize(m.RegistryName, ColorCyan)) |
| 323 | } |
| 324 | fmt.Println() |
| 325 | } |
| 326 | fmt.Println() |
| 327 | return |
| 328 | } |
| 329 | allMeta = filtered |
| 330 | } |
| 331 | |
| 332 | // If no metadata found at all, try direct install as fallback |
| 333 | if len(allMeta) == 0 { |
| 334 | fmt.Printf("\n %s %s...\n", i18n.T("skill.install.installing"), colorize(name, ColorCyan)) |
| 335 | result, installErr := sh.registryMgr.Install(ctx, name) |
| 336 | if installErr != nil { |
| 337 | fmt.Printf(" %s %s\n\n", colorize(i18n.T("skill.error")+":", ColorRed), installErr.Error()) |
| 338 | return |
| 339 | } |
| 340 | sh.showInstallResult(result) |
| 341 | return |
| 342 | } |
| 343 | |
| 344 | // If multiple registries have it and no --from was specified, disambiguate |
| 345 | if len(allMeta) > 1 && fromRegistry == "" { |
| 346 | // Check if registries are actually different |
| 347 | registries := make(map[string]bool) |
| 348 | for _, m := range allMeta { |
| 349 | registries[m.RegistryName] = true |
| 350 | } |
| 351 | if len(registries) > 1 { |
| 352 | fmt.Printf("\n %s %q %s:\n\n", |
| 353 | i18n.T("skill.install.found_in_multiple"), |
| 354 | name, |
| 355 | i18n.T("skill.install.registries_label")) |
| 356 | for i, m := range allMeta { |
| 357 | installStr := "" |
no test coverage detected