Class: Generators::Avo::SkillsGenerator

Inherits:
BaseGenerator
  • Object
show all
Defined in:
lib/generators/avo/skills_generator.rb

Overview

Installs the Avo skills loader into the host app.

Only the loader is copied — the skills themselves stay inside the gem, which is the whole point: a copied skill tree drifts from the locked Avo version with nothing to refresh it. Re-running this generator refreshes the loader.

Deliberately its own namespace rather than part of avo:install, so it does not change behavior for apps that already ran the installer.

Constant Summary collapse

TARGETS =

Claude Code scans .claude/skills; .agents/skills is the cross-agent convention; .cursor/skills is what Cursor reads. Installing to all three is why the loader is copied rather than symlinked — a symlink into a version-named gem directory breaks on the next bundle update.

{
  "claude" => ".claude/skills/avo",
  "agents" => ".agents/skills/avo",
  "cursor" => ".cursor/skills/avo"
}.freeze
LEGACY_ROOTS =

Where a pre-gem install of avo-hq/skills materialized its catalog. npx skills add writes project-locally, so the stale copies land in the same directories this generator installs into.

[
  ".claude/skills",
  ".agents/skills",
  ".cursor/skills"
].freeze
GLOBAL_LEGACY_ROOT =

Checked, reported, and never deleted. This directory is shared by every project on the machine — a skill here may be deliberately installed for a different app, and a generator run inside one project has no business removing it. The user gets the command instead.

"~/.claude/skills"

Instance Method Summary collapse

Methods inherited from BaseGenerator

#initialize

Constructor Details

This class inherits a constructor from Generators::Avo::BaseGenerator

Instance Method Details

#clean_legacy_skillsObject

A leftover catalog sits in the same scan directories as the loader and can shadow it, silently serving instructions written for a different Avo version — which is the whole problem this feature removes. Install time is the right place to catch it: it is the one moment we know the user is present and thinking about skills.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/generators/avo/skills_generator.rb', line 63

def clean_legacy_skills
  leftovers = legacy_skill_dirs
  global = global_legacy_skill_dirs
  return if leftovers.empty? && global.empty?

  if leftovers.any?
    say "\nFound #{pluralize_skills(leftovers.length)} in this project from a previous avo-hq/skills install:"
    by_directory(leftovers).each { |dir, count| say "  #{dir}#{" " * padding(dir)}#{count}", :yellow }
    say "These are not version-pinned and can shadow the skills that ship with your Avo gem."

    if remove_legacy?
      by_directory(leftovers).each do |dir, count|
        leftovers.select { |path| display_dir(path) == dir }.each { |path| FileUtils.rm_rf(path) }
        say_status :remove, "#{dir} (#{pluralize_skills(count)})", :red
      end
    else
      report_kept(leftovers)
    end
  end

  report_global(global) if global.any?
  say "\nIf you installed the Claude Code plugin, remove it with: /plugin uninstall avo-skills"
end

#install_loaderObject



51
52
53
54
55
56
# File 'lib/generators/avo/skills_generator.rb', line 51

def install_loader
  destinations.each do |destination|
    copy_file "skills/SKILL.md", File.join(destination, "SKILL.md")
    install_resolver File.join(destination, "scripts", "avo-skills-resolve")
  end
end