aircana 3.2.1 → 4.0.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec_status +168 -153
  3. data/CHANGELOG.md +55 -0
  4. data/CLAUDE.md +50 -39
  5. data/README.md +70 -76
  6. data/lib/aircana/cli/app.rb +16 -21
  7. data/lib/aircana/cli/commands/generate.rb +0 -12
  8. data/lib/aircana/cli/commands/kb.rb +590 -0
  9. data/lib/aircana/cli/help_formatter.rb +5 -4
  10. data/lib/aircana/configuration.rb +13 -28
  11. data/lib/aircana/contexts/confluence.rb +55 -24
  12. data/lib/aircana/contexts/confluence_content.rb +48 -5
  13. data/lib/aircana/contexts/local.rb +8 -9
  14. data/lib/aircana/contexts/manifest.rb +46 -34
  15. data/lib/aircana/contexts/web.rb +47 -17
  16. data/lib/aircana/generators/skills_generator.rb +194 -0
  17. data/lib/aircana/templates/skills/base_skill.erb +12 -0
  18. data/lib/aircana/version.rb +1 -1
  19. metadata +4 -18
  20. data/lib/aircana/cli/commands/agents.rb +0 -733
  21. data/lib/aircana/generators/agents_generator.rb +0 -79
  22. data/lib/aircana/templates/agents/base_agent.erb +0 -31
  23. data/lib/aircana/templates/agents/defaults/apply_feedback.erb +0 -91
  24. data/lib/aircana/templates/agents/defaults/executor.erb +0 -84
  25. data/lib/aircana/templates/agents/defaults/jira.erb +0 -45
  26. data/lib/aircana/templates/agents/defaults/planner.erb +0 -63
  27. data/lib/aircana/templates/agents/defaults/reviewer.erb +0 -94
  28. data/lib/aircana/templates/agents/defaults/sub-agent-coordinator.erb +0 -90
  29. data/lib/aircana/templates/hooks/refresh_agents.erb +0 -66
  30. data/lib/aircana/templates/hooks/sync_local_knowledge.erb +0 -86
  31. data/spec_target_1760656566_428/agents/test-agent/manifest.json +0 -16
  32. data/spec_target_1760656588_38/agents/test-agent/manifest.json +0 -16
  33. data/spec_target_1760656647_612/agents/test-agent/manifest.json +0 -16
  34. data/spec_target_1760656660_113/agents/test-agent/manifest.json +0 -16
  35. data/spec_target_1760656689_268/agents/test-agent/manifest.json +0 -16
  36. data/spec_target_1760656710_387/agents/test-agent/manifest.json +0 -16
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../generators"
4
+ require_relative "../contexts/manifest"
5
+
6
+ module Aircana
7
+ module Generators
8
+ # rubocop:disable Metrics/ClassLength
9
+ class SkillsGenerator < BaseGenerator
10
+ attr_reader :kb_name, :short_description, :skill_description, :knowledge_files
11
+
12
+ # rubocop:disable Metrics/ParameterLists
13
+ def initialize(kb_name:, short_description: nil, skill_description: nil, knowledge_files: [], file_in: nil,
14
+ file_out: nil)
15
+ @kb_name = kb_name
16
+ @short_description = short_description
17
+ @skill_description = skill_description || generate_skill_description
18
+ @knowledge_files = knowledge_files
19
+
20
+ super(
21
+ file_in: file_in || default_template_path,
22
+ file_out: file_out || default_output_path
23
+ )
24
+ end
25
+ # rubocop:enable Metrics/ParameterLists
26
+
27
+ # Generate SKILL.md based on manifest data
28
+ # rubocop:disable Metrics/MethodLength
29
+ def self.from_manifest(kb_name)
30
+ manifest = Contexts::Manifest.read_manifest(kb_name)
31
+ raise Error, "No manifest found for knowledge base '#{kb_name}'" unless manifest
32
+
33
+ knowledge_files = extract_knowledge_files_from_manifest(manifest)
34
+
35
+ # Warn if no knowledge files were found
36
+ if knowledge_files.empty?
37
+ Aircana.human_logger.warn "No knowledge files found for KB '#{kb_name}'. " \
38
+ "SKILL.md will be generated but will be empty. " \
39
+ "Run 'aircana kb refresh #{kb_name}' to fetch knowledge."
40
+ end
41
+
42
+ skill_description = generate_skill_description_from_manifest(manifest, kb_name)
43
+
44
+ new(
45
+ kb_name: kb_name,
46
+ skill_description: skill_description,
47
+ knowledge_files: knowledge_files
48
+ )
49
+ end
50
+ # rubocop:enable Metrics/MethodLength
51
+
52
+ # Class methods for manifest processing
53
+ def self.extract_knowledge_files_from_manifest(manifest)
54
+ kb_name = manifest["name"]
55
+
56
+ # If kb_dir exists, scan actual files on disk (preferred method)
57
+ if kb_name && Aircana.configuration.kb_knowledge_dir
58
+ kb_dir = Aircana.configuration.kb_path(kb_name)
59
+
60
+ return extract_files_from_disk(manifest, kb_dir) if Dir.exist?(kb_dir)
61
+ end
62
+
63
+ # Fallback: extract from manifest metadata (for tests or before files are created)
64
+ extract_files_from_manifest_metadata(manifest)
65
+ end
66
+
67
+ # rubocop:disable Metrics/MethodLength
68
+ def self.extract_files_from_disk(manifest, kb_dir)
69
+ actual_files = Dir.glob(File.join(kb_dir, "*.md"))
70
+ .reject { |f| File.basename(f) == "SKILL.md" }
71
+ .sort
72
+
73
+ # Build file list with summaries from manifest
74
+ actual_files.map do |filepath|
75
+ filename = File.basename(filepath)
76
+ summary = find_summary_for_file(manifest, filename)
77
+
78
+ {
79
+ summary: summary || File.basename(filename, ".md").tr("-", " ").capitalize,
80
+ filename: filename
81
+ }
82
+ end
83
+ end
84
+ # rubocop:enable Metrics/MethodLength
85
+
86
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
87
+ # rubocop:disable Metrics/PerceivedComplexity
88
+ def self.extract_files_from_manifest_metadata(manifest)
89
+ files = []
90
+
91
+ manifest["sources"]&.each do |source|
92
+ case source["type"]
93
+ when "confluence"
94
+ source["pages"]&.each do |page|
95
+ files << {
96
+ summary: page["summary"] || "Documentation",
97
+ filename: "#{sanitize_filename_from_id(page["id"])}.md"
98
+ }
99
+ end
100
+ when "web"
101
+ source["urls"]&.each do |url_entry|
102
+ files << {
103
+ summary: url_entry["summary"] || "Web resource",
104
+ filename: "#{sanitize_filename_from_url(url_entry["url"])}.md"
105
+ }
106
+ end
107
+ end
108
+ end
109
+
110
+ files
111
+ end
112
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
113
+ # rubocop:enable Metrics/PerceivedComplexity
114
+
115
+ # Find the summary for a given filename from the manifest
116
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
117
+ # rubocop:disable Metrics/PerceivedComplexity
118
+ def self.find_summary_for_file(manifest, filename)
119
+ manifest["sources"]&.each do |source|
120
+ case source["type"]
121
+ when "confluence"
122
+ source["pages"]&.each do |page|
123
+ return page["summary"] if filename.include?(page["id"])
124
+ end
125
+ when "web"
126
+ source["urls"]&.each do |url_entry|
127
+ sanitized_url_part = sanitize_filename_from_url(url_entry["url"])
128
+ return url_entry["summary"] if filename.include?(sanitized_url_part)
129
+ end
130
+ end
131
+ end
132
+
133
+ nil
134
+ end
135
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
136
+ # rubocop:enable Metrics/PerceivedComplexity
137
+
138
+ def self.generate_skill_description_from_manifest(manifest, kb_name)
139
+ # Generate a description optimized for Claude's skill discovery
140
+ source_count = manifest["sources"]&.size || 0
141
+ "Discover critical context for #{kb_name.split("-").join(" ")} from #{source_count} knowledge sources"
142
+ end
143
+
144
+ def self.sanitize_filename_from_id(page_id)
145
+ "page_#{page_id}"
146
+ end
147
+
148
+ def self.sanitize_filename_from_url(url)
149
+ # Extract meaningful name from URL
150
+ uri = URI.parse(url)
151
+ path_segments = uri.path.split("/").reject(&:empty?)
152
+
153
+ if path_segments.any?
154
+ path_segments.last.gsub(/[^a-z0-9\-_]/i, "-").gsub(/-+/, "-").downcase
155
+ else
156
+ uri.host.gsub(/[^a-z0-9\-_]/i, "-").gsub(/-+/, "-").downcase
157
+ end
158
+ rescue URI::InvalidURIError
159
+ "web_resource"
160
+ end
161
+ # rubocop:enable Metrics/ClassLength
162
+
163
+ protected
164
+
165
+ def locals
166
+ super.merge({
167
+ kb_name:,
168
+ skill_description:,
169
+ knowledge_files:
170
+ })
171
+ end
172
+
173
+ private
174
+
175
+ def default_template_path
176
+ File.join(File.dirname(__FILE__), "..", "templates", "skills", "base_skill.erb")
177
+ end
178
+
179
+ def default_output_path
180
+ File.join(Aircana.configuration.skills_dir, kb_name, "SKILL.md")
181
+ end
182
+
183
+ def generate_skill_description
184
+ return @skill_description if @skill_description
185
+
186
+ if @short_description
187
+ "Discover critical context for #{short_description}"
188
+ else
189
+ "Discover critical context for #{kb_name.split("-").join(" ")}"
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: Learn <%= kb_name.split("-").map(&:capitalize).join(" ") %>
3
+ description: <%= skill_description %>
4
+ ---
5
+
6
+ # Learn <%= kb_name.split("-").map(&:capitalize).join(" ") %>
7
+
8
+ ## Instructions
9
+ Choose a sub-topic most relevant to your current task:
10
+ <% knowledge_files.each do |file| %>
11
+ * <%= file[:summary] %>: [<%= file[:filename] %>](<%= file[:filename] %>)
12
+ <% end %>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aircana
4
- VERSION = "3.2.1"
4
+ VERSION = "4.0.0.rc2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aircana
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 4.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Weston Dransfield
@@ -127,7 +127,6 @@ files:
127
127
  - lib/aircana.rb
