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.3.0"

Class Method Summary collapse

Class Method Details

.builtin_skills_dirObject

Built-in skills that ship with the gem.



37
38
39
# File 'lib/ask/skills.rb', line 37

def builtin_skills_dir
  File.join(__dir__, "skills")
end

.default_sourcesObject

Default sources when no custom sources or agent directory given. Legacy .agents/skills/ is kept for backward compatibility.



32
33
34
# File 'lib/ask/skills.rb', line 32

def default_sources
  build_source_list
end

.discover(sources: nil, agent_dir: nil) ⇒ Registry

Discover skills from all configured sources.

Parameters:

  • agent_dir (String, nil) (defaults to: nil)

    optional agent directory to discover per-agent skills from (e.g. "agents/health_check")

  • sources (Array<Source::Base>, nil) (defaults to: nil)

    custom source list

Returns:



25
26
27
28
# File 'lib/ask/skills.rb', line 25

def discover(sources: nil, agent_dir: nil)
  all_sources = sources || build_source_list(agent_dir: agent_dir)
  Registry.new(all_sources)
end

.extract_body(content) ⇒ Object

Extract the markdown body from a file with frontmatter.



77
78
79
80
81
82
83
# File 'lib/ask/skills.rb', line 77

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) ⇒ Object

Load a skill from an arbitrary markdown file path.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ask/skills.rb', line 42

def load_file(path)
  path = File.expand_path(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.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ask/skills.rb', line 60

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