Class: Aircana::Generators::SkillsGenerator
- Inherits:
-
BaseGenerator
- Object
- BaseGenerator
- Aircana::Generators::SkillsGenerator
- Defined in:
- lib/aircana/generators/skills_generator.rb
Overview
rubocop:disable Metrics/ClassLength
Instance Attribute Summary collapse
-
#kb_name ⇒ Object
readonly
Returns the value of attribute kb_name.
-
#knowledge_files ⇒ Object
readonly
Returns the value of attribute knowledge_files.
-
#short_description ⇒ Object
readonly
Returns the value of attribute short_description.
-
#skill_description ⇒ Object
readonly
Returns the value of attribute skill_description.
Attributes inherited from BaseGenerator
Class Method Summary collapse
-
.extract_files_from_disk(manifest, kb_dir) ⇒ Object
rubocop:disable Metrics/MethodLength.
-
.extract_files_from_manifest_metadata(manifest) ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength rubocop:disable Metrics/PerceivedComplexity.
-
.extract_knowledge_files_from_manifest(manifest) ⇒ Object
Class methods for manifest processing.
-
.find_summary_for_file(manifest, filename) ⇒ Object
Find the summary for a given filename from the manifest rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength rubocop:disable Metrics/PerceivedComplexity.
-
.from_manifest(kb_name) ⇒ Object
Generate SKILL.md based on manifest data rubocop:disable Metrics/MethodLength.
- .generate_skill_description_from_manifest(manifest, kb_name) ⇒ Object
-
.sanitize_filename(title) ⇒ Object
rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength rubocop:enable Metrics/PerceivedComplexity.
- .sanitize_filename_from_id(page_id) ⇒ Object
- .sanitize_filename_from_url(url) ⇒ Object
Instance Method Summary collapse
-
#initialize(kb_name:, short_description: nil, skill_description: nil, knowledge_files: [], file_in: nil, file_out: nil) ⇒ SkillsGenerator
constructor
rubocop:disable Metrics/ParameterLists.
Methods inherited from BaseGenerator
Constructor Details
#initialize(kb_name:, short_description: nil, skill_description: nil, knowledge_files: [], file_in: nil, file_out: nil) ⇒ SkillsGenerator
rubocop:disable Metrics/ParameterLists
13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/aircana/generators/skills_generator.rb', line 13 def initialize(kb_name:, short_description: nil, skill_description: nil, knowledge_files: [], file_in: nil, file_out: nil) @kb_name = kb_name @short_description = short_description @skill_description = skill_description || generate_skill_description @knowledge_files = knowledge_files super( file_in: file_in || default_template_path, file_out: file_out || default_output_path ) end |
Instance Attribute Details
#kb_name ⇒ Object (readonly)
Returns the value of attribute kb_name.
10 11 12 |
# File 'lib/aircana/generators/skills_generator.rb', line 10 def kb_name @kb_name end |
#knowledge_files ⇒ Object (readonly)
Returns the value of attribute knowledge_files.
10 11 12 |
# File 'lib/aircana/generators/skills_generator.rb', line 10 def knowledge_files @knowledge_files end |
#short_description ⇒ Object (readonly)
Returns the value of attribute short_description.
10 11 12 |
# File 'lib/aircana/generators/skills_generator.rb', line 10 def short_description @short_description end |
#skill_description ⇒ Object (readonly)
Returns the value of attribute skill_description.
10 11 12 |
# File 'lib/aircana/generators/skills_generator.rb', line 10 def skill_description @skill_description end |
Class Method Details
.extract_files_from_disk(manifest, kb_dir) ⇒ Object
rubocop:disable Metrics/MethodLength
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/aircana/generators/skills_generator.rb', line 68 def self.extract_files_from_disk(manifest, kb_dir) actual_files = Dir.glob(File.join(kb_dir, "*.md")) .reject { |f| File.basename(f) == "SKILL.md" } .sort # Build file list with summaries from manifest actual_files.map do |filepath| filename = File.basename(filepath) summary = find_summary_for_file(manifest, filename) { summary: summary || File.basename(filename, ".md").tr("-", " ").capitalize, filename: filename } end end |
.extract_files_from_manifest_metadata(manifest) ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength rubocop:disable Metrics/PerceivedComplexity
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/aircana/generators/skills_generator.rb', line 88 def self.(manifest) files = [] manifest["sources"]&.each do |source| case source["type"] when "confluence" source["pages"]&.each do |page| files << { summary: page["summary"] || "Documentation", filename: "#{sanitize_filename_from_id(page["id"])}.md" } end when "web" source["urls"]&.each do |url_entry| files << { summary: url_entry["summary"] || "Web resource", filename: "#{sanitize_filename_from_url(url_entry["url"])}.md" } end end end files end |
.extract_knowledge_files_from_manifest(manifest) ⇒ Object
Class methods for manifest processing
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/aircana/generators/skills_generator.rb', line 53 def self.extract_knowledge_files_from_manifest(manifest) kb_name = manifest["name"] # If kb_dir exists, scan actual files on disk (preferred method) if kb_name && Aircana.configuration.kb_knowledge_dir kb_dir = Aircana.configuration.kb_path(kb_name) return extract_files_from_disk(manifest, kb_dir) if Dir.exist?(kb_dir) end # Fallback: extract from manifest metadata (for tests or before files are created) (manifest) end |
.find_summary_for_file(manifest, filename) ⇒ Object
Find the summary for a given filename from the manifest rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength rubocop:disable Metrics/PerceivedComplexity
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/aircana/generators/skills_generator.rb', line 118 def self.find_summary_for_file(manifest, filename) manifest["sources"]&.each do |source| case source["type"] when "confluence" source["pages"]&.each do |page| # Match by page ID (for old manifests) or by sanitized title (for new manifests) return page["summary"] if filename.include?(page["id"]) # Try matching by sanitized title if available if page["title"] sanitized_title = sanitize_filename(page["title"]) return page["summary"] if filename.include?(sanitized_title) end end when "web" source["urls"]&.each do |url_entry| sanitized_url_part = sanitize_filename_from_url(url_entry["url"]) return url_entry["summary"] if filename.include?(sanitized_url_part) end end end nil end |
.from_manifest(kb_name) ⇒ Object
Generate SKILL.md based on manifest data rubocop:disable Metrics/MethodLength
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/aircana/generators/skills_generator.rb', line 29 def self.from_manifest(kb_name) manifest = Contexts::Manifest.read_manifest(kb_name) raise Error, "No manifest found for knowledge base '#{kb_name}'" unless manifest knowledge_files = extract_knowledge_files_from_manifest(manifest) # Warn if no knowledge files were found if knowledge_files.empty? Aircana.human_logger.warn "No knowledge files found for KB '#{kb_name}'. " \ "SKILL.md will be generated but will be empty. " \ "Run 'aircana kb refresh #{kb_name}' to fetch knowledge." end skill_description = generate_skill_description_from_manifest(manifest, kb_name) new( kb_name: kb_name, skill_description: skill_description, knowledge_files: knowledge_files ) end |
.generate_skill_description_from_manifest(manifest, kb_name) ⇒ Object
159 160 161 162 163 |
# File 'lib/aircana/generators/skills_generator.rb', line 159 def self.generate_skill_description_from_manifest(manifest, kb_name) # Generate a description optimized for Claude's skill discovery source_count = manifest["sources"]&.size || 0 "Discover critical context for #{kb_name.split("-").join(" ")} from #{source_count} knowledge sources" end |
.sanitize_filename(title) ⇒ Object
rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength rubocop:enable Metrics/PerceivedComplexity
145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/aircana/generators/skills_generator.rb', line 145 def self.sanitize_filename(title) # Match the sanitization logic in Local#sanitize_filename sanitized = title.strip .gsub(%r{[<>:"/\\|?*]}, "-") .gsub(/\s+/, "-") .gsub(/-+/, "-") .gsub(/^-|-$/, "") sanitized = "untitled" if sanitized.empty? sanitized = sanitized[0, 200] if sanitized.length > 200 sanitized end |
.sanitize_filename_from_id(page_id) ⇒ Object
165 166 167 |
# File 'lib/aircana/generators/skills_generator.rb', line 165 def self.sanitize_filename_from_id(page_id) "page_#{page_id}" end |
.sanitize_filename_from_url(url) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/aircana/generators/skills_generator.rb', line 169 def self.sanitize_filename_from_url(url) # Extract meaningful name from URL uri = URI.parse(url) path_segments = uri.path.split("/").reject(&:empty?) if path_segments.any? path_segments.last.gsub(/[^a-z0-9\-_]/i, "-").gsub(/-+/, "-").downcase else uri.host.gsub(/[^a-z0-9\-_]/i, "-").gsub(/-+/, "-").downcase end rescue URI::InvalidURIError "web_resource" end |