ruby_llm-skills 0.3.0 → 0.5.0.pre1

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.
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Skills
5
+ # Shared duck-typing predicates for classifying skill sources.
6
+ # Used by both AgentExtensions and ChatExtensions.
7
+ module SourceDetection
8
+ private
9
+
10
+ def loader_source?(source)
11
+ source.respond_to?(:list) && source.respond_to?(:find)
12
+ end
13
+
14
+ # A Marketplace::Registry: its installed plugins load through #loader.
15
+ def marketplace_source?(source)
16
+ source.respond_to?(:installed) && source.respond_to?(:loader)
17
+ end
18
+
19
+ def database_collection_source?(source)
20
+ return false unless source.respond_to?(:to_a)
21
+
22
+ # ActiveRecord relations/CollectionProxy: recognizable even when empty
23
+ return true if source.respond_to?(:klass) && source.respond_to?(:where_values_hash)
24
+
25
+ first = source.first
26
+ first&.respond_to?(:name) && first.respond_to?(:content)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Plugin marketplaces from the command line:
4
+ #
5
+ # rake skills:marketplaces:add[EveryInc/compound-writing] # record a marketplace
6
+ # rake skills:marketplaces:add[typesafe-ai/skills,v0.5.7] # pinned to a tag or commit
7
+ # rake skills:marketplaces:list # what is recorded and installed
8
+ # rake skills:marketplaces:plugins[compound-writing] # the plugins a marketplace lists
9
+ # rake skills:marketplaces:install[compound-writing] # every supported plugin
10
+ # rake skills:marketplaces:install[compound-writing,cw-draft] # selected plugins (space separated)
11
+ # rake skills:marketplaces:install # reproduce the lockfile
12
+ # rake skills:marketplaces:update # move unpinned marketplaces forward
13
+ # rake skills:marketplaces:remove[compound-writing]
14
+ #
15
+ # Under Rails the tasks load the environment first, so the root and lockfile
16
+ # resolve against Rails.root.
17
+ namespace :skills do
18
+ namespace :marketplaces do
19
+ prerequisites = Rake::Task.task_defined?(:environment) ? [:environment] : []
20
+
21
+ registry = -> { RubyLLM::Skills.marketplaces }
22
+
23
+ report = lambda do |result|
24
+ result.installed.each { |key| puts " + #{key}" }
25
+ result.updated.each { |key| puts " ~ #{key}" }
26
+ result.unchanged.each { |key| puts " = #{key}" }
27
+ result.skipped.each { |key, reason| puts " - #{key}: #{reason}" }
28
+ result.errors.each { |key, message| puts " ! #{key}: #{message}" }
29
+ abort("#{result.errors.size} plugin(s) failed") unless result.success?
30
+ end
31
+
32
+ desc "Add a marketplace (owner/repo, owner/repo@ref, repository URL, hosted marketplace.json URL, or directory)"
33
+ task :add, [:locator, :ref] => prerequisites do |_, args|
34
+ abort("Usage: rake skills:marketplaces:add[locator,ref]") unless args[:locator]
35
+
36
+ record = registry.call.add(args[:locator], ref: args[:ref])
37
+ puts "Added #{record.name} from #{record.source} at #{record.commit[0, 12]}"
38
+ puts "Install with: rake skills:marketplaces:install[#{record.name}]"
39
+ end
40
+
41
+ desc "List the recorded marketplaces and their installed plugins"
42
+ task list: prerequisites do
43
+ records = registry.call.list
44
+ if records.empty?
45
+ puts "No marketplaces in #{registry.call.lockfile_path}"
46
+ next
47
+ end
48
+
49
+ records.each do |record|
50
+ pin = record.pinned? ? " (pinned)" : ""
51
+ puts "#{record.name} #{record.source} @#{record.commit.to_s[0, 12]}#{pin}"
52
+ record.plugins.each_value do |plugin|
53
+ puts " #{plugin.name} #{plugin.version} skills: #{plugin.skills.join(", ")}"
54
+ end
55
+ end
56
+ end
57
+
58
+ desc "List the plugins a marketplace offers"
59
+ task :plugins, [:name] => prerequisites do |_, args|
60
+ abort("Usage: rake skills:marketplaces:plugins[marketplace]") unless args[:name]
61
+
62
+ record = registry.call.fetch(args[:name])
63
+ registry.call.plugins(record.name).each do |entry|
64
+ state = if record.plugins.key?(entry.name)
65
+ "installed"
66
+ elsif entry.supported?
67
+ "available"
68
+ else
69
+ "unsupported (#{entry.source.reason})"
70
+ end
71
+ puts "#{entry.name} #{entry.version || "-"} #{state}"
72
+ puts " #{entry.description}" if entry.description
73
+ end
74
+ end
75
+
76
+ desc "Install a marketplace's plugins (all, or the space separated names), or reproduce the lockfile"
77
+ task :install, [:name, :plugins] => prerequisites do |_, args|
78
+ only = args[:plugins]&.split
79
+ report.call(registry.call.install(args[:name], only: only))
80
+ end
81
+
82
+ desc "Update every marketplace (or one) to its ref's current head"
83
+ task :update, [:name] => prerequisites do |_, args|
84
+ report.call(registry.call.update(args[:name]))
85
+ end
86
+
87
+ desc "Remove a marketplace and its installed plugins"
88
+ task :remove, [:name] => prerequisites do |_, args|
89
+ abort("Usage: rake skills:marketplaces:remove[marketplace]") unless args[:name]
90
+
91
+ record = registry.call.remove(args[:name])
92
+ puts "Removed #{record.name}"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Loads the gem's Rake tasks outside Rails (the Railtie loads them under Rails):
4
+ #
5
+ # # Rakefile
6
+ # require "ruby_llm/skills/tasks"
7
+ #
8
+ require "ruby_llm/skills"
9
+
10
+ load File.expand_path("tasks/skills.rake", __dir__)
11
+ load File.expand_path("tasks/marketplaces.rake", __dir__)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Skills
5
- VERSION = "0.3.0"
5
+ VERSION = "0.5.0.pre1"
6
6
  end