128
128
  - lib/aircana/cli.rb
129
129
  - lib/aircana/cli/app.rb
130
- - lib/aircana/cli/commands/agents.rb
131
130
  - lib/aircana/cli/commands/doctor.rb
132
131
  - lib/aircana/cli/commands/doctor_checks.rb
133
132
  - lib/aircana/cli/commands/doctor_helpers.rb
@@ -135,6 +134,7 @@ files:
135
134
  - lib/aircana/cli/commands/generate.rb
136
135
  - lib/aircana/cli/commands/hooks.rb
137
136
  - lib/aircana/cli/commands/init.rb
137
+ - lib/aircana/cli/commands/kb.rb
138
138
  - lib/aircana/cli/commands/plugin.rb
139
139
  - lib/aircana/cli/help_formatter.rb
140
140
  - lib/aircana/cli/shell_command.rb
@@ -150,7 +150,6 @@ files:
150
150
  - lib/aircana/contexts/web.rb
151
151
  - lib/aircana/fzf_helper.rb
152
152
  - lib/aircana/generators.rb
153
- - lib/aircana/generators/agents_generator.rb
154
153
  - lib/aircana/generators/apply_feedback_command_generator.rb
155
154
  - lib/aircana/generators/ask_expert_command_generator.rb
156
155
  - lib/aircana/generators/base_generator.rb
