ara-cli 0.1.10.5__py3-none-any.whl → 0.1.11.0__py3-none-any.whl
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.
Potentially problematic release.
This version of ara-cli might be problematic. Click here for more details.
- ara_cli/__init__.py +0 -1
- ara_cli/__main__.py +23 -49
- ara_cli/chat.py +142 -18
- ara_cli/chat_agent/__init__.py +0 -0
- ara_cli/chat_agent/agent_communicator.py +62 -0
- ara_cli/chat_agent/agent_process_manager.py +211 -0
- ara_cli/chat_agent/agent_status_manager.py +73 -0
- ara_cli/chat_agent/agent_workspace_manager.py +76 -0
- ara_cli/directory_navigator.py +37 -4
- ara_cli/templates/prompt-modules/commands/empty.commands.md +2 -12
- ara_cli/templates/prompt-modules/commands/extract_general.commands.md +12 -0
- ara_cli/templates/prompt-modules/commands/extract_markdown.commands.md +11 -0
- ara_cli/templates/prompt-modules/commands/extract_python.commands.md +13 -0
- ara_cli/templates/prompt-modules/commands/feature_add_or_modifiy_specified_behavior.commands.md +36 -0
- ara_cli/templates/prompt-modules/commands/feature_generate_initial_specified_bevahior.commands.md +53 -0
- ara_cli/templates/prompt-modules/commands/prompt_template_tech_stack_transformer.commands.md +95 -0
- ara_cli/templates/prompt-modules/commands/python_bug_fixing_code.commands.md +34 -0
- ara_cli/templates/prompt-modules/commands/python_generate_code.commands.md +27 -0
- ara_cli/templates/prompt-modules/commands/python_refactoring_code.commands.md +39 -0
- ara_cli/templates/prompt-modules/commands/python_step_definitions_generation_and_fixing.commands.md +40 -0
- ara_cli/templates/prompt-modules/commands/python_unittest_generation_and_fixing.commands.md +48 -0
- ara_cli/version.py +1 -1
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.11.0.dist-info}/METADATA +31 -1
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.11.0.dist-info}/RECORD +27 -28
- ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +0 -27
- ara_cli/templates/prompt-modules/blueprints/pytest_unittest_prompt.blueprint.md +0 -32
- ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -30
- ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -9
- ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -17
- ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -14
- ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -102
- ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -20
- ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -13
- ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -20
- ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -18
- ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -43
- ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -13
- ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -15
- ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -9
- ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -15
- ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -19
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.11.0.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.11.0.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.11.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
from ara_cli.chat_agent.agent_workspace_manager import AgentWorkspaceManager
|
|
2
|
+
from ara_cli.error_handler import AraError, ErrorLevel
|
|
3
|
+
from ara_cli.chat_agent.agent_status_manager import AgentStatusManager
|
|
4
|
+
from ara_cli.chat_agent.agent_communicator import AgentCommunicator
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import threading
|
|
8
|
+
import psutil
|
|
9
|
+
import queue
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AgentProcessManager:
|
|
13
|
+
_instance = None
|
|
14
|
+
|
|
15
|
+
def __new__(cls, chat_instance=None):
|
|
16
|
+
if cls._instance is None:
|
|
17
|
+
cls._instance = super(AgentProcessManager, cls).__new__(cls)
|
|
18
|
+
cls._instance._initialized = False
|
|
19
|
+
return cls._instance
|
|
20
|
+
|
|
21
|
+
def __init__(self, chat_instance=None):
|
|
22
|
+
if hasattr(self, "_initialized") and self._initialized:
|
|
23
|
+
if chat_instance:
|
|
24
|
+
self.chat_instance = chat_instance
|
|
25
|
+
return
|
|
26
|
+
if chat_instance is None:
|
|
27
|
+
raise ValueError(
|
|
28
|
+
"chat_instance must be provided for the first instantiation"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
self.chat_instance = chat_instance
|
|
32
|
+
self.agent_process = None
|
|
33
|
+
self.agent_reader_thread = None
|
|
34
|
+
self.agent_output_queue = queue.Queue()
|
|
35
|
+
self.agent_mode = False
|
|
36
|
+
self.agent_name = None
|
|
37
|
+
self.status_manager = AgentStatusManager()
|
|
38
|
+
self._initialized = True
|
|
39
|
+
|
|
40
|
+
def cleanup_agent_process(self):
|
|
41
|
+
pid = self.status_manager.get_agent_pid()
|
|
42
|
+
if pid and psutil.pid_exists(pid):
|
|
43
|
+
try:
|
|
44
|
+
p = psutil.Process(pid)
|
|
45
|
+
p.terminate()
|
|
46
|
+
p.wait(timeout=3)
|
|
47
|
+
except (psutil.NoSuchProcess, psutil.TimeoutExpired):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
self.status_manager.clear_status()
|
|
51
|
+
|
|
52
|
+
if self.agent_process:
|
|
53
|
+
try:
|
|
54
|
+
self.agent_process.terminate()
|
|
55
|
+
except:
|
|
56
|
+
pass
|
|
57
|
+
self.agent_process = None
|
|
58
|
+
|
|
59
|
+
if self.agent_reader_thread and self.agent_reader_thread.is_alive():
|
|
60
|
+
self.agent_reader_thread = None
|
|
61
|
+
|
|
62
|
+
self.agent_mode = False
|
|
63
|
+
self.agent_name = None
|
|
64
|
+
if hasattr(self, "chat_instance"):
|
|
65
|
+
self.chat_instance.prompt = "ara> "
|
|
66
|
+
|
|
67
|
+
def start_agent(
|
|
68
|
+
self, agent_name, initial_prompt, artefact_classifier=None, artefact_name=None
|
|
69
|
+
):
|
|
70
|
+
if self.get_agent_status() != "No agent is currently running.":
|
|
71
|
+
raise AraError(
|
|
72
|
+
"An agent is already running. Use AGENT_STOP to stop it first."
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if agent_name not in self.chat_instance.AVAILABLE_AGENTS:
|
|
76
|
+
raise AraError(f"Unknown agent: {agent_name}")
|
|
77
|
+
|
|
78
|
+
base_work_dir = AgentWorkspaceManager.determine_base_work_dir(
|
|
79
|
+
self.chat_instance
|
|
80
|
+
)
|
|
81
|
+
agent_workspace_dir = AgentWorkspaceManager.determine_agent_workspace(
|
|
82
|
+
self.chat_instance, artefact_classifier, artefact_name
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
cmd = [
|
|
86
|
+
"ara-agents",
|
|
87
|
+
agent_name,
|
|
88
|
+
"-u",
|
|
89
|
+
initial_prompt,
|
|
90
|
+
"-g",
|
|
91
|
+
"roundrobin",
|
|
92
|
+
"-b",
|
|
93
|
+
".",
|
|
94
|
+
"-s",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
if artefact_classifier and artefact_name:
|
|
98
|
+
try:
|
|
99
|
+
artefact_path = self._find_artefact_path(
|
|
100
|
+
artefact_classifier, artefact_name
|
|
101
|
+
)
|
|
102
|
+
cmd.extend(["-r", artefact_path])
|
|
103
|
+
print(f"Starting {agent_name} with artefact: {artefact_path}")
|
|
104
|
+
print(f"Base work directory: {base_work_dir}")
|
|
105
|
+
print(f"Agent logs directory: {agent_workspace_dir}")
|
|
106
|
+
except AraError as e:
|
|
107
|
+
raise AraError(f"Error: {e}")
|
|
108
|
+
else:
|
|
109
|
+
print(f"Starting {agent_name}...")
|
|
110
|
+
print(f"Base work directory: {base_work_dir}")
|
|
111
|
+
print(f"Agent logs directory: {agent_workspace_dir}")
|
|
112
|
+
|
|
113
|
+
env = os.environ.copy()
|
|
114
|
+
env["CENTRAL_LOG_PATH"] = os.path.join(
|
|
115
|
+
agent_workspace_dir, "io_context.log")
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
self.agent_process = subprocess.Popen(
|
|
119
|
+
cmd,
|
|
120
|
+
stdin=subprocess.PIPE,
|
|
121
|
+
stdout=subprocess.PIPE,
|
|
122
|
+
stderr=subprocess.STDOUT,
|
|
123
|
+
text=True,
|
|
124
|
+
bufsize=1,
|
|
125
|
+
cwd=base_work_dir,
|
|
126
|
+
env=env,
|
|
127
|
+
)
|
|
128
|
+
self.agent_name = agent_name
|
|
129
|
+
self.status_manager.write_status(
|
|
130
|
+
self.agent_process.pid, self.agent_name, "processing"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
communicator = AgentCommunicator(self)
|
|
134
|
+
self.agent_reader_thread = threading.Thread(
|
|
135
|
+
target=communicator.read_agent_output, daemon=True
|
|
136
|
+
)
|
|
137
|
+
self.agent_reader_thread.start()
|
|
138
|
+
|
|
139
|
+
print(f"Agent {agent_name} started. Waiting for response...\n")
|
|
140
|
+
communicator.process_agent_output()
|
|
141
|
+
|
|
142
|
+
except FileNotFoundError:
|
|
143
|
+
raise AraError(
|
|
144
|
+
"Agent could not started."
|
|
145
|
+
"\nReason: 'ara-agents' command not found. Make sure ara-agents is locally installed.",
|
|
146
|
+
level=ErrorLevel.CRITICAL,
|
|
147
|
+
)
|
|
148
|
+
except Exception as e:
|
|
149
|
+
self.cleanup_agent_process()
|
|
150
|
+
raise AraError(f"Error starting agent: {e}")
|
|
151
|
+
|
|
152
|
+
def _find_artefact_path(self, artefact_classifier, artefact_name):
|
|
153
|
+
from ara_cli.classifier import Classifier
|
|
154
|
+
|
|
155
|
+
classifier_dir = Classifier.get_sub_directory(artefact_classifier)
|
|
156
|
+
if not classifier_dir:
|
|
157
|
+
raise AraError(f"Unknown classifier: {artefact_classifier}")
|
|
158
|
+
|
|
159
|
+
chat_dir = os.path.dirname(self.chat_instance.chat_name)
|
|
160
|
+
ara_dir = os.path.join(chat_dir, "ara", classifier_dir)
|
|
161
|
+
|
|
162
|
+
for ext in [artefact_classifier, "md"]:
|
|
163
|
+
artefact_path = os.path.join(ara_dir, f"{artefact_name}.{ext}")
|
|
164
|
+
if os.path.exists(artefact_path):
|
|
165
|
+
return artefact_path
|
|
166
|
+
|
|
167
|
+
raise AraError(
|
|
168
|
+
f"Artefact not found: {artefact_name}.{artefact_classifier}")
|
|
169
|
+
|
|
170
|
+
def send_to_agent(self, text):
|
|
171
|
+
if not self.agent_process or self.agent_process.poll() is not None:
|
|
172
|
+
print("Error: Agent process is not running")
|
|
173
|
+
self.cleanup_agent_process()
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
self.agent_process.stdin.write(text + "\n")
|
|
178
|
+
self.agent_process.stdin.flush()
|
|
179
|
+
|
|
180
|
+
self.agent_mode = False
|
|
181
|
+
self.chat_instance.prompt = "ara> "
|
|
182
|
+
self.status_manager.update_status_file(mode="processing")
|
|
183
|
+
|
|
184
|
+
communicator = AgentCommunicator(self)
|
|
185
|
+
communicator.process_agent_output()
|
|
186
|
+
|
|
187
|
+
except Exception as e:
|
|
188
|
+
print(f"Error sending to agent: {e}")
|
|
189
|
+
self.cleanup_agent_process()
|
|
190
|
+
|
|
191
|
+
def continue_agent(self):
|
|
192
|
+
status = self.get_agent_status()
|
|
193
|
+
if "No agent" in status:
|
|
194
|
+
print("No agent is currently running.")
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
if not self.agent_process or self.agent_process.poll() is not None:
|
|
198
|
+
print(
|
|
199
|
+
"AGENT_CONTINUE can only be used from the chat interface that started the agent."
|
|
200
|
+
)
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
if not self.agent_mode:
|
|
204
|
+
print("Agent is not waiting for input. Wait for 'ara-agent>' prompt.")
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
print("Continuing agent with empty input...")
|
|
208
|
+
self.send_to_agent("")
|
|
209
|
+
|
|
210
|
+
def get_agent_status(self):
|
|
211
|
+
return self.status_manager.get_agent_status()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import psutil
|
|
4
|
+
from ara_cli.directory_navigator import DirectoryNavigator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AgentStatusManager:
|
|
8
|
+
def get_status_file_path(self):
|
|
9
|
+
ara_root = DirectoryNavigator.find_ara_directory_root()
|
|
10
|
+
if not ara_root:
|
|
11
|
+
return None
|
|
12
|
+
return os.path.join(ara_root, ".araconfig", "agent_status.json")
|
|
13
|
+
|
|
14
|
+
def get_agent_pid(self):
|
|
15
|
+
status_file = self.get_status_file_path()
|
|
16
|
+
if not status_file or not os.path.exists(status_file):
|
|
17
|
+
return None
|
|
18
|
+
|
|
19
|
+
with open(status_file, "r") as f:
|
|
20
|
+
try:
|
|
21
|
+
status = json.load(f)
|
|
22
|
+
return status.get("pid")
|
|
23
|
+
except json.JSONDecodeError:
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
def update_status_file(self, mode):
|
|
27
|
+
status_file = self.get_status_file_path()
|
|
28
|
+
if not status_file or not os.path.exists(status_file):
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
with open(status_file, "r") as f:
|
|
33
|
+
status = json.load(f)
|
|
34
|
+
except (FileNotFoundError, json.JSONDecodeError):
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
status["mode"] = mode
|
|
38
|
+
|
|
39
|
+
with open(status_file, "w") as f:
|
|
40
|
+
json.dump(status, f)
|
|
41
|
+
|
|
42
|
+
def get_agent_status(self):
|
|
43
|
+
status_file = self.get_status_file_path()
|
|
44
|
+
if not status_file or not os.path.exists(status_file):
|
|
45
|
+
return "No agent is currently running."
|
|
46
|
+
|
|
47
|
+
with open(status_file, "r") as f:
|
|
48
|
+
try:
|
|
49
|
+
status = json.load(f)
|
|
50
|
+
except json.JSONDecodeError:
|
|
51
|
+
return "No agent is currently running."
|
|
52
|
+
|
|
53
|
+
pid = status.get("pid")
|
|
54
|
+
if not pid or not psutil.pid_exists(pid):
|
|
55
|
+
if os.path.exists(status_file):
|
|
56
|
+
os.remove(status_file)
|
|
57
|
+
return "No agent is currently running."
|
|
58
|
+
|
|
59
|
+
name = status.get("name")
|
|
60
|
+
mode = status.get("mode")
|
|
61
|
+
return f"Agent: {name} (running - {mode})"
|
|
62
|
+
|
|
63
|
+
def write_status(self, pid, name, mode):
|
|
64
|
+
status = {"pid": pid, "name": name, "mode": mode}
|
|
65
|
+
status_file = self.get_status_file_path()
|
|
66
|
+
if status_file:
|
|
67
|
+
with open(status_file, "w") as f:
|
|
68
|
+
json.dump(status, f)
|
|
69
|
+
|
|
70
|
+
def clear_status(self):
|
|
71
|
+
status_file = self.get_status_file_path()
|
|
72
|
+
if status_file and os.path.exists(status_file):
|
|
73
|
+
os.remove(status_file)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from ara_cli.error_handler import AraError
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AgentWorkspaceManager:
|
|
7
|
+
"""Manages workspace directories for agent execution."""
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def determine_agent_workspace(chat_instance, artefact_classifier=None, artefact_name=None):
|
|
11
|
+
"""
|
|
12
|
+
Determines the appropriate workspace directory for agent logs and data.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
chat_instance: The Chat instance
|
|
16
|
+
artefact_classifier: Optional artefact classifier (e.g., 'feature')
|
|
17
|
+
artefact_name: Optional artefact name
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
str: Absolute path to the agent workspace directory (for logs)
|
|
21
|
+
"""
|
|
22
|
+
base_directory = os.path.dirname(chat_instance.chat_name)
|
|
23
|
+
|
|
24
|
+
if artefact_classifier and artefact_name:
|
|
25
|
+
# Use artefact-specific workspace for logs
|
|
26
|
+
from ara_cli.classifier import Classifier
|
|
27
|
+
classifier_dir = Classifier.get_sub_directory(artefact_classifier)
|
|
28
|
+
if not classifier_dir:
|
|
29
|
+
raise AraError(f"Unknown classifier: {artefact_classifier}")
|
|
30
|
+
|
|
31
|
+
workspace_dir = os.path.join(
|
|
32
|
+
base_directory,
|
|
33
|
+
"ara",
|
|
34
|
+
classifier_dir,
|
|
35
|
+
f"{artefact_name}.data"
|
|
36
|
+
)
|
|
37
|
+
else:
|
|
38
|
+
# Use chat-specific workspace for logs
|
|
39
|
+
chat_name_without_ext = os.path.splitext(
|
|
40
|
+
os.path.basename(chat_instance.chat_name))[0]
|
|
41
|
+
workspace_dir = os.path.join(
|
|
42
|
+
base_directory,
|
|
43
|
+
"ara",
|
|
44
|
+
f"{chat_name_without_ext}"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Ensure workspace directory exists
|
|
48
|
+
os.makedirs(workspace_dir, exist_ok=True)
|
|
49
|
+
return os.path.abspath(workspace_dir)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def determine_base_work_dir(chat_instance):
|
|
53
|
+
"""
|
|
54
|
+
Determines the base working directory (project root).
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
chat_instance: The Chat instance
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
str: Absolute path to the project root directory
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
return os.path.dirname("./")
|
|
64
|
+
# The bwd should be the project root, not inside ara/
|
|
65
|
+
chat_dir = os.path.dirname(chat_instance.chat_name)
|
|
66
|
+
|
|
67
|
+
# Find project root by looking for 'ara' directory
|
|
68
|
+
current_dir = chat_dir
|
|
69
|
+
while True:
|
|
70
|
+
if os.path.isdir(os.path.join(current_dir, "ara")):
|
|
71
|
+
return os.path.abspath(current_dir)
|
|
72
|
+
parent_dir = os.path.dirname(current_dir)
|
|
73
|
+
if parent_dir == current_dir: # Reached filesystem root
|
|
74
|
+
# Fallback to chat directory if no 'ara' folder found
|
|
75
|
+
return os.path.abspath(chat_dir)
|
|
76
|
+
current_dir = parent_dir
|
ara_cli/directory_navigator.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import sys
|
|
2
3
|
from os.path import join, exists, isdir, dirname, basename
|
|
3
4
|
# from ara_cli.directory_searcher import DirectorySearcher
|
|
4
5
|
|
|
@@ -23,7 +24,8 @@ class DirectoryNavigator:
|
|
|
23
24
|
return original_directory
|
|
24
25
|
|
|
25
26
|
current_directory = original_directory
|
|
26
|
-
|
|
27
|
+
# Ensure loop breaks at root
|
|
28
|
+
while current_directory != dirname(current_directory):
|
|
27
29
|
potential_path = join(current_directory, self.target_directory)
|
|
28
30
|
if self.exists(potential_path):
|
|
29
31
|
os.chdir(potential_path)
|
|
@@ -31,7 +33,8 @@ class DirectoryNavigator:
|
|
|
31
33
|
current_directory = dirname(current_directory)
|
|
32
34
|
|
|
33
35
|
# If the loop completes, the target directory was not found
|
|
34
|
-
user_input = input(
|
|
36
|
+
user_input = input(
|
|
37
|
+
f"Unable to locate the '{self.target_directory}' directory. Do you want to create an 'ara' folder in the working directory? (y/N): ").strip().lower()
|
|
35
38
|
|
|
36
39
|
if user_input == '' or user_input == 'y':
|
|
37
40
|
ara_folder_path = join(original_directory, 'ara')
|
|
@@ -40,7 +43,8 @@ class DirectoryNavigator:
|
|
|
40
43
|
os.chdir(ara_folder_path)
|
|
41
44
|
return original_directory
|
|
42
45
|
else:
|
|
43
|
-
print(
|
|
46
|
+
print(
|
|
47
|
+
f"Unable to locate the '{self.target_directory}' directory and user declined to create 'ara' folder.")
|
|
44
48
|
sys.exit(0)
|
|
45
49
|
|
|
46
50
|
def navigate_to_relative(self, relative_path):
|
|
@@ -56,7 +60,36 @@ class DirectoryNavigator:
|
|
|
56
60
|
if self.exists(path):
|
|
57
61
|
os.chdir(path)
|
|
58
62
|
else:
|
|
59
|
-
raise Exception(
|
|
63
|
+
raise Exception(
|
|
64
|
+
f"Unable to navigate to '{relative_path}' relative to the target directory.")
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
def find_ara_directory_root():
|
|
68
|
+
"""Find the root ara directory by traversing up the directory tree."""
|
|
69
|
+
current_dir = os.getcwd()
|
|
70
|
+
|
|
71
|
+
# Check if we're already inside an ara directory structure
|
|
72
|
+
path_parts = current_dir.split(os.sep)
|
|
73
|
+
|
|
74
|
+
# Look for 'ara' in the path parts
|
|
75
|
+
if 'ara' in path_parts:
|
|
76
|
+
ara_index = path_parts.index('ara')
|
|
77
|
+
# Reconstruct path up to and including 'ara'
|
|
78
|
+
ara_root_parts = path_parts[:ara_index + 1]
|
|
79
|
+
potential_ara_root = os.sep.join(ara_root_parts)
|
|
80
|
+
if os.path.exists(potential_ara_root) and os.path.isdir(potential_ara_root):
|
|
81
|
+
return potential_ara_root
|
|
82
|
+
|
|
83
|
+
# If not inside ara directory, check current directory and parents
|
|
84
|
+
check_dir = current_dir
|
|
85
|
+
# Stop at filesystem root
|
|
86
|
+
while check_dir != os.path.dirname(check_dir):
|
|
87
|
+
ara_path = os.path.join(check_dir, 'ara')
|
|
88
|
+
if os.path.exists(ara_path) and os.path.isdir(ara_path):
|
|
89
|
+
return ara_path
|
|
90
|
+
check_dir = os.path.dirname(check_dir)
|
|
91
|
+
|
|
92
|
+
return None
|
|
60
93
|
|
|
61
94
|
# debug version
|
|
62
95
|
# def get_ara_directory(self):
|
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
### COMMANDS FOR ...
|
|
2
2
|
Your job is now:
|
|
3
|
-
*
|
|
4
|
-
* ...
|
|
5
|
-
|
|
6
|
-
* return your results in the following format, ensuring your generated code blocks are not just code snippets but at complete method levels. Use for every single generated code block this format:
|
|
7
|
-
```python
|
|
8
|
-
# [ ] extract
|
|
9
|
-
# filename: {path/filename}.py
|
|
10
|
-
{python code}
|
|
11
|
-
```
|
|
12
|
-
* the extract and filename statements are only allowed once per code block
|
|
13
|
-
|
|
14
|
-
* in case you think information is missing in order to generate a suffiently precise formulation, return a warning "WARNING: information is missing to correctly fullfill the job!" and then explain what kind of information you think is missing and how I could easily retrieve it.
|
|
3
|
+
* <main list for mandotory commands>
|
|
4
|
+
* ...
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# general file generation and file extract instructions
|
|
2
|
+
* return only full copy pastable file content using this markdown codeblock format with 5 backticks:
|
|
3
|
+
`````
|
|
4
|
+
# [ ] extract
|
|
5
|
+
# filename: <absolute filepath>/<filename>.<file_extension>
|
|
6
|
+
{valid file content depending on the given file_extension}
|
|
7
|
+
`````
|
|
8
|
+
|
|
9
|
+
* The extract and filename statements are only allowed once per markdown code block
|
|
10
|
+
* The first character of the first line inside your code block must be '#' and the first character of the second line inside your code block must be '#'
|
|
11
|
+
* replace the '# [ ] extract' statement of the template with '# [x] extract' in your response
|
|
12
|
+
* in case of files get deprecated give me a list of files that can be safely deleted
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# general markdown file generation and file extract instructions
|
|
2
|
+
* return full copy pastable file content using a markdown code block with 5-backticks:
|
|
3
|
+
`````
|
|
4
|
+
# [ ] extract
|
|
5
|
+
# filename: <filepath>/<filename>.md
|
|
6
|
+
{markdown formatted text}
|
|
7
|
+
`````
|
|
8
|
+
* The extract and filename statements are only allowed once per markdown code block
|
|
9
|
+
* The first character of the first line inside your code block must be '#' and the first character of the second line inside your code block must be '#'
|
|
10
|
+
* replace the '# [ ] extract' statement of the template with '# [x] extract' in your response
|
|
11
|
+
* in case of files get deprecated give me a list of files that can be safely deleted
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# general python code file generation and file extract instructions
|
|
2
|
+
* return only full copy pastable file content using this markdown codeblock format:
|
|
3
|
+
|
|
4
|
+
```python
|
|
5
|
+
# [ ] extract
|
|
6
|
+
# filename: src/{filename}.py
|
|
7
|
+
{python code}
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
* The extract and filename statements are only allowed once per markdown code block
|
|
11
|
+
* The first character of the first line inside your code block must be '#' and the first character of the second line inside your code block must be '#'
|
|
12
|
+
* replace the '# [ ] extract' statement of the template with '# [x] extract' in your response
|
|
13
|
+
* in case of files get deprecated give me a list of files that can be safely deleted
|
ara_cli/templates/prompt-modules/commands/feature_add_or_modifiy_specified_behavior.commands.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# COMMANDS FOR ADDING OR MODIFYING EXISTING SPECIFIED BEHAVIOR
|
|
2
|
+
|
|
3
|
+
**At first**:
|
|
4
|
+
|
|
5
|
+
Check if a set of feature files is given
|
|
6
|
+
|
|
7
|
+
* In case no feature files are given:
|
|
8
|
+
* Stop immediately and respond with: "Error in prompt context: no feature files are given as already specified application behavior"
|
|
9
|
+
|
|
10
|
+
* Else:
|
|
11
|
+
* Continue following the given instructions
|
|
12
|
+
|
|
13
|
+
# Instructions
|
|
14
|
+
Your job is now:
|
|
15
|
+
* Silently analyze the given feature files and the specified behavior.
|
|
16
|
+
* Silently analyze the additionally given information about new wanted behavior or changes of existing behavior
|
|
17
|
+
* Develop adaptation strategies that minimize feature file changes with respect to any given already existing feature files, prefer reusing and adapting existing formulations/scenarios and steps over completely new formulations
|
|
18
|
+
* Now formulate to fully cover the new or changed behavior (one, two or many changed or new feature files)
|
|
19
|
+
|
|
20
|
+
Follow these feature file quality rules:
|
|
21
|
+
* Each feature file should not consist of more than max 3 scenarios, each feature file should follow the single responsibility principle as well as the feature file formulations should follow the separation of concerns of feature files that fully cover the human user observable behavior described in the specification notes. Consider in your formulation of the Gherkin feature files that, when implementing the graphical user interfaces, the full functionality of the Python package Streamlit can be utilized.
|
|
22
|
+
* Follow strictly the given feature file format in order to structure your feature files.
|
|
23
|
+
* You are allowed to use scenario outlines where useful. But in case they are not helpful in order to increase the readability you can just use standard scenario formulations.
|
|
24
|
+
|
|
25
|
+
* Wrap and return the formulated feature files as full copy pastable file content in the following format as markdown code block:
|
|
26
|
+
|
|
27
|
+
```artefact
|
|
28
|
+
# [ ] extract
|
|
29
|
+
# filename: ara/features/{filename}.feature
|
|
30
|
+
{formulation, with the valid feature file structure following the given feature files as reference}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
* The extract and filename statements are only allowed once per markdown code block
|
|
34
|
+
* The first character of the first line inside your code block must be '#' and the first character of the second line inside your code block must be '#'
|
|
35
|
+
* replace the '# [ ] extract' statement of the template with '# [x] extract' in your response
|
|
36
|
+
* in case of files get deprecated give me a list of files that can be safely deleted
|
ara_cli/templates/prompt-modules/commands/feature_generate_initial_specified_bevahior.commands.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# COMMANDS FOR INITIALLY SPECIFYING APPLICATION BEHAVIOR USING FEATURE FILES
|
|
2
|
+
|
|
3
|
+
* Given a description of the wanted application behavior as bullet point list, specification document, ...
|
|
4
|
+
|
|
5
|
+
* And given this feature template with placeholders in <...>
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
@creator_Egermeier
|
|
9
|
+
Feature: <descriptive title>
|
|
10
|
+
|
|
11
|
+
As a <user>
|
|
12
|
+
I want to <do something | need something>
|
|
13
|
+
So that <I can achieve something>
|
|
14
|
+
|
|
15
|
+
Contributes to <here comes your parent artefact> <here comes your classifier of the parent artefact>
|
|
16
|
+
|
|
17
|
+
Description: <further optional description to understand
|
|
18
|
+
the rule, no format defined, the example artefact is only a placeholder>
|
|
19
|
+
|
|
20
|
+
Scenario: <descriptive scenario title>
|
|
21
|
+
Given <precondition>
|
|
22
|
+
When <action>
|
|
23
|
+
Then <expected result>
|
|
24
|
+
|
|
25
|
+
Scenario Outline: <descriptive scenario title>
|
|
26
|
+
Given <precondition>
|
|
27
|
+
When <action>
|
|
28
|
+
Then <expected result>
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
| descriptive scenario title | precondition | action | expected result |
|
|
32
|
+
| <example title 1> | <example precond. 1> | <example action 1> | <example result 1> |
|
|
33
|
+
| <example title 2> | <example precond. 2> | <example action 2> | <example result 2> |
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
# Instructions
|
|
37
|
+
* Now formulate a set (one, two or many, each feature file should not consist of more than max 3 scenarios
|
|
38
|
+
* Each feature file should follow the single responsibility principle as well as the feature file formulations should follow the separation of concerns) of feature files that fully cover the human user observable behavior described in the specification notes.
|
|
39
|
+
* Consider in your formulation of the Gherkin feature files when specifying the behavior of graphical user interfaces: Describe the behavior of the graphical user interfaces so that I can clearly imagine both how they work and their visual look and feel.
|
|
40
|
+
* Follow strictly the given template format in order to structure your feature files. You are allowed to use scenario outlines where useful. But in case they are not helpful in order to increase the readability you can just use standard scenario formulations.
|
|
41
|
+
|
|
42
|
+
* Wrap and return the formulated feature files as full copy pastable file content in the following format as markdown code block:
|
|
43
|
+
|
|
44
|
+
```artefact
|
|
45
|
+
# [ ] extract
|
|
46
|
+
# filename: ara/features/{filename}.feature
|
|
47
|
+
{formulation, with the valid feature file structure as given by the feature gherkin template}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
* The extract and filename statements are only allowed once per markdown code block
|
|
51
|
+
* The first character of the first line inside your code block must be '#' and the first character of the second line inside your code block must be '#'
|
|
52
|
+
* replace the '# [ ] extract' statement of the template with '# [x] extract' in your response
|
|
53
|
+
* in case of files get deprecated give me a list of files that can be safely deleted
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Tech Stack Prompt Template Transformer
|
|
2
|
+
|
|
3
|
+
## PROMPT:
|
|
4
|
+
You are a prompt template transformation specialist. Your task is to transform Python-specific prompt templates into equivalent templates for a different technology stack while maintaining the same structure, intent, and quality standards.
|
|
5
|
+
|
|
6
|
+
### INPUT REQUIREMENTS:
|
|
7
|
+
1. **Target Technology Stack** (MANDATORY): The technology stack to transform to (e.g., 'C#', 'Java', 'React', 'TypeScript', 'Go', 'Rust', etc.)
|
|
8
|
+
2. **Source Prompt Templates** (MANDATORY): One or more Python prompt templates to transform
|
|
9
|
+
|
|
10
|
+
### TRANSFORMATION RULES:
|
|
11
|
+
1. **Preserve Structure and Intent**:
|
|
12
|
+
- Maintain the same logical flow and purpose of each prompt template
|
|
13
|
+
- Keep all sections and their hierarchical organization
|
|
14
|
+
- Preserve the extract/filename format for code generation
|
|
15
|
+
|
|
16
|
+
2. **Technology-Specific Adaptations**:
|
|
17
|
+
- Replace Python-specific references with target technology equivalents
|
|
18
|
+
- Update file extensions (.py → appropriate extension for target stack)
|
|
19
|
+
- Adapt coding standards (PEP8 → target language conventions)
|
|
20
|
+
- Replace Python packages with target language equivalents
|
|
21
|
+
- Update testing frameworks (pytest/behave → target language testing tools)
|
|
22
|
+
- Adapt documentation styles (numpy docstrings → target language documentation)
|
|
23
|
+
- Update logging approaches to target language standards
|
|
24
|
+
- Adjust line/method/class length limits based on target language best practices. Prefer lower length limits.
|
|
25
|
+
|
|
26
|
+
3. **Naming Convention**:
|
|
27
|
+
- Prefix each transformed template filename with the target technology
|
|
28
|
+
- Example: `python_bug_fixing_code.commands.md` → `csharp_bug_fixing_code.commands.md`
|
|
29
|
+
|
|
30
|
+
4. **Output Format**:
|
|
31
|
+
- Return each transformed template as a complete, copy-pastable markdown file in 5-backticks
|
|
32
|
+
- The first character of the first line inside your code block must be '#' and the first character of the second line inside your code block must be '#'
|
|
33
|
+
- Use this format for each transformed template:
|
|
34
|
+
|
|
35
|
+
`````markdown
|
|
36
|
+
# [ ] extract
|
|
37
|
+
# filename: ara/.araconfig/custom-prompt-modules/commands/{technology}_{original_template_name}
|
|
38
|
+
{transformed template content}
|
|
39
|
+
`````
|
|
40
|
+
|
|
41
|
+
5. Markdown code block handling in prompt templates
|
|
42
|
+
The first and the second line of the Markdown code blocks used in the prompt templates serve as extraction control commands. the '#' tags in the first and second line of the code blocks must not be replaced by any other symbols, independent of the technology for which the markdown code block response is defined
|
|
43
|
+
|
|
44
|
+
6. **Technology Mapping Guidelines**:
|
|
45
|
+
**For C#/.NET:**
|
|
46
|
+
- PEP8 → C# Coding Conventions (Microsoft guidelines)
|
|
47
|
+
- pytest → NUnit/xUnit/MSTest
|
|
48
|
+
- behave → SpecFlow
|
|
49
|
+
- unittest.mock → Moq/NSubstitute
|
|
50
|
+
- numpy docstrings → XML documentation comments
|
|
51
|
+
- logging package → ILogger/Serilog/NLog
|
|
52
|
+
|
|
53
|
+
**For Java:**
|
|
54
|
+
- PEP8 → Java Code Conventions (Oracle/Google style)
|
|
55
|
+
- pytest → JUnit/TestNG
|
|
56
|
+
- behave → Cucumber-JVM
|
|
57
|
+
- unittest.mock → Mockito/EasyMock
|
|
58
|
+
- numpy docstrings → Javadoc
|
|
59
|
+
- logging package → SLF4J/Log4j
|
|
60
|
+
|
|
61
|
+
**For JavaScript/TypeScript:**
|
|
62
|
+
- PEP8 → ESLint/Prettier standards
|
|
63
|
+
- pytest → Jest/Mocha/Vitest
|
|
64
|
+
- behave → Cucumber.js, Selenium
|
|
65
|
+
- unittest.mock → Jest mocks/Sinon
|
|
66
|
+
- numpy docstrings → JSDoc/TSDoc
|
|
67
|
+
- logging package → Winston/Bunyan/Pino
|
|
68
|
+
|
|
69
|
+
**For React:**
|
|
70
|
+
- Include React-specific patterns (components, hooks, state management)
|
|
71
|
+
- pytest → Jest/React Testing Library
|
|
72
|
+
- behave → Selenium
|
|
73
|
+
- Add component testing guidelines
|
|
74
|
+
- Include JSX/TSX specific rules
|
|
75
|
+
|
|
76
|
+
7. **Preserve Key Constraints**:
|
|
77
|
+
- Maintain separation of concerns and single responsibility principles
|
|
78
|
+
- Keep modular/extensible design requirements
|
|
79
|
+
- Preserve testability requirements
|
|
80
|
+
- Maintain observability/logging requirements
|
|
81
|
+
|
|
82
|
+
### VALIDATION:
|
|
83
|
+
- Ensure all Python-specific references are properly transformed
|
|
84
|
+
- Verify file paths and extensions match target technology conventions
|
|
85
|
+
- Confirm testing and mocking frameworks are appropriate for target stack
|
|
86
|
+
- Check that documentation styles match target language standards
|
|
87
|
+
|
|
88
|
+
### OUTPUT SPECIFICATION:
|
|
89
|
+
- Replace '# [ ] extract' with '# [x] extract' in all output blocks
|
|
90
|
+
- Ensure each template is complete and ready for extraction
|
|
91
|
+
- Include a summary of key transformations made for each template
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
**Begin transformation after receiving target technology stack and source templates.**
|