7
7
  end
@@ -1,50 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # RubyLLM 1.12.0 Agent uses `delegate` but doesn't require ActiveSupport.
4
- # Provide a minimal fallback for plain Ruby environments.
5
- unless Module.method_defined?(:delegate)
6
- class Module
7
- def delegate(*methods, to:, prefix: nil, allow_nil: false, private: false, **_options)
8
- target_method = to.to_sym
9
-
10
- methods.each do |method_name|
11
- delegated_method = delegated_method_name(method_name, target_method, prefix)
12
-
13
- define_method(delegated_method) do |*args, **kwargs, &block|
14
- target = public_send(target_method)
15
- if target.nil?
16
- return nil if allow_nil
17
-
18
- raise NoMethodError,
19
- "#{self.class}##{delegated_method} delegated to ##{target_method}, but ##{target_method} is nil"
20
- end
21
-
22
- if kwargs.empty?
23
- target.public_send(method_name, *args, &block)
24
- else
25
- target.public_send(method_name, *args, **kwargs, &block)
26
- end
27
- end
28
-
29
- private delegated_method if binding.local_variable_get(:private)
30
- end
31
- end
32
-
33
- private
34
-
35
- def delegated_method_name(method_name, target_method, prefix)
36
- case prefix
37
- when true
38
- :"#{target_method}_#{method_name}"
39
- when String, Symbol
40
- :"#{prefix}_#{method_name}"
41
- else
42
- method_name
43
- end
44
- end
45
- end
46
- end
47
-
48
3
  require "ruby_llm"
49
4
 
50
5
  require_relative "skills/version"
@@ -56,6 +11,7 @@ require_relative "skills/loader"
56
11
  require_relative "skills/filesystem_loader"
57
12
  require_relative "skills/chat_extensions"
58
13
  require_relative "skills/agent_extensions"
14
+ require_relative "skills/marketplace"
59
15
 
60
16
  # Load Rails integration when Rails is available
61
17
  require_relative "skills/railtie" if defined?(Rails::Railtie)
@@ -118,6 +74,28 @@ module RubyLLM
118
74
  require_relative "skills/composite_loader"
119
75
  CompositeLoader.new(loaders)
120
76
  end
77
+
78
+ # The plugin marketplaces recorded in a lockfile and installed under a root.
79
+ #
80
+ # @param root [String] where plugins are installed (default: vendor/skills)
81
+ # @param lockfile [String] the lockfile (default: skills.lock.json)
82
+ # @return [Marketplace::Registry]
83
+ # @example
84
+ # marketplaces = RubyLLM::Skills.marketplaces
85
+ # marketplaces.add("EveryInc/compound-writing")
86
+ # marketplaces.install("compound-writing")
87
+ def marketplaces(root: Marketplace.root, lockfile: Marketplace.lockfile)
88
+ Marketplace::Registry.new(root: root, lockfile: lockfile)
89
+ end
90
+
91
+ # Load the skills of every installed marketplace plugin.
92
+ #
93
+ # @return [Loader] loader over the installed plugins' skills
94
+ # @example
95
+ # chat.with_skills("app/skills", RubyLLM::Skills.from_marketplaces)
96
+ def from_marketplaces(root: Marketplace.root, lockfile: Marketplace.lockfile)
97
+ marketplaces(root: root, lockfile: lockfile).loader
98
+ end
121
99
  end
