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.
- checksums.yaml +4 -4
- data/.rspec_status +175 -186
- data/CLAUDE.md +1 -7
- data/README.md +91 -81
- data/lib/aircana/cli/app.rb +5 -29
- data/lib/aircana/cli/commands/agents.rb +78 -0
- data/lib/aircana/cli/commands/doctor_checks.rb +0 -12
- data/lib/aircana/cli/commands/dump_context.rb +2 -3
- data/lib/aircana/cli/commands/generate.rb +3 -5
- data/lib/aircana/configuration.rb +1 -2
- data/lib/aircana/contexts/confluence.rb +1 -3
- data/lib/aircana/contexts/manifest.rb +1 -10
- data/lib/aircana/contexts/web.rb +1 -3
- data/lib/aircana/generators/agents_generator.rb +2 -6
- data/lib/aircana/generators/{relevant_files_command_generator.rb → ask_expert_command_generator.rb} +3 -13
- data/lib/aircana/generators.rb +0 -2
- data/lib/aircana/templates/agents/defaults/sub-agent-coordinator.erb +90 -0
- data/lib/aircana/templates/commands/ask_expert.erb +44 -0
- data/lib/aircana/version.rb +1 -1
- data/lib/aircana.rb +0 -2
- metadata +5 -11
- data/lib/aircana/cli/commands/add_directory.rb +0 -148
- data/lib/aircana/cli/commands/add_files.rb +0 -26
- data/lib/aircana/cli/commands/clear_files.rb +0 -16
- data/lib/aircana/cli/commands/files.rb +0 -65
- data/lib/aircana/contexts/relevant_files.rb +0 -78
- data/lib/aircana/generators/relevant_files_verbose_results_generator.rb +0 -34
- data/lib/aircana/templates/commands/add_relevant_files.erb +0 -3
- data/lib/aircana/templates/relevant_files_verbose_results.erb +0 -18
@@ -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
|
+
) %>
|
data/lib/aircana/version.rb
CHANGED
data/lib/aircana.rb
CHANGED
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:
|
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-
|
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/
|
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,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 %>
|