Module: Gem::Skill::Linker

Defined in:
lib/gem/skill/linker.rb

Overview

Manages .claude/skills/ symlinks in a project, pointing to ~/.gem/skills cache.

Class Method Summary collapse

Class Method Details

Raises:



12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/gem/skill/linker.rb', line 12

def self.link(gem_name, version, project_root = Dir.pwd)
  target = Cache.skill_path(gem_name, version)
  raise Error, "No cached skill for #{gem_name} #{version}. Run: gem skill install #{gem_name}" \
    unless File.exist?(target)

  dir = skills_dir(project_root)
  FileUtils.mkdir_p(dir)

  link_path = File.join(dir, "#{gem_name}.md")
  File.unlink(link_path) if File.symlink?(link_path)
  File.symlink(target, link_path)
end

.linked_gems(project_root = Dir.pwd) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/gem/skill/linker.rb', line 30

def self.linked_gems(project_root = Dir.pwd)
  dir = skills_dir(project_root)
  return [] unless Dir.exist?(dir)

  Dir.glob(File.join(dir, "*.md")).filter_map do |path|
    next unless File.symlink?(path)

    gem_name = File.basename(path, ".md")
    target   = File.readlink(path)
    version  = target.match(%r{/([^/]+)/SKILL\.md$})&.captures&.first
    { gem_name: gem_name, version: version, target: target, valid: File.exist?(target) }
  end
end


44
45
46
47
48
# File 'lib/gem/skill/linker.rb', line 44

def self.prune_dead_links(project_root = Dir.pwd)
  linked_gems(project_root)
    .reject { |entry| entry[:valid] }
    .each   { |entry| unlink(entry[:gem_name], project_root) }
end

.skills_dir(project_root = Dir.pwd) ⇒ Object



8
9
10
# File 'lib/gem/skill/linker.rb', line 8

def self.skills_dir(project_root = Dir.pwd)
  File.join(project_root, ".claude", "skills")
end


25
26
27
28
# File 'lib/gem/skill/linker.rb', line 25

def self.unlink(gem_name, project_root = Dir.pwd)
  link_path = File.join(skills_dir(project_root), "#{gem_name}.md")
  File.unlink(link_path) if File.symlink?(link_path)
end