122
100
 
123
101
  self.default_path = "app/skills"
metadata CHANGED
@@ -1,28 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm-skills
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kieran Klaassen
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 2026-02-17 00:00:00.000000000 Z
11
+ date: 2026-09-18 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: ruby_llm
14
15
  requirement: !ruby/object:Gem::Requirement
15
16
  requirements:
16
- - - "~>"
17
+ - - ">="
17
18
  - !ruby/object:Gem::Version
18
- version: '1.12'
19
+ version: 2.0.0.rc3
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3'
19
23
  type: :runtime
20
24
  prerelease: false
21
25
  version_requirements: !ruby/object:Gem::Requirement
22
26
  requirements:
23
- - - "~>"
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 2.0.0.rc3
30
+ - - "<"
24
31
  - !ruby/object:Gem::Version
25
- version: '1.12'
32
+ version: '3'
26
33
  description: Load, validate, and integrate Agent Skills with RubyLLM. Supports the
27
34
  open Agent Skills specification for progressive skill discovery and loading from
28
35
  filesystem, zip archives, and databases.
@@ -46,10 +53,25 @@ files:
46
53
  - lib/ruby_llm/skills/error.rb
47
54
  - lib/ruby_llm/skills/filesystem_loader.rb
48
55
  - lib/ruby_llm/skills/loader.rb
56
+ - lib/ruby_llm/skills/marketplace.rb
57
+ - lib/ruby_llm/skills/marketplace/bundle.rb
58
+ - lib/ruby_llm/skills/marketplace/config.rb
59
+ - lib/ruby_llm/skills/marketplace/fetcher.rb
60
+ - lib/ruby_llm/skills/marketplace/github_repo.rb
61
+ - lib/ruby_llm/skills/marketplace/gitlab_repo.rb
62
+ - lib/ruby_llm/skills/marketplace/http.rb
63
+ - lib/ruby_llm/skills/marketplace/locator.rb
64
+ - lib/ruby_llm/skills/marketplace/lockfile.rb
65
+ - lib/ruby_llm/skills/marketplace/manifest.rb
66
+ - lib/ruby_llm/skills/marketplace/registry.rb
67
+ - lib/ruby_llm/skills/marketplace/tarball.rb
49
68
  - lib/ruby_llm/skills/parser.rb
50
69
  - lib/ruby_llm/skills/railtie.rb
51
70
  - lib/ruby_llm/skills/skill.rb
52
71
  - lib/ruby_llm/skills/skill_tool.rb
72
+ - lib/ruby_llm/skills/source_detection.rb
73
+ - lib/ruby_llm/skills/tasks.rb
74
+ - lib/ruby_llm/skills/tasks/marketplaces.rake
53
75
  - lib/ruby_llm/skills/tasks/skills.rake
54
76
  - lib/ruby_llm/skills/validator.rb
55
77
  - lib/ruby_llm/skills/version.rb
@@ -61,6 +83,7 @@ metadata:
61
83
  source_code_uri: https://github.com/kieranklaassen/ruby_llm-skills
62
84
  changelog_uri: https://github.com/kieranklaassen/ruby_llm-skills/blob/main/CHANGELOG.md
63
85
  rubygems_mfa_required: 'true'
86
+ post_install_message:
64
87
  rdoc_options: []
65
88
  require_paths:
66
89
  - lib
@@ -71,11 +94,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
71
94
  version: 3.2.0
72
95
  required_rubygems_version: !ruby/object:Gem::Requirement
73
96
  requirements:
74
- - - ">="
97
+ - - ">"
75
98
  - !ruby/object:Gem::Version
76
- version: '0'
99
+ version: 1.3.1
77
100
  requirements: []
78
- rubygems_version: 3.6.2
101
+ rubygems_version: 3.4.20
102
+ signing_key:
79
103
  specification_version: 4
80
104
  summary: Agent Skills extension for RubyLLM
81
105
  test_files: []