Class: Kward::Skills::Registry
- Inherits:
-
Object
- Object
- Kward::Skills::Registry
- Defined in:
- lib/kward/skills/registry.rb
Overview
Discovers Agent Skills and reads their bounded instruction resources.
Project sources are included only when the caller marks them trusted. If duplicate skill names exist, the first source in documented precedence order wins.
Defined Under Namespace
Classes: SkillSource
Instance Method Summary collapse
-
#initialize(config_dir:, workspace_root:, project_skills_trusted:, skill_class:, max_file_bytes:, markdown_parser:, inside_directory:) ⇒ Registry
constructor
A new instance of Registry.
-
#read_skill_file(name, relative_path = nil) ⇒ String
Reads a skill's main instructions or a bounded relative resource.
-
#skills ⇒ Array<ConfigFiles::Skill>
Returns discovered, validated skills in precedence order.
Constructor Details
#initialize(config_dir:, workspace_root:, project_skills_trusted:, skill_class:, max_file_bytes:, markdown_parser:, inside_directory:) ⇒ Registry
Returns a new instance of Registry.
17 18 19 20 21 22 23 24 25 |
# File 'lib/kward/skills/registry.rb', line 17 def initialize(config_dir:, workspace_root:, project_skills_trusted:, skill_class:, max_file_bytes:, markdown_parser:, inside_directory:) @config_dir = config_dir @workspace_root = workspace_root @project_skills_trusted = project_skills_trusted @skill_class = skill_class @max_file_bytes = max_file_bytes @markdown_parser = markdown_parser @inside_directory = inside_directory end |
Instance Method Details
#read_skill_file(name, relative_path = nil) ⇒ String
Reads a skill's main instructions or a bounded relative resource.
Absolute paths, paths escaping the skill folder, missing files, and files above the configured size limit return user-facing error strings.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/kward/skills/registry.rb', line 62 def read_skill_file(name, relative_path = nil) skill = skills.find { |candidate| candidate.name == name.to_s } return "Error: unknown skill: #{name}" unless skill path = relative_path.to_s.empty? ? "SKILL.md" : relative_path.to_s return "Error: skill path must be relative" if Pathname.new(path).absolute? base = File.realpath(skill.folder) target = File.(path, base) real_target = File.realpath(target) unless @inside_directory.call(real_target, base) return "Error: skill path outside skill folder: #{path}" end return "Error: skill path is not a file: #{path}" unless File.file?(real_target) size = File.size(real_target) return "Error: skill file too large: #{path} (#{size} bytes)" if size > @max_file_bytes content = File.read(real_target) relative_path.to_s.empty? ? skill_content(skill, content) : content rescue Errno::ENOENT "Error: skill file not found: #{path}" rescue StandardError => e "Error: could not read skill file #{path}: #{e.}" end |
#skills ⇒ Array<ConfigFiles::Skill>
Returns discovered, validated skills in precedence order.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/kward/skills/registry.rb', line 31 def skills seen = {} skill_sources.flat_map do |source| scan_source(source).filter_map do |path| skill = parse_skill(path) next unless skill if seen[skill.name] warn "Warning: skipping duplicate Kward skill #{skill.name.inspect}: #{path}" next end seen[skill.name] = true skill end end rescue StandardError => e warn "Warning: skipping Kward skills: #{e.}" [] end |