aircana 1.5.0 → 2.0.0.rc1

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.
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: sub-agent-coordinator
3
+ description: Analyzes questions and coordinates multiple sub-agents to provide comprehensive expert answers by identifying relevant domains and orchestrating parallel consultations
4
+ model: inherit
5
+ color: purple
6
+ ---
7
+
8
+ <%= helpers.model_instructions("You are a Sub-Agent Coordinator responsible for analyzing questions and orchestrating responses from multiple specialized sub-agents to provide comprehensive, expert-level answers.
9
+
10
+ CORE RESPONSIBILITIES:
11
+
12
+ 1. QUESTION ANALYSIS
13
+ - Parse and understand the context, domain, and scope of questions
14
+ - Identify key technical areas, frameworks, and expertise domains involved
15
+ - Determine the complexity level and breadth of knowledge required
16
+
17
+ 2. AGENT DISCOVERY & SELECTION
18
+ - Scan available Claude Code sub-agents in the file system
19
+ - Evaluate each agent's relevance to the question based on their descriptions
20
+ - Prioritize agents most likely to provide valuable domain-specific insights
21
+ - Consider both direct expertise and adjacent knowledge areas
22
+
23
+ 3. COORDINATION STRATEGY
24
+ - Determine optimal consultation approach (parallel vs sequential)
25
+ - Formulate specific, targeted questions for each relevant sub-agent
26
+ - Ensure comprehensive coverage while avoiding redundancy
27
+ - Plan response synthesis methodology
28
+
29
+ 4. RESPONSE ORCHESTRATION
30
+ - Present clear rationale for agent selection decisions
31
+ - Provide specific guidance for parallel Task tool invocations
32
+ - Suggest follow-up questions if initial responses need clarification
33
+ - Coordinate timing and dependencies between agent consultations
34
+
35
+ WORKFLOW FOR QUESTION HANDLING:
36
+
37
+ STEP 1: Question Assessment
38
+ - Analyze the question's technical domains and scope
39
+ - Identify primary and secondary areas of expertise needed
40
+ - Determine if the question requires architectural, implementation, or domain-specific knowledge
41
+
42
+ STEP 2: Agent Identification
43
+ - List all available sub-agents by scanning the Claude Code configuration
44
+ - Score relevance of each agent (High/Medium/Low) with brief rationale
45
+ - Select 2-5 most relevant agents to avoid information overload
46
+ - Document why specific agents were chosen or excluded
47
+
48
+ STEP 3: Consultation Planning
49
+ - For each selected agent, craft a specific question or prompt
50
+ - Ensure questions leverage each agent's unique expertise
51
+ - Plan for parallel execution when agents have independent domains
52
+ - Identify any sequential dependencies between agent consultations
53
+
54
+ STEP 4: Execution Guidance
55
+ - Provide clear instructions for using Task tool with appropriate subagent_types
56
+ - Specify whether consultations should be parallel or sequential
57
+ - Include fallback plans if certain agents are unavailable
58
+ - Suggest timeout considerations for complex queries
59
+
60
+ STEP 5: Response Synthesis Strategy
61
+ - Outline how responses from different agents should be integrated
62
+ - Identify potential conflicts or contradictions to watch for
63
+ - Suggest approaches for reconciling different expert perspectives
64
+ - Plan for follow-up questions based on initial responses
65
+
66
+ IMPORTANT GUIDELINES:
67
+ - Always explain your reasoning for agent selection decisions
68
+ - Focus on actionable coordination rather than attempting to answer the question yourself
69
+ - Leverage the collective expertise rather than relying on single sources
70
+ - Provide clear, executable instructions for the coordination process
71
+ - Consider the user's context and technical level when planning consultations
72
+
73
+ EXAMPLE OUTPUT FORMAT:
74
+ ```
75
+ Question Analysis: [Brief analysis of domains and expertise needed]
76
+
77
+ Selected Agents:
78
+ 1. [Agent Name] (High relevance) - [Specific reason and question to ask]
79
+ 2. [Agent Name] (Medium relevance) - [Specific reason and question to ask]
80
+
81
+ Consultation Strategy:
82
+ - Execute agents 1 and 2 in parallel using Task tool
83
+ - Follow up with [specific approach] based on responses
84
+ - Synthesize responses focusing on [key integration points]
85
+
86
+ Execution Instructions:
87
+ [Specific Task tool invocations and coordination steps]
88
+ ```", important: true) %>
89
+
90
+ Remember: Your role is coordination and orchestration, not direct problem-solving. Your value comes from leveraging the collective knowledge of specialized agents effectively.
@@ -0,0 +1,44 @@
1
+ <%= helpers.model_instructions(
2
+ "You are coordinating expert consultation to answer a question by leveraging multiple specialized sub-agents. Follow this precise workflow:
3
+
4
+ STEP 1: QUESTION VALIDATION
5
+ #{$ARGUMENTS.nil? || $ARGUMENTS.empty? ? 'Ask the user: \"What is your question?\" and wait for their response before proceeding.' : "Question to analyze: \"#{$ARGUMENTS}\""}
6
+
7
+ STEP 2: COORDINATION PHASE
8
+ Use the Task tool with subagent_type 'sub-agent-coordinator' to analyze the question and identify relevant sub-agents. Provide the coordinator with the complete question context.
9
+
10
+ STEP 3: PARALLEL EXPERT CONSULTATION
11
+ Based on the coordinator's recommendations, use the Task tool to consult each identified relevant sub-agent in parallel. For each agent:
12
+ - Use the appropriate subagent_type for each recommended agent
13
+ - Provide the original question plus any agent-specific context the coordinator suggested
14
+ - Execute multiple Task tool calls in a single message for parallel processing
15
+
16
+ STEP 4: SYNTHESIS AND RESPONSE
17
+ After receiving responses from all consulted agents:
18
+ - Analyze and synthesize the expert feedback
19
+ - Identify common themes, conflicting viewpoints, and complementary insights
20
+ - Provide a comprehensive answer that leverages the collective expertise
21
+ - Cite which agents contributed specific insights where relevant
22
+ - Note any areas where experts disagreed and provide your assessment
23
+
24
+ STEP 5: FOLLOW-UP GUIDANCE
25
+ If the question requires further clarification or the expert responses suggest additional considerations:
26
+ - Suggest specific follow-up questions
27
+ - Recommend additional agents to consult if needed
28
+ - Provide guidance on next steps based on the expert consensus
29
+
30
+ IMPORTANT EXECUTION NOTES:
31
+ - Always start with the sub-agent-coordinator for proper agent selection
32
+ - Use parallel Task tool execution when consulting multiple agents (single message with multiple tool calls)
33
+ - Ensure each agent receives context appropriate to their expertise domain
34
+ - Synthesize responses rather than simply concatenating them
35
+ - Maintain focus on providing actionable, comprehensive answers
36
+
37
+ EXAMPLE PARALLEL EXECUTION:
38
+ If coordinator recommends agents A, B, and C, send one message with three Task tool calls:
39
+ 1. Task(subagent_type='agent-A', prompt='[question + A-specific context]')
40
+ 2. Task(subagent_type='agent-B', prompt='[question + B-specific context]')
41
+ 3. Task(subagent_type='agent-C', prompt='[question + C-specific context]')
42
+
43
+ This approach ensures you leverage the full expertise available while maintaining efficient coordination."
44
+ ) %>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aircana
4
- VERSION = "1.5.0"
4
+ VERSION = "2.0.0.rc1"
5
5
  end
data/lib/aircana.rb CHANGED
@@ -37,8 +37,6 @@ module Aircana
37
37
  def initialize!
38
38
  return if @initialized
39
39
 
40
- create_dir_if_needed(configuration.relevant_project_files_dir)
41
-
42
40
  @initialized = true
43
41
  end
44
42
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aircana
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 2.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Weston Dransfield
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-09-28 00:00:00.000000000 Z
10
+ date: 2025-09-30 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: httparty
@@ -118,15 +118,11 @@ files:
118
118
  - lib/aircana.rb
119
119
  - lib/aircana/cli.rb
120
120
  - lib/aircana/cli/app.rb
121
- - lib/aircana/cli/commands/add_directory.rb
122
- - lib/aircana/cli/commands/add_files.rb
123
121
  - lib/aircana/cli/commands/agents.rb
124
- - lib/aircana/cli/commands/clear_files.rb
125
122
  - lib/aircana/cli/commands/doctor.rb
126
123
  - lib/aircana/cli/commands/doctor_checks.rb
127
124
  - lib/aircana/cli/commands/doctor_helpers.rb
128
125
  - lib/aircana/cli/commands/dump_context.rb
129
- - lib/aircana/cli/commands/files.rb
130
126
  - lib/aircana/cli/commands/generate.rb
131
127
  - lib/aircana/cli/commands/hooks.rb
132
128
  - lib/aircana/cli/commands/install.rb
@@ -142,18 +138,16 @@ files:
142
138
  - lib/aircana/contexts/confluence_setup.rb
143
139
  - lib/aircana/contexts/local.rb
144
140
  - lib/aircana/contexts/manifest.rb
145
- - lib/aircana/contexts/relevant_files.rb
146
141
  - lib/aircana/contexts/web.rb
147
142
  - lib/aircana/fzf_helper.rb
148
143
  - lib/aircana/generators.rb
149
144
  - lib/aircana/generators/agents_generator.rb
145
+ - lib/aircana/generators/ask_expert_command_generator.rb
150
146
  - lib/aircana/generators/base_generator.rb
151
147
  - lib/aircana/generators/helpers.rb
152
148
  - lib/aircana/generators/hooks_generator.rb
153
149
  - lib/aircana/generators/plan_command_generator.rb
154
150
  - lib/aircana/generators/project_config_generator.rb
155
- - lib/aircana/generators/relevant_files_command_generator.rb
156
- - lib/aircana/generators/relevant_files_verbose_results_generator.rb
157
151
  - lib/aircana/generators/write_plan_command_generator.rb
158
152
  - lib/aircana/human_logger.rb
159
153
  - lib/aircana/initializers.rb
@@ -164,7 +158,8 @@ files:
164
158
  - lib/aircana/templates/agents/base_agent.erb
165
159
  - lib/aircana/templates/agents/defaults/jira.erb
166
160
  - lib/aircana/templates/agents/defaults/planner.erb
167
- - lib/aircana/templates/commands/add_relevant_files.erb
161
+ - lib/aircana/templates/agents/defaults/sub-agent-coordinator.erb
162
+ - lib/aircana/templates/commands/ask_expert.erb
168
163
  - lib/aircana/templates/commands/plan.erb
169
164
  - lib/aircana/templates/commands/write_plan.erb
170
165
  - lib/aircana/templates/hooks/bundle_install.erb
@@ -175,7 +170,6 @@ files:
175
170
  - lib/aircana/templates/hooks/rubocop_pre_commit.erb
176
171
  - lib/aircana/templates/hooks/session_start.erb
177
172
  - lib/aircana/templates/hooks/user_prompt_submit.erb
178
- - lib/aircana/templates/relevant_files_verbose_results.erb
179
173
  - lib/aircana/version.rb
180
174
  - sig/aircana.rbs
181
175
  homepage: https://github.com/westonkd/aircana
@@ -1,148 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "tty-prompt"
4
- require_relative "../../contexts/relevant_files"
5
-
6
- module Aircana
7
- module CLI
8
- module AddDirectory
9
- class << self
10
- def run(directory_path)
11
- return unless directory_valid?(directory_path)
12
-
13
- selected_files = collect_files_recursively(directory_path)
14
- return log_no_files_found(directory_path) if selected_files.empty?
15
-
16
- return unless confirm_large_operation?(selected_files.size, directory_path)
17
-
18
- process_files(directory_path, selected_files)
19
- end
20
-
21
- private
22
-
23
- def directory_valid?(directory_path)
24
- unless File.directory?(directory_path)
25
- Aircana.human_logger.error "Directory not found: #{directory_path}"
26
- return false
27
- end
28
-
29
- unless File.readable?(directory_path)
30
- Aircana.human_logger.error "Directory not readable: #{directory_path}"
31
- return false
32
- end
33
-
34
- true
35
- end
36
-
37
- def log_no_files_found(directory_path)
38
- Aircana.human_logger.info "No files found in directory: #{directory_path}"
39
- end
40
-
41
- def confirm_large_operation?(file_count, directory_path)
42
- return true if file_count <= 50
43
-
44
- show_large_operation_warning(file_count, directory_path)
45
- TTY::Prompt.new.yes?("Continue with adding #{file_count} files?")
46
- end
47
-
48
- def show_large_operation_warning(file_count, directory_path)
49
- estimated_size = estimate_total_size(directory_path, file_count)
50
- Aircana.human_logger.warn "Large directory operation detected:"
51
- Aircana.human_logger.info " Directory: #{directory_path}"
52
- Aircana.human_logger.info " Files: #{file_count}"
53
- Aircana.human_logger.info " Estimated size: #{estimated_size}"
54
- Aircana.human_logger.warn " This may result in high token usage with Claude"
55
- end
56
-
57
- def estimate_total_size(directory_path, file_count)
58
- sample_files = get_sample_files(directory_path, file_count)
59
- return "Unknown" if sample_files.empty?
60
-
61
- total_bytes = calculate_sample_size(sample_files)
62
- estimated_total = extrapolate_total_size(total_bytes, sample_files.size, file_count)
63
- format_file_size(estimated_total)
64
- end
65
-
66
- def get_sample_files(directory_path, file_count)
67
- Dir.glob(File.join(directory_path, "**", "*"))
68
- .reject { |f| File.directory?(f) }
69
- .sample([file_count, 10].min)
70
- end
71
-
72
- def calculate_sample_size(sample_files)
73
- sample_files.sum do |f|
74
- File.size(f)
75
- rescue StandardError
76
- 0
77
- end
78
- end
79
-
80
- def extrapolate_total_size(total_bytes, sample_size, file_count)
81
- avg_size = total_bytes / sample_size.to_f
82
- (avg_size * file_count).to_i
83
- end
84
-
85
- def format_file_size(bytes)
86
- units = %w[B KB MB GB]
87
- size = bytes.to_f
88
- unit_index = 0
89
-
90
- while size >= 1024 && unit_index < units.length - 1
91
- size /= 1024
92
- unit_index += 1
93
- end
94
-
95
- "#{size.round(1)} #{units[unit_index]}"
96
- end
97
-
98
- def process_files(directory_path, selected_files)
99
- file_count = selected_files.length
100
- Aircana.human_logger.info "Found #{file_count} files in directory: #{directory_path}"
101
-
102
- ProgressTracker.with_spinner("Adding #{file_count} files to context") do
103
- Contexts::RelevantFiles.add(selected_files)
104
- end
105
-
106
- Aircana.human_logger.success "Successfully added #{file_count} files from directory"
107
- end
108
-
109
- def log_token_warning(file_count)
110
- Aircana.human_logger.warn "Large number of files (#{file_count}) may result in high token usage"
111
- end
112
-
113
- def collect_files_recursively(directory_path)
114
- Dir.glob(File.join(directory_path, "**", "*"), File::FNM_DOTMATCH)
115
- .reject { |path| File.directory?(path) }
116
- .reject { |path| should_ignore_file?(path) }
117
- end
118
-
119
- def should_ignore_file?(file_path)
120
- ignore_patterns.any? { |pattern| file_path.match?(pattern) }
121
- end
122
-
123
- def ignore_patterns
124
- directory_patterns + file_patterns
125
- end
126
-
127
- def directory_patterns
128
- [
129
- %r{/\.git/}, %r{/node_modules/}, %r{/\.vscode/}, %r{/\.idea/},
130
- %r{/coverage/}, %r{/dist/}, %r{/build/}, %r{/tmp/}, %r{/vendor/},
131
- %r{/\.bundle/}, %r{/\.rvm/}, %r{/\.rbenv/}
132
- ]
133
- end
134
-
135
- def file_patterns
136
- [
137
- %r{/\.DS_Store$}, %r{/log/.*\.log$},
138
- /\.(jpg|jpeg|png|gif|bmp|tiff|svg|ico|webp)$/i,
139
- /\.(mp4|avi|mkv|mov|wmv|flv|webm)$/i,
140
- /\.(mp3|wav|flac|aac|ogg)$/i,
141
- /\.(zip|tar|gz|rar|7z|bz2)$/i,
142
- /\.(exe|dll|so|dylib)$/i
143
- ]
144
- end
145
- end
146
- end
147
- end
148
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../shell_command"
4
- require_relative "../../contexts/relevant_files"
5
-
6
- module Aircana
7
- module CLI
8
- module AddFiles
9
- class << self
10
- def run
11
- selected_files = FzfHelper.select_files_interactively(
12
- header: "Select files for Claude context (Ctrl+A: select all, ?: toggle preview)"
13
- )
14
-
15
- if selected_files.empty?
16
- Aircana.human_logger.info "No files selected. Exiting."
17
- return
18
- end
19
-
20
- Aircana.human_logger.success "Selected #{selected_files.size} files for context"
21
- Contexts::RelevantFiles.add(selected_files)
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../shell_command"
4
- require_relative "../../contexts/relevant_files"
5
-
6
- module Aircana
7
- module CLI
8
- module ClearFiles
9
- class << self
10
- def run
11
- Contexts::RelevantFiles.remove_all
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "add_files"
4
- require_relative "add_directory"
5
- require_relative "clear_files"
6
- require_relative "../../contexts/relevant_files"
7
-
8
- module Aircana
9
- module CLI
10
- module Files
11
- class << self
12
- def add
13
- AddFiles.run
14
- end
15
-
16
- def add_dir(directory_path)
17
- AddDirectory.run(directory_path)
18
- end
19
-
20
- def clear
21
- ClearFiles.run
22
- end
23
-
24
- def list
25
- relevant_files_dir = Aircana.configuration.relevant_project_files_dir
26
- return print_no_directory_message unless Dir.exist?(relevant_files_dir)
27
-
28
- files = get_tracked_files(relevant_files_dir)
29
- return print_no_files_message if files.empty?
30
-
31
- print_files_list(files)
32
- end
33
-
34
- private
35
-
36
- def print_no_directory_message
37
- Aircana.human_logger.info(
38
- "No relevant files directory found. Use 'aircana files add' to start tracking files."
39
- )
40
- end
41
-
42
- def print_no_files_message
43
- Aircana.human_logger.info("No relevant files currently tracked.")
44
- end
45
-
46
- def get_tracked_files(relevant_files_dir)
47
- Dir.glob("#{relevant_files_dir}/*").map do |link|
48
- File.readlink(link)
49
- rescue StandardError
50
- link
51
- end
52
- end
53
-
54
- def print_files_list(files)
55
- Aircana.human_logger.info("Current relevant files:")
56
- files.each_with_index do |file, index|
57
- relative_path = file.start_with?(Dir.pwd) ? file.gsub("#{Dir.pwd}/", "") : file
58
- Aircana.human_logger.info(" #{index + 1}. #{relative_path}")
59
- end
60
- Aircana.human_logger.info("\nTotal: #{files.length} files")
61
- end
62
- end
63
- end
64
- end
65
- end
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Aircana
4
- module Contexts
5
- class RelevantFiles
6
- class << self
7
- # TODO: Honor the provided verbose flag
8
- def print(_verbose: false)
9
- verbose_generator(default_stream: true).generate
10
- end
11
-
12
- def add(files)
13
- files = Array(files)
14
-
15
- return if files.empty?
16
-
17
- Aircana.create_dir_if_needed(Aircana.configuration.relevant_project_files_dir)
18
-
19
- files.each do |file|
20
- absolute_file_path = File.expand_path(file)
21
- link_path = "#{Aircana.configuration.relevant_project_files_dir}/#{File.basename(file)}"
22
-
23
- FileUtils.rm_f(link_path)
24
- File.symlink(absolute_file_path, link_path)
25
- end
26
-
27
- rewrite_verbose_file
28
- end
29
-
30
- def remove(files)
31
- files = Array(files)
32
-
33
- return if files.empty?
34
-
35
- Aircana.create_dir_if_needed(Aircana.configuration.relevant_project_files_dir)
36
-
37
- files.each do |file|
38
- link_path = "#{Aircana.configuration.relevant_project_files_dir}/#{File.basename(file)}"
39
- FileUtils.rm_f(link_path)
40
- end
41
-
42
- rewrite_verbose_file
43
- end
44
-
45
- def remove_all
46
- return unless directory_exists?
47
-
48
- Dir.glob("#{Aircana.configuration.relevant_project_files_dir}/*").each do |file|
49
- FileUtils.rm_f(file)
50
- end
51
-
52
- return unless Dir.empty?(Aircana.configuration.relevant_project_files_dir)
53
-
54
- Dir.rmdir(Aircana.configuration.relevant_project_files_dir)
55
- end
56
-
57
- private
58
-
59
- def rewrite_verbose_file
60
- verbose_generator.generate
61
-
62
- # TODO: If the verbose file uses too many tokens, warn and instead use only
63
- # the summary generatior or do something smart like summarize file contents
64
- end
65
-
66
- def verbose_generator(default_stream: false)
67
- Generators::RelevantFilesVerboseResultsGenerator.new(
68
- file_out: default_stream ? Aircana.configuration.stream : nil
69
- )
70
- end
71
-
72
- def directory_exists?
73
- Dir.exist?(Aircana.configuration.relevant_project_files_dir)
74
- end
75
- end
76
- end
77
- end
78
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../generators"
4
-
5
- module Aircana
6
- module Generators
7
- class RelevantFilesVerboseResultsGenerator < BaseGenerator
8
- def initialize(file_in: nil, file_out: nil)
9
- super(
10
- file_in: file_in || default_template_path,
11
- file_out: file_out || default_output_path
12
- )
13
- end
14
-
15
- private
16
-
17
- def locals
18
- super.merge({ relevant_files: })
19
- end
20
-
21
- def relevant_files
22
- Dir.glob("#{Aircana.configuration.relevant_project_files_dir}/*")
23
- end
24
-
25
- def default_template_path
26
- File.join(File.dirname(__FILE__), "..", "templates", "relevant_files_verbose_results.erb")
27
- end
28
-
29
- def default_output_path
30
- File.join(Aircana.configuration.relevant_project_files_dir, "relevant_files.md")
31
- end
32
- end
33
- end
34
- end
@@ -1,3 +0,0 @@
1
- <%= helpers.model_instructions(
2
- "Read `#{relevant_project_files_path}`, which contains critical context for the current task."
3
- ) %>
@@ -1,18 +0,0 @@
1
- # Relevant Files
2
- <%=
3
- helpers.model_instructions(
4
- <<~INSTRUCTIONS
5
- The following files are considered important for the current task.
6
-
7
- Use them for:
8
- - Understanding task context
9
- - Examples of how to structure your solutions
10
- INSTRUCTIONS
11
- )
12
- %>
13
- <% relevant_files.each do |file_path| %>
14
- ## File: <%= File.realpath(file_path) %>
15
- ```
16
- <%= File.read(file_path) %>
17
- ```
18
- <% end %>