Class: Pikuri::Skill::Catalog::Bundled
- Inherits:
-
Catalog
- Object
- Catalog
- Pikuri::Skill::Catalog::Bundled
- Defined in:
- lib/pikuri/skill/catalog.rb
Overview
On-disk catalog over a list of search bases (project root,
home dir, …). Under each base it scans .pikuri/skills (the
user's own), .claude/skills (Claude Code skills ride along)
and .agents/skills (PI's cross-harness convention), in that
order; missing subdirs are skipped.
Precedence
Bases left to right, subdirs in the order above; the first skill seen for a name wins, later ones dropped with a warning. Pass the project root first for "project beats global".
Validation
The Agent Skills standard is enforced leniently: a missing
description is the only hard failure (skill skipped). Name/dir
mismatch, oversized name/description, invalid name chars, a paths:
that is neither a string nor a list of them, and malformed YAML log a
warning and load anyway. A file with no frontmatter is skipped silently
(not meant as a skill). Note which way the paths: failure falls: a
value this class cannot read leaves the skill advertised, never hidden.
Trust
Bundled.new(search_bases: [
Pikuri::Bundle::Base.new(dir: project_root, trusted: repo_sources_are_mine),
Pikuri::Bundle::Base.new(dir: Dir.home)
])
Per-base Bundle::Base#trusted unions into one
#untrusted_level at scan time, because SkillTool declares its legs
once: a single skill from an unvouched base takes the whole catalog to
:hard. The union counts a skill at the point it wins its name, so
an untrusted base costs nothing when it is empty or when its skills all
lost a collision — a host may therefore name a base it knows nothing
about and still report :none for the user who turns out to have no
skills there.
A host that can rule out writes to a base may vouch for it without
asking anyone: bin/pikuri-code does this for Dir.home, since skill
roots ride in the workspace's readable: and never its writable:, so
nothing but the user's own hand puts a skill there.
Instance Attribute Summary collapse
-
#roots ⇒ Array<String>
readonly
Absolute paths of the existing skill directories this catalog covered, in scan order.
Instance Method Summary collapse
- #get(name) ⇒ Skill?
- #initialize(search_bases:) ⇒ Bundled constructor
- #list ⇒ Array<Skill>
-
#untrusted_level ⇒ Symbol
:nonewhen every skill this catalog stored came from atrustedbase, else:hard.
Constructor Details
#initialize(search_bases:) ⇒ Bundled
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/pikuri/skill/catalog.rb', line 176 def initialize(search_bases:) super() @roots = [] @skills = {} @untrusted = false search_bases.each do |entry| base = entry.is_a?(Bundle::Base) ? entry : Bundle::Base.new(dir: entry) SKILL_SUBDIRS.each do |sub| root = File.join(base.dir.to_s, sub) next unless File.directory?(root) @roots << root scan_root(root, trusted: base.trusted) end end @roots.freeze @skills.freeze @list = @skills.values.freeze freeze end |
Instance Attribute Details
#roots ⇒ Array<String> (readonly)
Returns absolute paths of the existing skill directories this catalog covered, in scan order.
212 213 214 |
# File 'lib/pikuri/skill/catalog.rb', line 212 def roots @roots end |
Instance Method Details
#get(name) ⇒ Skill?
206 207 208 |
# File 'lib/pikuri/skill/catalog.rb', line 206 def get(name) @skills[name] end |
#untrusted_level ⇒ Symbol
Returns :none when every skill this catalog stored came
from a trusted base, else :hard.
216 |
# File 'lib/pikuri/skill/catalog.rb', line 216 def untrusted_level = @untrusted ? :hard : :none |