aircana 1.2.0 → 1.3.0
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 +169 -179
- data/CHANGELOG.md +7 -0
- data/CLAUDE.md +0 -2
- data/README.md +47 -6
- data/lib/aircana/cli/app.rb +0 -2
- data/lib/aircana/cli/commands/agents.rb +3 -0
- data/lib/aircana/cli/commands/doctor.rb +11 -5
- data/lib/aircana/cli/commands/doctor_checks.rb +48 -0
- data/lib/aircana/cli/commands/install.rb +4 -5
- data/lib/aircana/generators/agents_generator.rb +1 -1
- data/lib/aircana/generators/helpers.rb +1 -2
- data/lib/aircana/generators/hooks_generator.rb +2 -0
- data/lib/aircana/generators/relevant_files_command_generator.rb +1 -1
- data/lib/aircana/system_checker.rb +11 -0
- data/lib/aircana/templates/agents/base_agent.erb +4 -3
- data/lib/aircana/templates/hooks/notification_sqs.erb +75 -0
- data/lib/aircana/templates/hooks/pre_tool_use.erb +32 -7
- data/lib/aircana/version.rb +1 -1
- data/spec_output_1758908468_248/commands/air-add-relevant-files.md +1 -0
- data/spec_output_1758908479_36/commands/air-add-relevant-files.md +1 -0
- data/spec_output_1758908547_132/commands/air-add-relevant-files.md +1 -0
- data/spec_output_1758908553_721/commands/air-add-relevant-files.md +1 -0
- data/spec_output_1758917010_960/commands/air-add-relevant-files.md +1 -0
- data/spec_output_1758917064_555/commands/air-add-relevant-files.md +1 -0
- metadata +8 -5
- data/lib/aircana/cli/commands/plan.rb +0 -69
- data/lib/aircana/cli/commands/work.rb +0 -69
- data/lib/aircana/templates/agents/defaults/planner.erb +0 -126
- data/lib/aircana/templates/agents/defaults/worker.erb +0 -185
@@ -126,6 +126,54 @@ module Aircana
|
|
126
126
|
end
|
127
127
|
end
|
128
128
|
end
|
129
|
+
|
130
|
+
module SQSIntegration
|
131
|
+
def check_sqs_integration
|
132
|
+
Aircana.human_logger.info "\nSQS Integration:"
|
133
|
+
|
134
|
+
check_sqs_dependencies
|
135
|
+
check_sqs_configuration
|
136
|
+
end
|
137
|
+
|
138
|
+
def check_sqs_dependencies
|
139
|
+
check_command("aws", "SQS operations", required: false)
|
140
|
+
check_command("jq", "JSON processing for notifications", required: false)
|
141
|
+
end
|
142
|
+
|
143
|
+
def check_sqs_configuration
|
144
|
+
sqs_queue_url = ENV.fetch("AIRCANA_SQS_QUEUE_URL", nil)
|
145
|
+
sqs_message_template = ENV.fetch("AIRCANA_SQS_MESSAGE_TEMPLATE", nil)
|
146
|
+
aws_region = ENV.fetch("AWS_REGION", "us-east-1")
|
147
|
+
|
148
|
+
if sqs_configured?(sqs_queue_url, sqs_message_template)
|
149
|
+
log_success("SQS Config", "Environment variables configured")
|
150
|
+
log_sqs_config_details(sqs_queue_url, sqs_message_template, aws_region) if @verbose
|
151
|
+
else
|
152
|
+
log_info("SQS Config", "Not configured")
|
153
|
+
log_sqs_configuration_remedy
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def sqs_configured?(queue_url, message_template)
|
158
|
+
!queue_url.nil? && !queue_url.empty? &&
|
159
|
+
!message_template.nil? && !message_template.empty?
|
160
|
+
end
|
161
|
+
|
162
|
+
def log_sqs_config_details(queue_url, message_template, aws_region)
|
163
|
+
log_info(" AIRCANA_SQS_QUEUE_URL", queue_url.length > 50 ? "#{queue_url[0..47]}..." : queue_url)
|
164
|
+
log_info(" AIRCANA_SQS_MESSAGE_TEMPLATE",
|
165
|
+
message_template.length > 40 ? "#{message_template[0..37]}..." : message_template)
|
166
|
+
log_info(" AWS_REGION", aws_region)
|
167
|
+
end
|
168
|
+
|
169
|
+
def log_sqs_configuration_remedy
|
170
|
+
log_remedy("Set AIRCANA_SQS_QUEUE_URL and AIRCANA_SQS_MESSAGE_TEMPLATE for SQS notifications")
|
171
|
+
log_remedy("Example:")
|
172
|
+
log_remedy(' export AIRCANA_SQS_QUEUE_URL="https://sqs.us-east-1.amazonaws.com/account/queue"')
|
173
|
+
log_remedy(' export AIRCANA_SQS_MESSAGE_TEMPLATE=\'{"text":"{{message}}}\'')
|
174
|
+
log_remedy(' export AWS_REGION="us-east-1" # Optional, defaults to us-east-1')
|
175
|
+
end
|
176
|
+
end
|
129
177
|
end
|
130
178
|
end
|
131
179
|
end
|
@@ -9,7 +9,7 @@ module Aircana
|
|
9
9
|
module Install
|
10
10
|
class << self
|
11
11
|
def run
|
12
|
-
|
12
|
+
generate_files
|
13
13
|
ensure_project_config_exists
|
14
14
|
install_commands_to_claude
|
15
15
|
install_hooks_to_claude
|
@@ -17,10 +17,8 @@ module Aircana
|
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
Aircana.human_logger.warn("No generated output files-auto generating now...")
|
20
|
+
def generate_files
|
21
|
+
Aircana.human_logger.info("Generating files before installation...")
|
24
22
|
Generate.run
|
25
23
|
end
|
26
24
|
|
@@ -118,6 +116,7 @@ module Aircana
|
|
118
116
|
"post_tool_use" => { event: "PostToolUse", matcher: nil },
|
119
117
|
"user_prompt_submit" => { event: "UserPromptSubmit", matcher: nil },
|
120
118
|
"session_start" => { event: "SessionStart", matcher: nil },
|
119
|
+
"notification_sqs" => { event: "Notification", matcher: nil },
|
121
120
|
"rubocop_pre_commit" => { event: "PreToolUse", matcher: "Bash" },
|
122
121
|
"rspec_test" => { event: "PostToolUse", matcher: "Bash" },
|
123
122
|
"bundle_install" => { event: "PostToolUse", matcher: "Bash" }
|
@@ -7,7 +7,7 @@ module Aircana
|
|
7
7
|
class AgentsGenerator < BaseGenerator
|
8
8
|
attr_reader :agent_name, :short_description, :description, :model, :color, :default_agent
|
9
9
|
|
10
|
-
AVAILABLE_DEFAULT_AGENTS =
|
10
|
+
AVAILABLE_DEFAULT_AGENTS = [].freeze
|
11
11
|
|
12
12
|
class << self
|
13
13
|
def create_default_agent(agent_name)
|
@@ -11,6 +11,7 @@ module Aircana
|
|
11
11
|
post_tool_use
|
12
12
|
user_prompt_submit
|
13
13
|
session_start
|
14
|
+
notification_sqs
|
14
15
|
rubocop_pre_commit
|
15
16
|
rspec_test
|
16
17
|
bundle_install
|
@@ -19,6 +20,7 @@ module Aircana
|
|
19
20
|
# Default hooks that are auto-installed
|
20
21
|
DEFAULT_HOOK_TYPES = %w[
|
21
22
|
session_start
|
23
|
+
notification_sqs
|
22
24
|
].freeze
|
23
25
|
|
24
26
|
class << self
|
@@ -25,7 +25,7 @@ module Aircana
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def default_output_path
|
28
|
-
File.join(Aircana.configuration.output_dir, "commands", "
|
28
|
+
File.join(Aircana.configuration.output_dir, "commands", "air-add-relevant-files.md")
|
29
29
|
end
|
30
30
|
|
31
31
|
def relevant_project_files_path
|
@@ -37,6 +37,17 @@ module Aircana
|
|
37
37
|
}.freeze
|
38
38
|
|
39
39
|
OPTIONAL_COMMANDS = {
|
40
|
+
"aws" => {
|
41
|
+
purpose: "SQS notifications via AWS CLI",
|
42
|
+
fallback: "SQS notifications will be disabled",
|
43
|
+
install: {
|
44
|
+
"macOS" => "brew install awscli",
|
45
|
+
"Ubuntu/Debian" => "apt install awscli",
|
46
|
+
"Fedora/CentOS" => "dnf install awscli",
|
47
|
+
"Arch" => "pacman -S aws-cli",
|
48
|
+
"Other" => "https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html"
|
49
|
+
}
|
50
|
+
},
|
40
51
|
"bat" => {
|
41
52
|
purpose: "enhanced file previews",
|
42
53
|
fallback: "head/cat for basic previews",
|
@@ -4,12 +4,11 @@ description: <%= short_description %>
|
|
4
4
|
model: <%= model %>
|
5
5
|
color: <%= color %>
|
6
6
|
---
|
7
|
-
<%= description %>
|
8
7
|
|
9
8
|
<%= helpers.model_instructions("ALWAYS check your knowledge base FIRST for every query, task, or question you receive. Your knowledge is stored in: @#{knowledge_path}
|
10
9
|
|
11
10
|
MANDATORY WORKFLOW:
|
12
|
-
1. BEFORE responding to ANY
|
11
|
+
1. BEFORE responding to ANY request - search and read relevant files in your knowledge base
|
13
12
|
2. Base your responses primarily on information found in your knowledge base
|
14
13
|
3. If knowledge base contains relevant information, cite specific files/sections
|
15
14
|
4. Only use general knowledge when your knowledge base lacks specific information
|
@@ -27,4 +26,6 @@ This knowledge base contains:
|
|
27
26
|
- Team standards and best practices
|
28
27
|
- Technical specifications and requirements
|
29
28
|
|
30
|
-
Always consult this knowledge base before making recommendations or providing guidance.
|
29
|
+
Always consult this knowledge base before making recommendations or providing guidance.
|
30
|
+
|
31
|
+
<%= description %>
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# Aircana SQS notification hook
|
3
|
+
# Sends Claude Code notifications to SQS
|
4
|
+
|
5
|
+
# Read JSON input from stdin
|
6
|
+
INPUT=$(cat)
|
7
|
+
|
8
|
+
# Set up logging
|
9
|
+
mkdir -p ~/.aircana
|
10
|
+
LOG_FILE="$HOME/.aircana/sqs_notifications.log"
|
11
|
+
|
12
|
+
# Log the notification input for debugging
|
13
|
+
echo "$(date): Notification Hook Input:" >> $LOG_FILE
|
14
|
+
echo "$INPUT" >> $LOG_FILE
|
15
|
+
echo "---" >> $LOG_FILE
|
16
|
+
|
17
|
+
# Check if jq is available
|
18
|
+
if ! command -v jq &> /dev/null; then
|
19
|
+
echo "$(date): Error - jq not found. Cannot parse notification." >> $LOG_FILE
|
20
|
+
exit 0
|
21
|
+
fi
|
22
|
+
|
23
|
+
# Check if aws CLI is available
|
24
|
+
if ! command -v aws &> /dev/null; then
|
25
|
+
echo "$(date): Error - aws CLI not found. Cannot send to SQS." >> $LOG_FILE
|
26
|
+
exit 0
|
27
|
+
fi
|
28
|
+
|
29
|
+
# Parse the notification message
|
30
|
+
MESSAGE=$(echo "$INPUT" | jq -r '.message // empty')
|
31
|
+
|
32
|
+
# Skip empty messages
|
33
|
+
if [ -z "$MESSAGE" ] || [ "$MESSAGE" = "null" ]; then
|
34
|
+
echo "$(date): No message found in notification" >> $LOG_FILE
|
35
|
+
exit 0
|
36
|
+
fi
|
37
|
+
|
38
|
+
# Check required environment variables
|
39
|
+
if [ -z "$AIRCANA_SQS_QUEUE_URL" ]; then
|
40
|
+
echo "$(date): AIRCANA_SQS_QUEUE_URL not set, skipping SQS notification" >> $LOG_FILE
|
41
|
+
exit 0
|
42
|
+
fi
|
43
|
+
|
44
|
+
if [ -z "$AIRCANA_SQS_MESSAGE_TEMPLATE" ]; then
|
45
|
+
echo "$(date): AIRCANA_SQS_MESSAGE_TEMPLATE not set, skipping SQS notification" >> $LOG_FILE
|
46
|
+
exit 0
|
47
|
+
fi
|
48
|
+
|
49
|
+
# Create the message body by substituting {{message}} in the template
|
50
|
+
MESSAGE_BODY=$(echo "$AIRCANA_SQS_MESSAGE_TEMPLATE" | sed "s|{{message}}|$MESSAGE|g")
|
51
|
+
|
52
|
+
# Log the message being sent
|
53
|
+
echo "$(date): Sending SQS message:" >> $LOG_FILE
|
54
|
+
echo "Queue URL: $AIRCANA_SQS_QUEUE_URL" >> $LOG_FILE
|
55
|
+
echo "Message Body: $MESSAGE_BODY" >> $LOG_FILE
|
56
|
+
|
57
|
+
# Send message to SQS using aws CLI
|
58
|
+
AWS_REGION=${AWS_REGION:-us-east-1}
|
59
|
+
SQS_RESULT=$(aws --region "$AWS_REGION" sqs send-message \
|
60
|
+
--queue-url "$AIRCANA_SQS_QUEUE_URL" \
|
61
|
+
--message-body "$MESSAGE_BODY" 2>&1)
|
62
|
+
|
63
|
+
# Log the result
|
64
|
+
if [ $? -eq 0 ]; then
|
65
|
+
echo "$(date): Successfully sent SQS message" >> $LOG_FILE
|
66
|
+
echo "Response: $SQS_RESULT" >> $LOG_FILE
|
67
|
+
else
|
68
|
+
echo "$(date): Failed to send SQS message" >> $LOG_FILE
|
69
|
+
echo "Error: $SQS_RESULT" >> $LOG_FILE
|
70
|
+
fi
|
71
|
+
|
72
|
+
echo "---" >> $LOG_FILE
|
73
|
+
|
74
|
+
# Return success - don't block Claude Code if SQS fails
|
75
|
+
exit 0
|
@@ -2,25 +2,33 @@
|
|
2
2
|
# Pre-tool-use hook generated by Aircana
|
3
3
|
# This hook runs before any tool is executed
|
4
4
|
|
5
|
-
#
|
6
|
-
|
7
|
-
|
5
|
+
# Read JSON input from stdin
|
6
|
+
INPUT=$(cat)
|
7
|
+
|
8
|
+
# Parse JSON to extract tool information
|
9
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
|
10
|
+
TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input // empty')
|
11
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty')
|
12
|
+
CWD=$(echo "$INPUT" | jq -r '.cwd // empty')
|
8
13
|
|
9
14
|
# Log the tool usage (optional)
|
10
|
-
echo "$(date): About to use tool: $TOOL_NAME" >> ~/.aircana/hooks.log
|
15
|
+
echo "$(date): Session $SESSION_ID - About to use tool: $TOOL_NAME in $CWD" >> ~/.aircana/hooks.log
|
11
16
|
|
12
17
|
# Basic validation example
|
13
18
|
case "$TOOL_NAME" in
|
14
19
|
"Bash")
|
15
20
|
# Add validation for bash commands
|
16
|
-
|
21
|
+
COMMAND=$(echo "$TOOL_INPUT" | jq -r '.command // empty')
|
22
|
+
if echo "$COMMAND" | grep -q "rm -rf /"; then
|
17
23
|
cat << EOF
|
18
24
|
{
|
19
25
|
"hookSpecificOutput": {
|
20
26
|
"hookEventName": "PreToolUse",
|
21
27
|
"permissionDecision": "deny",
|
22
28
|
"permissionDecisionReason": "Dangerous command detected: rm -rf /"
|
23
|
-
}
|
29
|
+
},
|
30
|
+
"continue": false,
|
31
|
+
"stopReason": "Blocked dangerous command"
|
24
32
|
}
|
25
33
|
EOF
|
26
34
|
exit 0
|
@@ -28,7 +36,23 @@ EOF
|
|
28
36
|
;;
|
29
37
|
"Edit"|"Write")
|
30
38
|
# Validate file operations
|
39
|
+
FILE_PATH=$(echo "$TOOL_INPUT" | jq -r '.file_path // empty')
|
31
40
|
# Add custom validation logic here
|
41
|
+
# Example: Check if trying to modify system files
|
42
|
+
if echo "$FILE_PATH" | grep -q "^/etc/\|^/usr/\|^/bin/\|^/sbin/"; then
|
43
|
+
cat << EOF
|
44
|
+
{
|
45
|
+
"hookSpecificOutput": {
|
46
|
+
"hookEventName": "PreToolUse",
|
47
|
+
"permissionDecision": "ask",
|
48
|
+
"permissionDecisionReason": "Attempting to modify system file: $FILE_PATH"
|
49
|
+
},
|
50
|
+
"continue": true,
|
51
|
+
"systemMessage": "Warning: About to modify a system file"
|
52
|
+
}
|
53
|
+
EOF
|
54
|
+
exit 0
|
55
|
+
fi
|
32
56
|
;;
|
33
57
|
esac
|
34
58
|
|
@@ -38,6 +62,7 @@ cat << EOF
|
|
38
62
|
"hookSpecificOutput": {
|
39
63
|
"hookEventName": "PreToolUse",
|
40
64
|
"permissionDecision": "allow"
|
41
|
-
}
|
65
|
+
},
|
66
|
+
"continue": true
|
42
67
|
}
|
43
68
|
EOF
|
data/lib/aircana/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
INSTRUCTIONS : Read `/Users/wdransfield/GitHub/aircana/.aircana/relevant_files/relevant_files.md`, which contains critical context for the current task.
|
@@ -0,0 +1 @@
|
|
1
|
+
INSTRUCTIONS : Read `/Users/wdransfield/GitHub/aircana/.aircana/relevant_files/relevant_files.md`, which contains critical context for the current task.
|
@@ -0,0 +1 @@
|
|
1
|
+
INSTRUCTIONS : Read `/Users/wdransfield/GitHub/aircana/.aircana/relevant_files/relevant_files.md`, which contains critical context for the current task.
|
@@ -0,0 +1 @@
|
|
1
|
+
INSTRUCTIONS : Read `/Users/wdransfield/GitHub/aircana/.aircana/relevant_files/relevant_files.md`, which contains critical context for the current task.
|
@@ -0,0 +1 @@
|
|
1
|
+
INSTRUCTIONS : Read `/Users/wdransfield/GitHub/aircana/.aircana/relevant_files/relevant_files.md`, which contains critical context for the current task.
|
@@ -0,0 +1 @@
|
|
1
|
+
INSTRUCTIONS : Read `/Users/wdransfield/GitHub/aircana/.aircana/relevant_files/relevant_files.md`, which contains critical context for the current task.
|
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: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Weston Dransfield
|
@@ -130,9 +130,7 @@ files:
|
|
130
130
|
- lib/aircana/cli/commands/generate.rb
|
131
131
|
- lib/aircana/cli/commands/hooks.rb
|
132
132
|
- lib/aircana/cli/commands/install.rb
|
133
|
-
- lib/aircana/cli/commands/plan.rb
|
134
133
|
- lib/aircana/cli/commands/project.rb
|
135
|
-
- lib/aircana/cli/commands/work.rb
|
136
134
|
- lib/aircana/cli/help_formatter.rb
|
137
135
|
- lib/aircana/cli/shell_command.rb
|
138
136
|
- lib/aircana/cli/subcommand.rb
|
@@ -162,10 +160,9 @@ files:
|
|
162
160
|
- lib/aircana/symlink_manager.rb
|
163
161
|
- lib/aircana/system_checker.rb
|
164
162
|
- lib/aircana/templates/agents/base_agent.erb
|
165
|
-
- lib/aircana/templates/agents/defaults/planner.erb
|
166
|
-
- lib/aircana/templates/agents/defaults/worker.erb
|
167
163
|
- lib/aircana/templates/commands/add_relevant_files.erb
|
168
164
|
- lib/aircana/templates/hooks/bundle_install.erb
|
165
|
+
- lib/aircana/templates/hooks/notification_sqs.erb
|
169
166
|
- lib/aircana/templates/hooks/post_tool_use.erb
|
170
167
|
- lib/aircana/templates/hooks/pre_tool_use.erb
|
171
168
|
- lib/aircana/templates/hooks/rspec_test.erb
|
@@ -175,6 +172,12 @@ files:
|
|
175
172
|
- lib/aircana/templates/relevant_files_verbose_results.erb
|
176
173
|
- lib/aircana/version.rb
|
177
174
|
- sig/aircana.rbs
|
175
|
+
- spec_output_1758908468_248/commands/air-add-relevant-files.md
|
176
|
+
- spec_output_1758908479_36/commands/air-add-relevant-files.md
|
177
|
+
- spec_output_1758908547_132/commands/air-add-relevant-files.md
|
178
|
+
- spec_output_1758908553_721/commands/air-add-relevant-files.md
|
179
|
+
- spec_output_1758917010_960/commands/air-add-relevant-files.md
|
180
|
+
- spec_output_1758917064_555/commands/air-add-relevant-files.md
|
178
181
|
homepage: https://github.com/westonkd/aircana
|
179
182
|
licenses:
|
180
183
|
- MIT
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "generate"
|
4
|
-
require_relative "install"
|
5
|
-
require_relative "../../generators/agents_generator"
|
6
|
-
|
7
|
-
module Aircana
|
8
|
-
module CLI
|
9
|
-
module Plan
|
10
|
-
class << self
|
11
|
-
def run
|
12
|
-
ensure_planner_agent_installed
|
13
|
-
launch_claude_with_planner
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def ensure_planner_agent_installed
|
19
|
-
planner_agent_path = File.join(
|
20
|
-
Aircana.configuration.claude_code_config_path,
|
21
|
-
"agents",
|
22
|
-
"planner.md"
|
23
|
-
)
|
24
|
-
|
25
|
-
return if File.exist?(planner_agent_path)
|
26
|
-
|
27
|
-
Aircana.human_logger.info("Planner agent not found. Generating and installing...")
|
28
|
-
Generate.run
|
29
|
-
Install.run
|
30
|
-
end
|
31
|
-
|
32
|
-
def launch_claude_with_planner
|
33
|
-
prompt = "Start a planning session with the 'planner' sub-agent"
|
34
|
-
|
35
|
-
Aircana.human_logger.info("Launching Claude Code with planner agent...")
|
36
|
-
|
37
|
-
claude_path = find_claude_path
|
38
|
-
if claude_path
|
39
|
-
system("#{claude_path} \"#{prompt}\"")
|
40
|
-
else
|
41
|
-
handle_claude_not_found(prompt)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def handle_claude_not_found(prompt)
|
46
|
-
error_message = "Claude Code command not found. " \
|
47
|
-
"Please make sure Claude Code is installed and in your PATH."
|
48
|
-
Aircana.human_logger.error(error_message)
|
49
|
-
Aircana.human_logger.info("You can manually start Claude Code and run: #{prompt}")
|
50
|
-
end
|
51
|
-
|
52
|
-
def find_claude_path
|
53
|
-
# Try common locations for Claude Code binary (same as ClaudeClient)
|
54
|
-
possible_paths = [
|
55
|
-
File.expand_path("~/.claude/local/claude"),
|
56
|
-
`/usr/bin/which claude`.strip,
|
57
|
-
"/usr/local/bin/claude"
|
58
|
-
]
|
59
|
-
|
60
|
-
possible_paths.each do |path|
|
61
|
-
return path if !path.empty? && File.executable?(path)
|
62
|
-
end
|
63
|
-
|
64
|
-
nil
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "generate"
|
4
|
-
require_relative "install"
|
5
|
-
require_relative "../../generators/agents_generator"
|
6
|
-
|
7
|
-
module Aircana
|
8
|
-
module CLI
|
9
|
-
module Work
|
10
|
-
class << self
|
11
|
-
def run
|
12
|
-
ensure_worker_agent_installed
|
13
|
-
launch_claude_with_worker
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def ensure_worker_agent_installed
|
19
|
-
worker_agent_path = File.join(
|
20
|
-
Aircana.configuration.claude_code_config_path,
|
21
|
-
"agents",
|
22
|
-
"worker.md"
|
23
|
-
)
|
24
|
-
|
25
|
-
return if File.exist?(worker_agent_path)
|
26
|
-
|
27
|
-
Aircana.human_logger.info("Worker agent not found. Generating and installing...")
|
28
|
-
Generate.run
|
29
|
-
Install.run
|
30
|
-
end
|
31
|
-
|
32
|
-
def launch_claude_with_worker
|
33
|
-
prompt = "Start a work session with the 'worker' sub-agent"
|
34
|
-
|
35
|
-
Aircana.human_logger.info("Launching Claude Code with worker agent...")
|
36
|
-
|
37
|
-
claude_path = find_claude_path
|
38
|
-
if claude_path
|
39
|
-
system("#{claude_path} \"#{prompt}\"")
|
40
|
-
else
|
41
|
-
handle_claude_not_found(prompt)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def handle_claude_not_found(prompt)
|
46
|
-
error_message = "Claude Code command not found. " \
|
47
|
-
"Please make sure Claude Code is installed and in your PATH."
|
48
|
-
Aircana.human_logger.error(error_message)
|
49
|
-
Aircana.human_logger.info("You can manually start Claude Code and run: #{prompt}")
|
50
|
-
end
|
51
|
-
|
52
|
-
def find_claude_path
|
53
|
-
# Try common locations for Claude Code binary (same as ClaudeClient)
|
54
|
-
possible_paths = [
|
55
|
-
File.expand_path("~/.claude/local/claude"),
|
56
|
-
`/usr/bin/which claude`.strip,
|
57
|
-
"/usr/local/bin/claude"
|
58
|
-
]
|
59
|
-
|
60
|
-
possible_paths.each do |path|
|
61
|
-
return path if !path.empty? && File.executable?(path)
|
62
|
-
end
|
63
|
-
|
64
|
-
nil
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
---
|
2
|
-
name: planner
|
3
|
-
description: Specialized agent for creating implementation plans for Jira tickets
|
4
|
-
model: inherit
|
5
|
-
color: blue
|
6
|
-
---
|
7
|
-
# Planner Agent
|
8
|
-
|
9
|
-
You are the Planner Agent, specialized in creating comprehensive implementation plans for Jira tickets through AI-powered collaboration with expert agents.
|
10
|
-
|
11
|
-
<%= helpers.model_instructions("ALWAYS check your knowledge base FIRST for every query, task, or question you receive. Your knowledge is stored in: @#{knowledge_path}
|
12
|
-
|
13
|
-
MANDATORY WORKFLOW FOR KNOWLEDGE:
|
14
|
-
1. BEFORE starting any planning - search and read relevant files in your knowledge base
|
15
|
-
2. Look for existing planning templates, processes, and methodologies
|
16
|
-
3. Check for similar ticket plans or implementation patterns
|
17
|
-
4. Review project-specific requirements and constraints
|
18
|
-
5. Base your planning approach on knowledge base guidance when available
|
19
|
-
6. Incorporate knowledge base standards into your execution plans
|
20
|
-
|
21
|
-
Your knowledge base contains domain-specific information that takes priority over general planning knowledge.", important: true) %>
|
22
|
-
|
23
|
-
## Core Responsibilities
|
24
|
-
|
25
|
-
You create detailed implementation plans by:
|
26
|
-
1. Gathering ticket requirements from Jira
|
27
|
-
2. Collecting relevant project files for context
|
28
|
-
3. Coordinating with expert agents for specialized analysis
|
29
|
-
4. Generating comprehensive execution plans
|
30
|
-
5. Creating actionable todo lists
|
31
|
-
6. Storing plans in structured format
|
32
|
-
|
33
|
-
## Planning Workflow
|
34
|
-
|
35
|
-
Follow this exact sequence for every planning session:
|
36
|
-
|
37
|
-
### Step A: Ticket Identification
|
38
|
-
- Prompt user for Jira ticket ID to plan for
|
39
|
-
- If no ticket provided, ask if they want to create a new one.
|
40
|
-
- Use MCP Jira tools to fetch ticket details
|
41
|
-
|
42
|
-
**IMMEDIATELY: Check Knowledge Base**
|
43
|
-
- Search your knowledge base (@<%= knowledge_path %>) for:
|
44
|
-
- Similar tickets or implementations
|
45
|
-
- Relevant planning methodologies
|
46
|
-
- Project-specific planning templates
|
47
|
-
- Domain-specific requirements and constraints
|
48
|
-
|
49
|
-
### Step B: Check Existing Plan
|
50
|
-
- Examine ticket description for "# AGENT PLAN #" section
|
51
|
-
- If found, present existing plan to user
|
52
|
-
- Ask if adjustments are needed to current plan
|
53
|
-
|
54
|
-
### Step C: Gather Context (if no plan exists)
|
55
|
-
- **FIRST: Ask user for relevant files**
|
56
|
-
- Prompt: "What files are most relevant to this ticket? Please list file paths."
|
57
|
-
- These files provide crucial context before expert consultation
|
58
|
-
- Read and analyze provided relevant files
|
59
|
-
- Extract key patterns, frameworks, and architectural decisions
|
60
|
-
|
61
|
-
### Step D: Expert Agent Coordination
|
62
|
-
- Based on ticket requirements, relevant files, and knowledge base findings, identify expert agents
|
63
|
-
- **BEFORE consulting experts**: Review knowledge base for existing expert guidance on similar topics
|
64
|
-
- Use Claude Code's Task tool to consult expert agents in parallel
|
65
|
-
- Ask each expert to provide key details for the plan in their domain of expertise
|
66
|
-
- **Combine knowledge base findings with expert recommendations** for comprehensive planning
|
67
|
-
|
68
|
-
### Step E: Plan Generation
|
69
|
-
- Consolidate expert recommendations into cohesive execution plan
|
70
|
-
- Create detailed todo list including:
|
71
|
-
- Implementation steps
|
72
|
-
- Unit test writing requirements
|
73
|
-
- Test execution and iteration cycles
|
74
|
-
- Present plan to user for approval and adjustments
|
75
|
-
|
76
|
-
### Step F: Plan Storage
|
77
|
-
- Format plan with required sections (see below)
|
78
|
-
- If new ticket needed, ask for Jira project and create ticket
|
79
|
-
- Update/create Jira ticket with complete plan in description. Do not search yourself
|
80
|
-
for an appropriate Jira project. Always ask the user what Jira project the ticket
|
81
|
-
should be created in.
|
82
|
-
|
83
|
-
## Plan Format
|
84
|
-
|
85
|
-
Store plans in Jira ticket descriptions using this exact structure:
|
86
|
-
|
87
|
-
```markdown
|
88
|
-
# AGENT PLAN #
|
89
|
-
|
90
|
-
## Relevant Files
|
91
|
-
- path/to/file1.rb
|
92
|
-
- path/to/file2.rb
|
93
|
-
- directory/file3.rb
|
94
|
-
|
95
|
-
## Expert Agents
|
96
|
-
- agent-name-1
|
97
|
-
- agent-name-2
|
98
|
-
|
99
|
-
## Execution Plan
|
100
|
-
[Detailed implementation steps from expert analysis]
|
101
|
-
|
102
|
-
## Todo List
|
103
|
-
- [ ] Task 1
|
104
|
-
- [ ] Task 2
|
105
|
-
- [ ] Write unit tests for [specific functionality]
|
106
|
-
- [ ] Run tests and iterate until all pass
|
107
|
-
- [ ] Final integration testing
|
108
|
-
```
|
109
|
-
|
110
|
-
## Key Instructions
|
111
|
-
|
112
|
-
1. **Always ask for relevant files BEFORE consulting expert agents**
|
113
|
-
2. **Use the exact "# AGENT PLAN #" header for plan sections**
|
114
|
-
3. **Include test writing and execution in every todo list**
|
115
|
-
4. **Present plans to users for approval before saving**
|
116
|
-
5. **Use MCP Jira tools for all ticket operations**
|
117
|
-
6. **Coordinate expert agents using Claude Code's Task tool**
|
118
|
-
|
119
|
-
## Error Handling
|
120
|
-
|
121
|
-
- If Jira access fails, guide user to check MCP Jira configuration
|
122
|
-
- If no expert agents found, proceed with general analysis
|
123
|
-
- If file access fails, note in plan and continue
|
124
|
-
- Always provide fallback options when tools fail
|
125
|
-
|
126
|
-
Start every planning session by confirming: "I'm ready to help you create an implementation plan. Do you have a Jira ticket ID to plan for, or would you like to create a new ticket?"
|