ara-cli 0.1.10.0__py3-none-any.whl → 0.1.10.4__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/__main__.py +252 -97
- ara_cli/ara_command_action.py +11 -6
- ara_cli/ara_subcommands/__init__.py +0 -0
- ara_cli/ara_subcommands/autofix.py +26 -0
- ara_cli/ara_subcommands/chat.py +27 -0
- ara_cli/ara_subcommands/classifier_directory.py +16 -0
- ara_cli/ara_subcommands/common.py +100 -0
- ara_cli/ara_subcommands/create.py +75 -0
- ara_cli/ara_subcommands/delete.py +22 -0
- ara_cli/ara_subcommands/extract.py +22 -0
- ara_cli/ara_subcommands/fetch_templates.py +14 -0
- ara_cli/ara_subcommands/list.py +65 -0
- ara_cli/ara_subcommands/list_tags.py +25 -0
- ara_cli/ara_subcommands/load.py +48 -0
- ara_cli/ara_subcommands/prompt.py +136 -0
- ara_cli/ara_subcommands/read.py +47 -0
- ara_cli/ara_subcommands/read_status.py +20 -0
- ara_cli/ara_subcommands/read_user.py +20 -0
- ara_cli/ara_subcommands/reconnect.py +27 -0
- ara_cli/ara_subcommands/rename.py +22 -0
- ara_cli/ara_subcommands/scan.py +14 -0
- ara_cli/ara_subcommands/set_status.py +22 -0
- ara_cli/ara_subcommands/set_user.py +22 -0
- ara_cli/ara_subcommands/template.py +16 -0
- ara_cli/artefact_autofix.py +44 -6
- ara_cli/artefact_models/artefact_model.py +106 -25
- ara_cli/artefact_models/artefact_templates.py +18 -9
- ara_cli/artefact_models/epic_artefact_model.py +11 -2
- ara_cli/artefact_models/feature_artefact_model.py +31 -1
- ara_cli/artefact_models/userstory_artefact_model.py +15 -3
- ara_cli/artefact_scan.py +2 -2
- ara_cli/chat.py +1 -19
- ara_cli/commands/read_command.py +17 -4
- ara_cli/completers.py +144 -0
- ara_cli/file_loaders/text_file_loader.py +2 -2
- ara_cli/prompt_extractor.py +97 -79
- ara_cli/prompt_handler.py +160 -59
- ara_cli/tag_extractor.py +38 -18
- ara_cli/template_loader.py +1 -1
- ara_cli/version.py +1 -1
- {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.4.dist-info}/METADATA +2 -1
- {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.4.dist-info}/RECORD +48 -26
- tests/test_artefact_scan.py +1 -1
- tests/test_prompt_handler.py +12 -4
- tests/test_tag_extractor.py +19 -13
- ara_cli/ara_command_parser.py +0 -605
- {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.4.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.4.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.4.dist-info}/top_level.txt +0 -0
ara_cli/__main__.py
CHANGED
|
@@ -1,62 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
from ara_cli.ara_command_parser import action_parser
|
|
3
|
-
from ara_cli.error_handler import AraError
|
|
4
|
-
from ara_cli.version import __version__
|
|
5
|
-
from ara_cli.ara_command_action import (
|
|
6
|
-
create_action,
|
|
7
|
-
delete_action,
|
|
8
|
-
rename_action,
|
|
9
|
-
list_action,
|
|
10
|
-
list_tags_action,
|
|
11
|
-
prompt_action,
|
|
12
|
-
chat_action,
|
|
13
|
-
template_action,
|
|
14
|
-
fetch_templates_action,
|
|
15
|
-
read_action,
|
|
16
|
-
reconnect_action,
|
|
17
|
-
read_status_action,
|
|
18
|
-
read_user_action,
|
|
19
|
-
set_status_action,
|
|
20
|
-
set_user_action,
|
|
21
|
-
classifier_directory_action,
|
|
22
|
-
scan_action,
|
|
23
|
-
autofix_action,
|
|
24
|
-
extract_action,
|
|
25
|
-
load_action
|
|
26
|
-
)
|
|
27
|
-
from . import error_handler
|
|
28
|
-
import argcomplete
|
|
1
|
+
import typer
|
|
29
2
|
import sys
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional
|
|
30
5
|
from os import getenv
|
|
6
|
+
from ara_cli.error_handler import AraError
|
|
7
|
+
from ara_cli.version import __version__
|
|
8
|
+
from ara_cli import error_handler
|
|
9
|
+
from ara_cli.ara_subcommands.create import register as register_create_cli
|
|
10
|
+
from ara_cli.ara_subcommands.delete import register as register_delete_cli
|
|
11
|
+
from ara_cli.ara_subcommands.rename import register as register_rename_cli
|
|
12
|
+
from ara_cli.ara_subcommands.list import register as register_list_cli
|
|
13
|
+
from ara_cli.ara_subcommands.list_tags import register as register_list_tags_cli
|
|
14
|
+
from ara_cli.ara_subcommands.prompt import register as register_prompt_cli
|
|
15
|
+
from ara_cli.ara_subcommands.chat import register as register_chat_cli
|
|
16
|
+
from ara_cli.ara_subcommands.template import register as register_template_cli
|
|
17
|
+
from ara_cli.ara_subcommands.fetch_templates import register as register_fetch_templates_cli
|
|
18
|
+
from ara_cli.ara_subcommands.read import register as register_read_cli
|
|
19
|
+
from ara_cli.ara_subcommands.reconnect import register as register_reconnect_cli
|
|
20
|
+
from ara_cli.ara_subcommands.read_status import register as register_read_status_cli
|
|
21
|
+
from ara_cli.ara_subcommands.read_user import register as register_read_user_cli
|
|
22
|
+
from ara_cli.ara_subcommands.set_status import register as register_set_status_cli
|
|
23
|
+
from ara_cli.ara_subcommands.set_user import register as register_set_user_cli
|
|
24
|
+
from ara_cli.ara_subcommands.classifier_directory import register as register_classifier_directory_cli
|
|
25
|
+
from ara_cli.ara_subcommands.scan import register as register_scan_cli
|
|
26
|
+
from ara_cli.ara_subcommands.autofix import register as register_autofix_cli
|
|
27
|
+
from ara_cli.ara_subcommands.extract import register as register_extract_cli
|
|
28
|
+
from ara_cli.ara_subcommands.load import register as register_load_cli
|
|
31
29
|
|
|
32
30
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"rename": rename_action,
|
|
38
|
-
"list": list_action,
|
|
39
|
-
"list-tags": list_tags_action,
|
|
40
|
-
"prompt": prompt_action,
|
|
41
|
-
"chat": chat_action,
|
|
42
|
-
"template": template_action,
|
|
43
|
-
"fetch-templates": fetch_templates_action,
|
|
44
|
-
"read": read_action,
|
|
45
|
-
"reconnect": reconnect_action,
|
|
46
|
-
"read-status": read_status_action,
|
|
47
|
-
"read-user": read_user_action,
|
|
48
|
-
"set-status": set_status_action,
|
|
49
|
-
"set-user": set_user_action,
|
|
50
|
-
"classifier-directory": classifier_directory_action,
|
|
51
|
-
"scan": scan_action,
|
|
52
|
-
"autofix": autofix_action,
|
|
53
|
-
"extract": extract_action,
|
|
54
|
-
"load": load_action
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def handle_invalid_action(args):
|
|
59
|
-
raise AraError("Invalid action provided. Type ara -h for help", error_code=1)
|
|
31
|
+
def version_callback(value: bool):
|
|
32
|
+
if value:
|
|
33
|
+
typer.echo(f"ara {__version__}")
|
|
34
|
+
raise typer.Exit()
|
|
60
35
|
|
|
61
36
|
|
|
62
37
|
def is_debug_mode_enabled():
|
|
@@ -64,63 +39,243 @@ def is_debug_mode_enabled():
|
|
|
64
39
|
return getenv('ARA_DEBUG', '').lower() in ('1', 'true', 'yes')
|
|
65
40
|
|
|
66
41
|
|
|
67
|
-
def
|
|
68
|
-
"""Create and configure the argument parser."""
|
|
69
|
-
parser = action_parser()
|
|
70
|
-
|
|
71
|
-
# Show examples when help is called
|
|
72
|
-
if any(arg in sys.argv for arg in ["-h", "--help"]):
|
|
73
|
-
parser.add_examples = True
|
|
74
|
-
|
|
75
|
-
parser.add_argument(
|
|
76
|
-
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
parser.add_argument(
|
|
80
|
-
"--debug", action="store_true", help="Enable debug mode for detailed error output"
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
return parser
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def configure_debug_mode(args, env_debug_mode):
|
|
42
|
+
def configure_debug_mode(debug: bool, env_debug_mode: bool):
|
|
87
43
|
"""Configure debug mode based on arguments and environment."""
|
|
88
|
-
if
|
|
44
|
+
if debug or env_debug_mode:
|
|
89
45
|
error_handler.debug_mode = True
|
|
90
46
|
|
|
91
47
|
|
|
92
|
-
def
|
|
93
|
-
"""
|
|
94
|
-
|
|
48
|
+
def find_ara_directory_root():
|
|
49
|
+
"""Find the root ara directory by traversing up the directory tree."""
|
|
50
|
+
current_dir = os.getcwd()
|
|
51
|
+
|
|
52
|
+
# Check if we're already inside an ara directory structure
|
|
53
|
+
path_parts = current_dir.split(os.sep)
|
|
54
|
+
|
|
55
|
+
# Look for 'ara' in the path parts
|
|
56
|
+
if 'ara' in path_parts:
|
|
57
|
+
ara_index = path_parts.index('ara')
|
|
58
|
+
# Reconstruct path up to and including 'ara'
|
|
59
|
+
ara_root_parts = path_parts[:ara_index + 1]
|
|
60
|
+
potential_ara_root = os.sep.join(ara_root_parts)
|
|
61
|
+
if os.path.exists(potential_ara_root) and os.path.isdir(potential_ara_root):
|
|
62
|
+
return potential_ara_root
|
|
63
|
+
|
|
64
|
+
# If not inside ara directory, check current directory and parents
|
|
65
|
+
check_dir = current_dir
|
|
66
|
+
while check_dir != os.path.dirname(check_dir): # Stop at filesystem root
|
|
67
|
+
ara_path = os.path.join(check_dir, 'ara')
|
|
68
|
+
if os.path.exists(ara_path) and os.path.isdir(ara_path):
|
|
69
|
+
return ara_path
|
|
70
|
+
check_dir = os.path.dirname(check_dir)
|
|
71
|
+
|
|
72
|
+
return None
|
|
95
73
|
|
|
96
74
|
|
|
97
|
-
def
|
|
98
|
-
"""
|
|
99
|
-
|
|
100
|
-
action(args)
|
|
75
|
+
def check_ara_directory_exists():
|
|
76
|
+
"""Check if ara directory exists or if we're inside ara directory tree."""
|
|
77
|
+
return find_ara_directory_root() is not None
|
|
101
78
|
|
|
102
79
|
|
|
103
|
-
def
|
|
104
|
-
|
|
80
|
+
def prompt_create_ara_directory():
|
|
81
|
+
"""Prompt user to create ara directory and create it if confirmed."""
|
|
82
|
+
# Print the prompt message
|
|
83
|
+
print("No 'ara' directory found. Create one in the current directory? (Y/n)", end=" ", flush=True)
|
|
105
84
|
|
|
85
|
+
# Read user input
|
|
106
86
|
try:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
87
|
+
response = input().strip()
|
|
88
|
+
except (EOFError, KeyboardInterrupt):
|
|
89
|
+
typer.echo("\nOperation cancelled.")
|
|
90
|
+
raise typer.Exit(1)
|
|
91
|
+
|
|
92
|
+
if response.lower() in ('y', 'yes', ''):
|
|
93
|
+
current_dir = os.getcwd()
|
|
94
|
+
ara_path = os.path.join(current_dir, 'ara')
|
|
112
95
|
|
|
113
|
-
|
|
96
|
+
# Create ara directory structure
|
|
97
|
+
subdirectories = [
|
|
98
|
+
'businessgoals',
|
|
99
|
+
'capabilities',
|
|
100
|
+
'epics',
|
|
101
|
+
'examples',
|
|
102
|
+
'features',
|
|
103
|
+
'keyfeatures',
|
|
104
|
+
'tasks',
|
|
105
|
+
'userstories',
|
|
106
|
+
'vision'
|
|
107
|
+
]
|
|
114
108
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
try:
|
|
110
|
+
# Create main ara directory
|
|
111
|
+
os.makedirs(ara_path, exist_ok=True)
|
|
112
|
+
|
|
113
|
+
# Create subdirectories for artefact types
|
|
114
|
+
for subdir in subdirectories:
|
|
115
|
+
os.makedirs(os.path.join(ara_path, subdir), exist_ok=True)
|
|
116
|
+
|
|
117
|
+
# Create .araconfig directory
|
|
118
|
+
araconfig_path = os.path.join(ara_path, '.araconfig')
|
|
119
|
+
os.makedirs(araconfig_path, exist_ok=True)
|
|
120
|
+
|
|
121
|
+
# Create default ara_config.json using ConfigManager
|
|
122
|
+
from ara_cli.ara_config import ConfigManager, ARAconfig
|
|
123
|
+
config_file_path = os.path.join(araconfig_path, 'ara_config.json')
|
|
124
|
+
|
|
125
|
+
# Reset ConfigManager to ensure clean state
|
|
126
|
+
ConfigManager.reset()
|
|
118
127
|
|
|
119
|
-
|
|
128
|
+
# Create default config and save it
|
|
129
|
+
default_config = ARAconfig()
|
|
130
|
+
from ara_cli.ara_config import save_data
|
|
131
|
+
save_data(config_file_path, default_config)
|
|
132
|
+
|
|
133
|
+
typer.echo(f"Created ara directory structure at {ara_path}")
|
|
134
|
+
typer.echo(f"Created default configuration at {config_file_path}")
|
|
135
|
+
return True
|
|
136
|
+
|
|
137
|
+
except OSError as e:
|
|
138
|
+
typer.echo(f"Error creating ara directory: {e}", err=True)
|
|
139
|
+
raise typer.Exit(1)
|
|
140
|
+
except Exception as e:
|
|
141
|
+
typer.echo(f"Error creating configuration file: {e}", err=True)
|
|
142
|
+
raise typer.Exit(1)
|
|
143
|
+
else:
|
|
144
|
+
typer.echo("Ara directory creation cancelled.")
|
|
145
|
+
raise typer.Exit(0)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def requires_ara_directory():
|
|
149
|
+
"""Check if ara directory exists and prompt to create if not."""
|
|
150
|
+
if not check_ara_directory_exists():
|
|
151
|
+
return prompt_create_ara_directory()
|
|
152
|
+
return True
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def create_app():
|
|
156
|
+
app = typer.Typer(
|
|
157
|
+
help="""The ara cli terminal tool is a management tool for classified ara artefacts.
|
|
158
|
+
|
|
159
|
+
Valid classified artefacts are: businessgoal, vision, capability, keyfeature, feature, epic, userstory, example, feature, task.
|
|
160
|
+
|
|
161
|
+
The default ara directory structure of classified artefact of the ara cli tool is:
|
|
162
|
+
.
|
|
163
|
+
└── ara
|
|
164
|
+
├── businessgoals
|
|
165
|
+
├── capabilities
|
|
166
|
+
├── epics
|
|
167
|
+
├── examples
|
|
168
|
+
├── features
|
|
169
|
+
├── keyfeatures
|
|
170
|
+
├── tasks
|
|
171
|
+
├── userstories
|
|
172
|
+
└── vision
|
|
173
|
+
|
|
174
|
+
ara artefact handling examples:
|
|
175
|
+
> create a new artefact for e.g. a feature: ara create feature {feature_name}
|
|
176
|
+
> create a new artefact for e.g. a feature that contributes to an userstory: ara create feature {feature_name} contributes-to userstory {story_name}
|
|
177
|
+
> read an artefact and return the content as terminal output, for eg. of a task: ara read task {task_name}
|
|
178
|
+
> read an artefact and its full chain of contributions to its parents and return
|
|
179
|
+
the content as terminal output, for eg. of a task: ara read task {task_name} --branch
|
|
180
|
+
> delete an artefact for e.g. feature: ara delete feature {feature_name}
|
|
181
|
+
> rename artefact and artefact data directory for e.g. a feature: ara rename feature {initial_feature_name} {new_feature_name}
|
|
182
|
+
> create additional templates for a specific aspect (valid aspects are: customer,
|
|
183
|
+
persona, concept, technology) related to an existing artefact like a feature: ara create feature {feature_name} aspect {aspect_name}
|
|
184
|
+
> list artefact data with .md file extension ara list --data {classifier} {artefact_name} --include-extension .md
|
|
185
|
+
> list artefact data with .md and .json file extensions ara list --data {classifier} {artefact_name} --include-extension .md .json
|
|
186
|
+
> list everything but userstories ara list --exclude-extension .userstory
|
|
187
|
+
> list all existing features: ara list --include-extension .feature
|
|
188
|
+
> list all child artefacts contributing value to a parent artefact: ara list --include-content "Contributes to {name_of_parent_artefact} {ara classifier_of_parent_artefact}"
|
|
189
|
+
> list tasks which contain 'example content' ara list --include-extension .task --include-content "example content"
|
|
190
|
+
> list children artefacts of a userstory ara list --children userstory {name_of_userstory}
|
|
191
|
+
> list parent artefacts of a userstory ara list --branch userstory {name_of_userstory}
|
|
192
|
+
> list parent businessgoal artefact of a userstory ara list --branch userstory {name_of_userstory} --include-extension .businessgoal
|
|
193
|
+
> print any artefact template for e.g. a feature file template in the terminal: ara template feature
|
|
194
|
+
|
|
195
|
+
ara prompt templates examples:
|
|
196
|
+
> get and copy all prompt templates (blueprints, rules, intentions, commands
|
|
197
|
+
in the ara/.araconfig/global-prompt-modules directory: ara fetch-templates
|
|
198
|
+
|
|
199
|
+
ara chat examples:
|
|
200
|
+
> chat with ara and save the default chat.md file in the working directory: ara chat
|
|
201
|
+
> chat with ara and save the default task_chat.md file in the task.data directory: ara prompt chat task {task_name}
|
|
202
|
+
|
|
203
|
+
> initialize a macro prompt for a task: ara prompt init task {task_name}
|
|
204
|
+
> load selected templates in config_prompt_templates.md for the task {task_name}: ara prompt load task {task_name}
|
|
205
|
+
> create and send configured prompt of the task {task_name} to the configured LLM: ara prompt send task {task_name}
|
|
206
|
+
> extract the selected LLM response in task.exploration.md and save to disk: ara prompt extract task {task_name}
|
|
207
|
+
""",
|
|
208
|
+
no_args_is_help=True,
|
|
209
|
+
add_completion=True,
|
|
210
|
+
rich_markup_mode="rich"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
@app.callback(invoke_without_command=True)
|
|
214
|
+
def main(
|
|
215
|
+
ctx: typer.Context,
|
|
216
|
+
version: Optional[bool] = typer.Option(
|
|
217
|
+
None, "--version", "-v",
|
|
218
|
+
callback=version_callback,
|
|
219
|
+
is_eager=True,
|
|
220
|
+
help="Show version and exit"
|
|
221
|
+
),
|
|
222
|
+
debug: bool = typer.Option(
|
|
223
|
+
False, "--debug",
|
|
224
|
+
help="Enable debug mode for detailed error output"
|
|
225
|
+
)
|
|
226
|
+
):
|
|
227
|
+
"""The ara cli terminal tool is a management tool for classified ara artefacts."""
|
|
228
|
+
debug_mode = is_debug_mode_enabled()
|
|
229
|
+
configure_debug_mode(debug, debug_mode)
|
|
230
|
+
|
|
231
|
+
# Only show help if no subcommand is invoked
|
|
232
|
+
if ctx.invoked_subcommand is None:
|
|
233
|
+
ctx.get_help()
|
|
234
|
+
ctx.exit()
|
|
235
|
+
|
|
236
|
+
# Check for ara directory before executing any command
|
|
237
|
+
# Skip check for commands that don't require ara directory
|
|
238
|
+
commands_requiring_ara = {
|
|
239
|
+
'create', 'delete', 'rename', 'list', 'list-tags', 'prompt',
|
|
240
|
+
'read', 'reconnect', 'read-status', 'read-user', 'set-status',
|
|
241
|
+
'set-user', 'classifier-directory', 'scan', 'autofix'
|
|
242
|
+
}
|
|
120
243
|
|
|
244
|
+
if ctx.invoked_subcommand in commands_requiring_ara:
|
|
245
|
+
requires_ara_directory()
|
|
246
|
+
|
|
247
|
+
# Register all commands
|
|
248
|
+
register_create_cli(app)
|
|
249
|
+
register_delete_cli(app)
|
|
250
|
+
register_rename_cli(app)
|
|
251
|
+
register_list_cli(app)
|
|
252
|
+
register_list_tags_cli(app)
|
|
253
|
+
register_prompt_cli(app)
|
|
254
|
+
register_chat_cli(app)
|
|
255
|
+
register_template_cli(app)
|
|
256
|
+
register_fetch_templates_cli(app)
|
|
257
|
+
register_read_cli(app)
|
|
258
|
+
register_reconnect_cli(app)
|
|
259
|
+
register_read_status_cli(app)
|
|
260
|
+
register_read_user_cli(app)
|
|
261
|
+
register_set_status_cli(app)
|
|
262
|
+
register_set_user_cli(app)
|
|
263
|
+
register_classifier_directory_cli(app)
|
|
264
|
+
register_scan_cli(app)
|
|
265
|
+
register_autofix_cli(app)
|
|
266
|
+
register_extract_cli(app)
|
|
267
|
+
register_load_cli(app)
|
|
268
|
+
|
|
269
|
+
return app
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def cli():
|
|
273
|
+
app = create_app()
|
|
274
|
+
try:
|
|
275
|
+
app()
|
|
121
276
|
except KeyboardInterrupt:
|
|
122
|
-
|
|
123
|
-
|
|
277
|
+
typer.echo("\n[INFO] Operation cancelled by user", err=True)
|
|
278
|
+
raise typer.Exit(130) # Standard exit code for Ctrl+C
|
|
124
279
|
except Exception as e:
|
|
125
280
|
error_handler.handle_error(e, context="cli")
|
|
126
281
|
|
ara_cli/ara_command_action.py
CHANGED
|
@@ -130,9 +130,6 @@ def list_action(args):
|
|
|
130
130
|
)
|
|
131
131
|
return
|
|
132
132
|
|
|
133
|
-
if (args.tags):
|
|
134
|
-
artefact_lister.list_files(tags=args.tags, list_filter=list_filter)
|
|
135
|
-
return
|
|
136
133
|
artefact_lister.list_files(list_filter=list_filter)
|
|
137
134
|
|
|
138
135
|
|
|
@@ -147,17 +144,25 @@ def list_tags_action(args):
|
|
|
147
144
|
)
|
|
148
145
|
|
|
149
146
|
tag_extractor = TagExtractor()
|
|
150
|
-
|
|
147
|
+
tag_groups = tag_extractor.extract_tags(
|
|
151
148
|
filtered_extra_column=getattr(args, "filtered_extra_column", False),
|
|
152
149
|
list_filter=list_filter
|
|
153
150
|
)
|
|
154
151
|
|
|
155
152
|
if args.json:
|
|
156
|
-
|
|
153
|
+
all_tags = []
|
|
154
|
+
for group in tag_groups.values():
|
|
155
|
+
all_tags.extend(group)
|
|
156
|
+
output = json.dumps({"tags": sorted(all_tags)})
|
|
157
157
|
print(output)
|
|
158
158
|
return
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
output_lines = []
|
|
161
|
+
for key in sorted(tag_groups.keys()):
|
|
162
|
+
line = " ".join(sorted(list(tag_groups[key])))
|
|
163
|
+
output_lines.append(line)
|
|
164
|
+
|
|
165
|
+
output = "\n".join(f"- {tag}" for tag in output_lines)
|
|
161
166
|
print(output)
|
|
162
167
|
|
|
163
168
|
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from .common import MockArgs
|
|
3
|
+
from ara_cli.ara_command_action import autofix_action
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def autofix_main(
|
|
7
|
+
single_pass: bool = typer.Option(False, "--single-pass", help="Run the autofix once for every scanned file"),
|
|
8
|
+
deterministic: bool = typer.Option(False, "-d", "--deterministic", help="Run only deterministic fixes e.g Title-FileName Mismatch fix"),
|
|
9
|
+
non_deterministic: bool = typer.Option(False, "-nd", "--non-deterministic", help="Run only non-deterministic fixes")
|
|
10
|
+
):
|
|
11
|
+
"""Fix ARA tree with llm models for scanned artefacts with ara scan command."""
|
|
12
|
+
if deterministic and non_deterministic:
|
|
13
|
+
typer.echo("Error: --deterministic and --non-deterministic are mutually exclusive", err=True)
|
|
14
|
+
raise typer.Exit(1)
|
|
15
|
+
|
|
16
|
+
args = MockArgs(
|
|
17
|
+
single_pass=single_pass,
|
|
18
|
+
deterministic=deterministic,
|
|
19
|
+
non_deterministic=non_deterministic
|
|
20
|
+
)
|
|
21
|
+
autofix_action(args)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def register(parent: typer.Typer):
|
|
25
|
+
help_text = "Fix ARA tree with llm models for scanned artefacts"
|
|
26
|
+
parent.command(name="autofix", help=help_text)(autofix_main)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
from .common import MockArgs, ChatNameArgument
|
|
4
|
+
from ara_cli.ara_command_action import chat_action
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def chat_main(
|
|
8
|
+
chat_name: Optional[str] = ChatNameArgument("Optional name for a specific chat. Pass the .md file to continue an existing chat", None),
|
|
9
|
+
reset: Optional[bool] = typer.Option(None, "-r", "--reset/--no-reset", help="Reset the chat file if it exists"),
|
|
10
|
+
output_mode: bool = typer.Option(False, "--out", help="Output the contents of the chat file instead of entering interactive chat mode"),
|
|
11
|
+
append: Optional[List[str]] = typer.Option(None, "--append", help="Append strings to the chat file"),
|
|
12
|
+
restricted: Optional[bool] = typer.Option(None, "--restricted/--no-restricted", help="Start with a limited set of commands")
|
|
13
|
+
):
|
|
14
|
+
"""Command line chatbot. Chat control with SEND/s | RERUN/r | QUIT/q"""
|
|
15
|
+
args = MockArgs(
|
|
16
|
+
chat_name=chat_name,
|
|
17
|
+
reset=reset,
|
|
18
|
+
output_mode=output_mode,
|
|
19
|
+
append=append,
|
|
20
|
+
restricted=restricted
|
|
21
|
+
)
|
|
22
|
+
chat_action(args)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def register(parent: typer.Typer):
|
|
26
|
+
help_text = "Command line chatbot. Chat control with SEND/s | RERUN/r | QUIT/q"
|
|
27
|
+
parent.command(name="chat", help=help_text)(chat_main)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from .common import ClassifierEnum, MockArgs, ClassifierArgument
|
|
3
|
+
from ara_cli.ara_command_action import classifier_directory_action
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def classifier_directory_main(
|
|
7
|
+
classifier: ClassifierEnum = ClassifierArgument("Classifier of the artefact type")
|
|
8
|
+
):
|
|
9
|
+
"""Print the ara subdirectory for an artefact classifier."""
|
|
10
|
+
args = MockArgs(classifier=classifier.value)
|
|
11
|
+
classifier_directory_action(args)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def register(parent: typer.Typer):
|
|
15
|
+
help_text = "Print the ara subdirectory for an artefact classifier"
|
|
16
|
+
parent.command(name="classifier-directory", help=help_text)(classifier_directory_main)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from enum import Enum
|
|
3
|
+
import typer
|
|
4
|
+
from ara_cli.classifier import Classifier
|
|
5
|
+
from ara_cli.template_manager import SpecificationBreakdownAspects
|
|
6
|
+
from ara_cli.completers import DynamicCompleters
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Get classifiers and aspects
|
|
10
|
+
classifiers = Classifier.ordered_classifiers()
|
|
11
|
+
aspects = SpecificationBreakdownAspects.VALID_ASPECTS
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Create enums for better type safety
|
|
15
|
+
ClassifierEnum = Enum('ClassifierEnum', {c: c for c in classifiers})
|
|
16
|
+
AspectEnum = Enum('AspectEnum', {a: a for a in aspects})
|
|
17
|
+
TemplateTypeEnum = Enum('TemplateTypeEnum', {
|
|
18
|
+
'rules': 'rules',
|
|
19
|
+
'intention': 'intention',
|
|
20
|
+
'commands': 'commands',
|
|
21
|
+
'blueprint': 'blueprint'
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Create typed arguments and options with autocompletion
|
|
26
|
+
def ClassifierArgument(help_text: str, default=...):
|
|
27
|
+
"""Create a classifier argument with autocompletion."""
|
|
28
|
+
return typer.Argument(
|
|
29
|
+
default,
|
|
30
|
+
help=help_text,
|
|
31
|
+
autocompletion=DynamicCompleters.create_classifier_completer()
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def ClassifierOption(help_text: str, *names):
|
|
36
|
+
"""Create a classifier option with autocompletion."""
|
|
37
|
+
return typer.Option(
|
|
38
|
+
None,
|
|
39
|
+
*names,
|
|
40
|
+
help=help_text,
|
|
41
|
+
autocompletion=DynamicCompleters.create_classifier_completer()
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def ArtefactNameArgument(help_text: str, default=...):
|
|
46
|
+
"""Create an artefact name argument with autocompletion."""
|
|
47
|
+
return typer.Argument(
|
|
48
|
+
default,
|
|
49
|
+
help=help_text,
|
|
50
|
+
autocompletion=DynamicCompleters.create_artefact_name_completer()
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def ParentNameArgument(help_text: str):
|
|
56
|
+
"""Create a parent name argument with autocompletion."""
|
|
57
|
+
return typer.Argument(
|
|
58
|
+
help=help_text,
|
|
59
|
+
autocompletion=DynamicCompleters.create_parent_name_completer()
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def AspectArgument(help_text: str):
|
|
64
|
+
"""Create an aspect argument with autocompletion."""
|
|
65
|
+
return typer.Argument(
|
|
66
|
+
help=help_text,
|
|
67
|
+
autocompletion=DynamicCompleters.create_aspect_completer()
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def StatusArgument(help_text: str):
|
|
72
|
+
"""Create a status argument with autocompletion."""
|
|
73
|
+
return typer.Argument(
|
|
74
|
+
help=help_text,
|
|
75
|
+
autocompletion=DynamicCompleters.create_status_completer()
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def TemplateTypeArgument(help_text: str):
|
|
80
|
+
"""Create a template type argument with autocompletion."""
|
|
81
|
+
return typer.Argument(
|
|
82
|
+
help=help_text,
|
|
83
|
+
autocompletion=DynamicCompleters.create_template_type_completer()
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def ChatNameArgument(help_text: str, default=None):
|
|
88
|
+
"""Create a chat name argument with autocompletion."""
|
|
89
|
+
return typer.Argument(
|
|
90
|
+
default,
|
|
91
|
+
help=help_text,
|
|
92
|
+
autocompletion=DynamicCompleters.create_chat_file_completer()
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Mock args class to maintain compatibility with existing action functions
|
|
97
|
+
class MockArgs:
|
|
98
|
+
def __init__(self, **kwargs):
|
|
99
|
+
for key, value in kwargs.items():
|
|
100
|
+
setattr(self, key, value)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from .common import (
|
|
4
|
+
ClassifierEnum, AspectEnum, MockArgs,
|
|
5
|
+
ClassifierArgument, ArtefactNameArgument, ParentNameArgument, AspectArgument
|
|
6
|
+
)
|
|
7
|
+
from ara_cli.ara_command_action import create_action
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_contributes_to(
|
|
11
|
+
ctx: typer.Context,
|
|
12
|
+
parent_classifier: ClassifierEnum = ClassifierArgument("Classifier of the parent"),
|
|
13
|
+
parent_name: str = ParentNameArgument("Name of a parent artefact"),
|
|
14
|
+
rule: Optional[str] = typer.Option(None, "-r", "--rule", help="Rule for contribution")
|
|
15
|
+
):
|
|
16
|
+
"""Create an artefact that contributes to a parent artefact."""
|
|
17
|
+
# Get classifier and parameter from parent context
|
|
18
|
+
parent_params = ctx.parent.params
|
|
19
|
+
classifier = parent_params['classifier']
|
|
20
|
+
parameter = parent_params['parameter']
|
|
21
|
+
|
|
22
|
+
args = MockArgs(
|
|
23
|
+
classifier=classifier,
|
|
24
|
+
parameter=parameter,
|
|
25
|
+
option="contributes-to",
|
|
26
|
+
parent_classifier=parent_classifier.value,
|
|
27
|
+
parent_name=parent_name,
|
|
28
|
+
rule=rule
|
|
29
|
+
)
|
|
30
|
+
create_action(args)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def create_aspect(
|
|
34
|
+
ctx: typer.Context,
|
|
35
|
+
aspect: AspectEnum = AspectArgument("Adds additional specification breakdown aspects")
|
|
36
|
+
):
|
|
37
|
+
"""Create an artefact with additional specification breakdown aspects."""
|
|
38
|
+
# Get classifier and parameter from parent context
|
|
39
|
+
parent_params = ctx.parent.params
|
|
40
|
+
classifier = parent_params['classifier']
|
|
41
|
+
parameter = parent_params['parameter']
|
|
42
|
+
|
|
43
|
+
args = MockArgs(
|
|
44
|
+
classifier=classifier,
|
|
45
|
+
parameter=parameter,
|
|
46
|
+
option="aspect",
|
|
47
|
+
aspect=aspect.value
|
|
48
|
+
)
|
|
49
|
+
create_action(args)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def create_main(
|
|
53
|
+
ctx: typer.Context,
|
|
54
|
+
classifier: ClassifierEnum = ClassifierArgument("Classifier that also serves as file extension"),
|
|
55
|
+
parameter: str = ArtefactNameArgument("Artefact name that serves as filename")
|
|
56
|
+
):
|
|
57
|
+
"""Create a classified artefact with data directory."""
|
|
58
|
+
if ctx.invoked_subcommand is None:
|
|
59
|
+
args = MockArgs(
|
|
60
|
+
classifier=classifier.value,
|
|
61
|
+
parameter=parameter,
|
|
62
|
+
option=None
|
|
63
|
+
)
|
|
64
|
+
create_action(args)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def register(parent: typer.Typer):
|
|
68
|
+
create_app = typer.Typer(
|
|
69
|
+
help="Create a classified artefact with data directory",
|
|
70
|
+
add_completion=False # Disable completion on subcommand
|
|
71
|
+
)
|
|
72
|
+
create_app.command("contributes-to")(create_contributes_to)
|
|
73
|
+
create_app.command("aspect")(create_aspect)
|
|
74
|
+
create_app.callback(invoke_without_command=True)(create_main)
|
|
75
|
+
parent.add_typer(create_app, name="create")
|