Module: Ask::Skills
- Defined in:
- lib/ask/skills.rb,
lib/ask/skills/skill.rb,
lib/ask/skills/version.rb,
lib/ask/skills/registry.rb,
lib/ask/skills/formatter.rb,
lib/ask/skills/validator.rb,
lib/ask/skills/sources/base.rb,
lib/ask/skills/sources/gems.rb,
lib/ask/skills/sources/filesystem.rb
Defined Under Namespace
Modules: Source Classes: Error, Formatter, Registry, Skill, Validator
Constant Summary collapse
- VERSION =
"0.2.1"
Class Method Summary collapse
- .builtin_skills_dir ⇒ Object
- .default_sources ⇒ Object
- .discover(sources: nil) ⇒ Object
-
.extract_body(content) ⇒ Object
Extract the markdown body from a file with frontmatter.
-
.load_file(path) ⇒ Skill
Load a skill from an arbitrary markdown file path.
-
.parse_frontmatter(content) ⇒ Object
Simple frontmatter parsing for skill files.
Class Method Details
.builtin_skills_dir ⇒ Object
33 34 35 36 37 38 |
# File 'lib/ask/skills.rb', line 33 def builtin_skills_dir # Skills live in lib/ask/skills/<skill_name>/SKILL.md # __dir__ in this file (lib/ask/skills.rb) is lib/ask/ # The skill directories are in lib/ask/skills/ File.join(__dir__, "skills") end |
.default_sources ⇒ Object
23 24 25 26 27 28 29 30 31 |
# File 'lib/ask/skills.rb', line 23 def default_sources [ # Highest priority first — first source wins in Registry Source::Filesystem.new(project_dir: ".agents/skills"), Source::Filesystem.new(user_dir: "~/.config/ask/skills"), Source::Gems.new, Source::Filesystem.new(dir: builtin_skills_dir), ] end |
.discover(sources: nil) ⇒ Object
19 20 21 |
# File 'lib/ask/skills.rb', line 19 def discover(sources: nil) Registry.new(sources || default_sources) end |
.extract_body(content) ⇒ Object
Extract the markdown body from a file with frontmatter.
82 83 84 85 86 87 88 |
# File 'lib/ask/skills.rb', line 82 def extract_body(content) return content unless content.start_with?("---\n") end_idx = content.index("\n---\n", 4) return content unless end_idx body = content[(end_idx + 5)..] || "" body.sub(/\A\n/, "").strip end |
.load_file(path) ⇒ Skill
Load a skill from an arbitrary markdown file path. Parses frontmatter if present, otherwise uses the filename as the skill name.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/ask/skills.rb', line 46 def load_file(path) path = File.(path) content = File.read(path) frontmatter = parse_frontmatter(content) body = extract_body(content) name = frontmatter["name"] || File.basename(path, ".md") description = frontmatter["description"] || "Ad-hoc skill loaded from #{File.basename(path)}" Skill.new( name: name, description: description, instructions: body.empty? ? content : body, source: path ) end |
.parse_frontmatter(content) ⇒ Object
Simple frontmatter parsing for skill files. Returns a hash of key-value pairs from between — markers.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/ask/skills.rb', line 65 def parse_frontmatter(content) return {} unless content.start_with?("---\n") end_idx = content.index("\n---\n", 4) return {} unless end_idx yaml_str = content[4...end_idx] yaml = {} yaml_str.split("\n").each do |line| if (m = line.match(/\A(\w+):\s*(.+)\z/)) value = m[2].strip value = value.gsub(/\A"|"\z/, "").gsub(/\A'|'\z/, "") yaml[m[1]] = value end end yaml end |