Class: Rubino::CLI::SkillsCommand
- Inherits:
-
Thor
- Object
- Thor
- Rubino::CLI::SkillsCommand
- Defined in:
- lib/rubino/cli/skills_command.rb
Overview
Subcommands for managing skills (#188). ‘list` mirrors the in-chat /skills disclosure (enabled/disabled markers), `show` prints a skill’s SKILL.md body (trust review before enabling), and ‘enable`/`disable` run the SAME registry-validated StateRepository write the HTTP API toggle and the in-chat `/skills enable|disable` use (Skills::Toggle) —no new logic, just the missing terminal surface.
‘install`/`update`/`remove` (#4) manage skills fetched from git repos (Skills::Installer): any repo shipping the registry’s ‘<name>/SKILL.md` layout is a source — no marketplace, nothing vendored in the gem.
Constant Summary collapse
- DOCUMENTS_SOURCE =
The ‘–documents` shorthand (#4): Anthropic’s four document skills.
"anthropics/skills"- DOCUMENT_SKILLS =
%w[pdf docx pptx xlsx].freeze
Class Method Summary collapse
Instance Method Summary collapse
- #disable(name) ⇒ Object
- #enable(name) ⇒ Object
- #install(source = nil) ⇒ Object
- #list ⇒ Object
- #remove(name) ⇒ Object
- #show(name) ⇒ Object
- #update(*names) ⇒ Object
Class Method Details
.exit_on_failure? ⇒ Boolean
25 26 27 |
# File 'lib/rubino/cli/skills_command.rb', line 25 def self.exit_on_failure? true end |
Instance Method Details
#disable(name) ⇒ Object
71 72 73 |
# File 'lib/rubino/cli/skills_command.rb', line 71 def disable(name) toggle(name, enabled: false) end |
#enable(name) ⇒ Object
66 67 68 |
# File 'lib/rubino/cli/skills_command.rb', line 66 def enable(name) toggle(name, enabled: true) end |
#install(source = nil) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/rubino/cli/skills_command.rb', line 82 def install(source = nil) wanted = Array([:skill]) if [:documents] source ||= DOCUMENTS_SOURCE wanted = DOCUMENT_SKILLS.dup if wanted.empty? end # Missing source / no-skills / fetch failure are all FAILURES on the # automation surface (P2-H1/H2): raise Thor::Error so the run exits # non-zero with the message on stderr instead of stdout-printing and # returning 0. raise Thor::Error, "missing source — pass owner/repo, a git URL, or --documents" if source.nil? installer = Skills::Installer.new fetched = installer.fetch(source) do |checkout, sha| found = installer.discover(checkout) if found.empty? raise Thor::Error, "no skills found in #{source} (expected <name>/SKILL.md directories)" elsif [:list] discovered_table(found) else install_selected(installer, found, wanted, checkout: checkout, source: source, commit: sha) end true end raise Thor::Error, "could not fetch #{source} — check the source name/URL and your network" if fetched.nil? end |
#list ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/rubino/cli/skills_command.rb', line 34 def list Rubino.ensure_database_ready! registry = Skills::Registry.trusted skills = registry.all if skills.empty? Rubino.ui.info("No skills found.") Rubino.ui.info("Add .md files to .rubino/skills/ to create skills.") warn_untrusted_hidden_skills(skills) return end sources = Skills::Installer.new.sources rows = skills.map do |skill| [skill.name, skill_status(skill.name, registry), provenance(skill.name, sources), skill.description.to_s] end Rubino.ui.table(headers: %w[Name Status Source Description], rows: rows) warn_untrusted_hidden_skills(skills) end |
#remove(name) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/rubino/cli/skills_command.rb', line 139 def remove(name) installer = Skills::Installer.new if installer.remove(name) Rubino.ui.success("Removed skill: #{name}") return end # Nothing removed — a FAILURE (P2-H1/H2). The "delete manually" hint # goes to stderr alongside the error, then raise so exit != 0. dir = File.join(installer.skills_dir, name) warn "It exists at #{dir} — delete the directory manually." if File.directory?(dir) raise Thor::Error, "#{name} wasn't installed via `rubino skills install` (no provenance entry)" end |
#show(name) ⇒ Object
55 56 57 58 59 60 61 62 63 |
# File 'lib/rubino/cli/skills_command.rb', line 55 def show(name) skill = Skills::Registry.trusted.find(name) # Not-found is a FAILURE on the automation surface (P2-H1/H2): raise so # exit_on_failure? exits non-zero with the message on stderr, matching # SessionCommand. ui.error wrote to stdout and returned 0. raise Thor::Error, "unknown skill: #{name}" if skill.nil? Rubino.ui.info(skill.content) end |
#update(*names) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/rubino/cli/skills_command.rb', line 111 def update(*names) installer = Skills::Installer.new if installer.sources.empty? Rubino.ui.info("No skills installed via `rubino skills install` yet.") return end # Report every name's outcome, but if ANY failed (unknown / fetch # failed), exit non-zero so automation detects the partial failure # (P2-H1). Per-name error lines go to stderr (warn), successes/notices # stay on stdout. failures = [] installer.update(names).each do |name, status| case status when :updated then Rubino.ui.success("Updated skill: #{name}") when :up_to_date then Rubino.ui.info("#{name} is up to date.") when :unknown warn "✗ unknown skill: #{name} (not installed via `rubino skills install`)" failures << name else warn "✗ could not update #{name} — fetch failed or the skill left its source" failures << name end end raise Thor::Error, "failed to update: #{failures.join(", ")}" unless failures.empty? end |