@@ -160,6 +159,7 @@ files:
160
159
  - lib/aircana/generators/plan_command_generator.rb
161
160
  - lib/aircana/generators/record_command_generator.rb
162
161
  - lib/aircana/generators/review_command_generator.rb
162
+ - lib/aircana/generators/skills_generator.rb
163
163
  - lib/aircana/hooks_manifest.rb
164
164
  - lib/aircana/human_logger.rb
165
165
  - lib/aircana/initializers.rb
@@ -167,13 +167,6 @@ files:
167
167
  - lib/aircana/plugin_manifest.rb
168
168
  - lib/aircana/progress_tracker.rb
169
169
  - lib/aircana/system_checker.rb
170
- - lib/aircana/templates/agents/base_agent.erb
171
- - lib/aircana/templates/agents/defaults/apply_feedback.erb
172
- - lib/aircana/templates/agents/defaults/executor.erb
173
- - lib/aircana/templates/agents/defaults/jira.erb
174
- - lib/aircana/templates/agents/defaults/planner.erb
175
- - lib/aircana/templates/agents/defaults/reviewer.erb
176
- - lib/aircana/templates/agents/defaults/sub-agent-coordinator.erb
177
170
  - lib/aircana/templates/commands/apply_feedback.erb
178
171
  - lib/aircana/templates/commands/ask_expert.erb
179
172
  - lib/aircana/templates/commands/execute.erb
@@ -184,20 +177,13 @@ files:
184
177
  - lib/aircana/templates/hooks/notification_sqs.erb
185
178
  - lib/aircana/templates/hooks/post_tool_use.erb
186
179
  - lib/aircana/templates/hooks/pre_tool_use.erb
187
- - lib/aircana/templates/hooks/refresh_agents.erb
188
180
  - lib/aircana/templates/hooks/rspec_test.erb
189
181
  - lib/aircana/templates/hooks/rubocop_pre_commit.erb
190
182
  - lib/aircana/templates/hooks/session_start.erb
191
- - lib/aircana/templates/hooks/sync_local_knowledge.erb
192
183
  - lib/aircana/templates/hooks/user_prompt_submit.erb
184
+ - lib/aircana/templates/skills/base_skill.erb
193
185
  - lib/aircana/version.rb
194
186
  - sig/aircana.rbs
195
- - spec_target_1760656566_428/agents/test-agent/manifest.json
196
- - spec_target_1760656588_38/agents/test-agent/manifest.json
197
- - spec_target_1760656647_612/agents/test-agent/manifest.json
198
- - spec_target_1760656660_113/agents/test-agent/manifest.json
199
- - spec_target_1760656689_268/agents/test-agent/manifest.json
200
- - spec_target_1760656710_387/agents/test-agent/manifest.json
201
187
  homepage: https://github.com/westonkd/aircana
202
188
  licenses:
203
189
  - MIT