ara-cli 0.1.9.69__py3-none-any.whl → 0.1.10.8__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.

Files changed (150) hide show
  1. ara_cli/__init__.py +18 -2
  2. ara_cli/__main__.py +248 -62
  3. ara_cli/ara_command_action.py +155 -86
  4. ara_cli/ara_config.py +226 -80
  5. ara_cli/ara_subcommands/__init__.py +0 -0
  6. ara_cli/ara_subcommands/autofix.py +26 -0
  7. ara_cli/ara_subcommands/chat.py +27 -0
  8. ara_cli/ara_subcommands/classifier_directory.py +16 -0
  9. ara_cli/ara_subcommands/common.py +100 -0
  10. ara_cli/ara_subcommands/create.py +75 -0
  11. ara_cli/ara_subcommands/delete.py +22 -0
  12. ara_cli/ara_subcommands/extract.py +22 -0
  13. ara_cli/ara_subcommands/fetch_templates.py +14 -0
  14. ara_cli/ara_subcommands/list.py +65 -0
  15. ara_cli/ara_subcommands/list_tags.py +25 -0
  16. ara_cli/ara_subcommands/load.py +48 -0
  17. ara_cli/ara_subcommands/prompt.py +136 -0
  18. ara_cli/ara_subcommands/read.py +47 -0
  19. ara_cli/ara_subcommands/read_status.py +20 -0
  20. ara_cli/ara_subcommands/read_user.py +20 -0
  21. ara_cli/ara_subcommands/reconnect.py +27 -0
  22. ara_cli/ara_subcommands/rename.py +22 -0
  23. ara_cli/ara_subcommands/scan.py +14 -0
  24. ara_cli/ara_subcommands/set_status.py +22 -0
  25. ara_cli/ara_subcommands/set_user.py +22 -0
  26. ara_cli/ara_subcommands/template.py +16 -0
  27. ara_cli/artefact_autofix.py +649 -68
  28. ara_cli/artefact_creator.py +8 -11
  29. ara_cli/artefact_deleter.py +2 -4
  30. ara_cli/artefact_fuzzy_search.py +22 -10
  31. ara_cli/artefact_link_updater.py +4 -4
  32. ara_cli/artefact_lister.py +29 -55
  33. ara_cli/artefact_models/artefact_data_retrieval.py +23 -0
  34. ara_cli/artefact_models/artefact_load.py +11 -3
  35. ara_cli/artefact_models/artefact_model.py +146 -39
  36. ara_cli/artefact_models/artefact_templates.py +70 -44
  37. ara_cli/artefact_models/businessgoal_artefact_model.py +23 -25
  38. ara_cli/artefact_models/epic_artefact_model.py +34 -26
  39. ara_cli/artefact_models/feature_artefact_model.py +203 -64
  40. ara_cli/artefact_models/keyfeature_artefact_model.py +21 -24
  41. ara_cli/artefact_models/serialize_helper.py +1 -1
  42. ara_cli/artefact_models/task_artefact_model.py +83 -15
  43. ara_cli/artefact_models/userstory_artefact_model.py +37 -27
  44. ara_cli/artefact_models/vision_artefact_model.py +23 -42
  45. ara_cli/artefact_reader.py +92 -91
  46. ara_cli/artefact_renamer.py +8 -4
  47. ara_cli/artefact_scan.py +66 -3
  48. ara_cli/chat.py +622 -162
  49. ara_cli/chat_agent/__init__.py +0 -0
  50. ara_cli/chat_agent/agent_communicator.py +62 -0
  51. ara_cli/chat_agent/agent_process_manager.py +211 -0
  52. ara_cli/chat_agent/agent_status_manager.py +73 -0
  53. ara_cli/chat_agent/agent_workspace_manager.py +76 -0
  54. ara_cli/commands/__init__.py +0 -0
  55. ara_cli/commands/command.py +7 -0
  56. ara_cli/commands/extract_command.py +15 -0
  57. ara_cli/commands/load_command.py +65 -0
  58. ara_cli/commands/load_image_command.py +34 -0
  59. ara_cli/commands/read_command.py +117 -0
  60. ara_cli/completers.py +144 -0
  61. ara_cli/directory_navigator.py +37 -4
  62. ara_cli/error_handler.py +134 -0
  63. ara_cli/file_classifier.py +6 -5
  64. ara_cli/file_lister.py +1 -1
  65. ara_cli/file_loaders/__init__.py +0 -0
  66. ara_cli/file_loaders/binary_file_loader.py +33 -0
  67. ara_cli/file_loaders/document_file_loader.py +34 -0
  68. ara_cli/file_loaders/document_reader.py +245 -0
  69. ara_cli/file_loaders/document_readers.py +233 -0
  70. ara_cli/file_loaders/file_loader.py +50 -0
  71. ara_cli/file_loaders/file_loaders.py +123 -0
  72. ara_cli/file_loaders/image_processor.py +89 -0
  73. ara_cli/file_loaders/markdown_reader.py +75 -0
  74. ara_cli/file_loaders/text_file_loader.py +187 -0
  75. ara_cli/global_file_lister.py +51 -0
  76. ara_cli/list_filter.py +1 -1
  77. ara_cli/output_suppressor.py +1 -1
  78. ara_cli/prompt_extractor.py +215 -88
  79. ara_cli/prompt_handler.py +521 -134
  80. ara_cli/prompt_rag.py +2 -2
  81. ara_cli/tag_extractor.py +83 -38
  82. ara_cli/template_loader.py +245 -0
  83. ara_cli/template_manager.py +18 -13
  84. ara_cli/templates/prompt-modules/commands/empty.commands.md +2 -12
  85. ara_cli/templates/prompt-modules/commands/extract_general.commands.md +12 -0
  86. ara_cli/templates/prompt-modules/commands/extract_markdown.commands.md +11 -0
  87. ara_cli/templates/prompt-modules/commands/extract_python.commands.md +13 -0
  88. ara_cli/templates/prompt-modules/commands/feature_add_or_modifiy_specified_behavior.commands.md +36 -0
  89. ara_cli/templates/prompt-modules/commands/feature_generate_initial_specified_bevahior.commands.md +53 -0
  90. ara_cli/templates/prompt-modules/commands/prompt_template_tech_stack_transformer.commands.md +95 -0
  91. ara_cli/templates/prompt-modules/commands/python_bug_fixing_code.commands.md +34 -0
  92. ara_cli/templates/prompt-modules/commands/python_generate_code.commands.md +27 -0
  93. ara_cli/templates/prompt-modules/commands/python_refactoring_code.commands.md +39 -0
  94. ara_cli/templates/prompt-modules/commands/python_step_definitions_generation_and_fixing.commands.md +40 -0
  95. ara_cli/templates/prompt-modules/commands/python_unittest_generation_and_fixing.commands.md +48 -0
  96. ara_cli/update_config_prompt.py +9 -3
  97. ara_cli/version.py +1 -1
  98. ara_cli-0.1.10.8.dist-info/METADATA +241 -0
  99. ara_cli-0.1.10.8.dist-info/RECORD +193 -0
  100. tests/test_ara_command_action.py +73 -59
  101. tests/test_ara_config.py +341 -36
  102. tests/test_artefact_autofix.py +1060 -0
  103. tests/test_artefact_link_updater.py +3 -3
  104. tests/test_artefact_lister.py +52 -132
  105. tests/test_artefact_renamer.py +2 -2
  106. tests/test_artefact_scan.py +327 -33
  107. tests/test_chat.py +2063 -498
  108. tests/test_file_classifier.py +24 -1
  109. tests/test_file_creator.py +3 -5
  110. tests/test_file_lister.py +1 -1
  111. tests/test_global_file_lister.py +131 -0
  112. tests/test_list_filter.py +2 -2
  113. tests/test_prompt_handler.py +746 -0
  114. tests/test_tag_extractor.py +19 -13
  115. tests/test_template_loader.py +192 -0
  116. tests/test_template_manager.py +5 -4
  117. tests/test_update_config_prompt.py +2 -2
  118. ara_cli/ara_command_parser.py +0 -327
  119. ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +0 -27
  120. ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -30
  121. ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -9
  122. ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -17
  123. ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -14
  124. ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -102
  125. ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -20
  126. ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -13
  127. ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -20
  128. ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -18
  129. ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -43
  130. ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -13
  131. ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -15
  132. ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -9
  133. ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -15
  134. ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -19
  135. ara_cli/templates/template.businessgoal +0 -10
  136. ara_cli/templates/template.capability +0 -10
  137. ara_cli/templates/template.epic +0 -15
  138. ara_cli/templates/template.example +0 -6
  139. ara_cli/templates/template.feature +0 -26
  140. ara_cli/templates/template.issue +0 -14
  141. ara_cli/templates/template.keyfeature +0 -15
  142. ara_cli/templates/template.task +0 -6
  143. ara_cli/templates/template.userstory +0 -17
  144. ara_cli/templates/template.vision +0 -14
  145. ara_cli-0.1.9.69.dist-info/METADATA +0 -16
  146. ara_cli-0.1.9.69.dist-info/RECORD +0 -158
  147. tests/test_ara_autofix.py +0 -219
  148. {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.10.8.dist-info}/WHEEL +0 -0
  149. {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.10.8.dist-info}/entry_points.txt +0 -0
  150. {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.10.8.dist-info}/top_level.txt +0 -0
@@ -2,17 +2,19 @@ from os.path import join
2
2
  import os
3
3
  import sys
4
4
  import json
5
+ from ara_cli.error_handler import AraError
6
+ from ara_cli.error_handler import handle_errors, AraValidationError
5
7
  from ara_cli.output_suppressor import suppress_stdout
6
8
  from ara_cli.artefact_fuzzy_search import suggest_close_name_matches
7
- from . import whitelisted_commands
9
+ from . import whitelisted_commands, error_handler
8
10
 
9
11
 
10
12
  def check_validity(condition, error_message):
11
13
  if not condition:
12
- print(error_message)
13
- sys.exit(1)
14
+ raise AraValidationError(error_message)
14
15
 
15
16
 
17
+ @handle_errors(context="create action", error_handler=error_handler)
16
18
  def create_action(args):
17
19
  from ara_cli.artefact_creator import ArtefactCreator
18
20
  from ara_cli.classifier import Classifier
@@ -33,7 +35,7 @@ def create_action(args):
33
35
  if parent_classifier and parent_name and rule:
34
36
  check_validity(Classifier.is_valid_classifier(parent_classifier), invalid_classifier_message)
35
37
  check_validity(is_valid_filename(parent_name), invalid_name_message)
36
- parent_artefact = ArtefactReader.read_single_artefact(artefact_name=parent_name, classifier=parent_classifier)
38
+ parent_artefact = ArtefactReader.read_artefact(artefact_name=parent_name, classifier=parent_classifier)
37
39
  rule = find_closest_rule(parent_artefact, rule)
38
40
  return parent_classifier, parent_name, rule
39
41
  if parent_classifier and parent_name:
@@ -62,6 +64,7 @@ def create_action(args):
62
64
  artefact_creator.run(args.parameter, args.classifier, parent_classifier, parent_name, rule)
63
65
 
64
66
 
67
+ @handle_errors(context="delete action", error_handler=error_handler)
65
68
  def delete_action(args):
66
69
  from ara_cli.artefact_deleter import ArtefactDeleter
67
70
 
@@ -69,6 +72,7 @@ def delete_action(args):
69
72
  artefact_deleter.delete(args.parameter, args.classifier, args.force)
70
73
 
71
74
 
75
+ @handle_errors(context="rename action", error_handler=error_handler)
72
76
  def rename_action(args):
73
77
  from ara_cli.artefact_renamer import ArtefactRenamer
74
78
  from ara_cli.classifier import Classifier
@@ -82,6 +86,7 @@ def rename_action(args):
82
86
  artefact_renamer.rename(args.parameter, args.aspect, args.classifier)
83
87
 
84
88
 
89
+ @handle_errors(context="rename action", error_handler=error_handler)
85
90
  def list_action(args):
86
91
  from ara_cli.artefact_lister import ArtefactLister
87
92
  from ara_cli.list_filter import ListFilter
@@ -125,12 +130,10 @@ def list_action(args):
125
130
  )
126
131
  return
127
132
 
128
- if (args.tags):
129
- artefact_lister.list_files(tags=args.tags, list_filter=list_filter)
130
- return
131
133
  artefact_lister.list_files(list_filter=list_filter)
132
134
 
133
135
 
136
+ @handle_errors(context="list-tags action", error_handler=error_handler)
134
137
  def list_tags_action(args):
135
138
  from ara_cli.tag_extractor import TagExtractor
136
139
  from ara_cli.list_filter import ListFilter
@@ -141,20 +144,29 @@ def list_tags_action(args):
141
144
  )
142
145
 
143
146
  tag_extractor = TagExtractor()
144
- tags = tag_extractor.extract_tags(
147
+ tag_groups = tag_extractor.extract_tags(
145
148
  filtered_extra_column=getattr(args, "filtered_extra_column", False),
146
149
  list_filter=list_filter
147
150
  )
148
151
 
149
152
  if args.json:
150
- output = json.dumps({"tags": tags})
153
+ all_tags = []
154
+ for group in tag_groups.values():
155
+ all_tags.extend(group)
156
+ output = json.dumps({"tags": sorted(all_tags)})
151
157
  print(output)
152
158
  return
153
159
 
154
- output = "\n".join(f"- {tag}" for tag in tags)
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)
155
166
  print(output)
156
167
 
157
168
 
169
+ @handle_errors(context="prompt action", error_handler=error_handler)
158
170
  def prompt_action(args):
159
171
  from ara_cli.classifier import Classifier
160
172
  from ara_cli.filename_validator import is_valid_filename
@@ -165,6 +177,7 @@ def prompt_action(args):
165
177
  classifier = args.classifier
166
178
  param = args.parameter
167
179
  init = args.steps
180
+ write = getattr(args, 'write', False)
168
181
 
169
182
  def handle_init():
170
183
  from ara_cli.prompt_handler import initialize_prompt_templates
@@ -192,7 +205,7 @@ def prompt_action(args):
192
205
  def handle_extract():
193
206
  from ara_cli.prompt_extractor import extract_and_save_prompt_results
194
207
  from ara_cli.update_config_prompt import update_artefact_config_prompt_files
195
- extract_and_save_prompt_results(classifier, param)
208
+ extract_and_save_prompt_results(classifier, param, write=write)
196
209
  print(f"automatic update after extract")
197
210
  update_artefact_config_prompt_files(classifier, param, automatic_update=True)
198
211
 
@@ -226,6 +239,7 @@ def prompt_action(args):
226
239
  raise ValueError(f"Unknown command '{init}' provided.")
227
240
 
228
241
 
242
+ @handle_errors(context="chat action", error_handler=error_handler)
229
243
  def chat_action(args):
230
244
  from ara_cli.chat import Chat
231
245
 
@@ -252,6 +266,60 @@ def chat_action(args):
252
266
  chat.start()
253
267
 
254
268
 
269
+ def _find_chat_file(chat_name: str) -> str | None:
270
+ """Resolves the chat file path based on common naming conventions."""
271
+ # Logic from setup_chat for finding existing files.
272
+ if os.path.exists(chat_name) and os.path.isfile(chat_name):
273
+ return chat_name
274
+
275
+ chat_name_md = f"{chat_name}.md"
276
+ if os.path.exists(chat_name_md) and os.path.isfile(chat_name_md):
277
+ return chat_name_md
278
+
279
+ chat_name_chat_md = f"{chat_name}_chat.md"
280
+ if os.path.exists(chat_name_chat_md) and os.path.isfile(chat_name_chat_md):
281
+ return chat_name_chat_md
282
+
283
+ return None
284
+
285
+
286
+ @handle_errors(context="load action", error_handler=error_handler)
287
+ def load_action(args):
288
+ from ara_cli.template_loader import TemplateLoader
289
+
290
+ chat_name = args.chat_name
291
+ template_type = args.template_type
292
+ template_name = args.template_name
293
+
294
+ chat_file_path = _find_chat_file(chat_name)
295
+
296
+ if not chat_file_path:
297
+ raise AraError(f"Chat file for '{chat_name}' not found.")
298
+
299
+ default_patterns = {
300
+ "rules": "*.rules.md",
301
+ "intention": "*.intention.md",
302
+ "commands": "*.commands.md"
303
+ }
304
+
305
+ default_pattern = default_patterns.get(template_type)
306
+
307
+ if not template_name and not default_pattern:
308
+ raise AraError(f"A template name is required for template type '{template_type}'.")
309
+
310
+ loader = TemplateLoader() # No chat instance for CLI context
311
+ success = loader.load_template(
312
+ template_name=template_name,
313
+ template_type=template_type,
314
+ chat_file_path=chat_file_path,
315
+ default_pattern=default_pattern
316
+ )
317
+
318
+ if not success:
319
+ sys.exit(1)
320
+
321
+
322
+ @handle_errors(context="template action", error_handler=error_handler)
255
323
  def template_action(args):
256
324
  from ara_cli.classifier import Classifier
257
325
  from ara_cli.template_manager import TemplatePathManager
@@ -264,6 +332,7 @@ def template_action(args):
264
332
  print(content)
265
333
 
266
334
 
335
+ @handle_errors(context="fetch-templates action", error_handler=error_handler)
267
336
  def fetch_templates_action(args):
268
337
  import shutil
269
338
  from ara_cli.ara_config import ConfigManager
@@ -293,60 +362,40 @@ def fetch_templates_action(args):
293
362
  os.makedirs(join(local_prompt_modules_dir, subdir), exist_ok=True)
294
363
 
295
364
 
365
+ @handle_errors(context="read action", error_handler=error_handler)
296
366
  def read_action(args):
297
- from ara_cli.artefact_reader import ArtefactReader
298
- from ara_cli.file_classifier import FileClassifier
367
+ from ara_cli.commands.read_command import ReadCommand
368
+ from ara_cli.list_filter import ListFilter
299
369
 
300
370
  classifier = args.classifier
301
371
  artefact_name = args.parameter
302
372
  read_mode = args.read_mode
303
373
 
304
- file_classifier = FileClassifier(os)
305
- classified_artefacts = ArtefactReader.read_artefacts()
306
- artefacts = classified_artefacts.get(classifier, [])
307
- all_artefact_names = [a.title for a in artefacts]
308
-
309
- if artefact_name not in all_artefact_names:
310
- suggest_close_name_matches(
311
- artefact_name,
312
- all_artefact_names
313
- )
314
- return
315
-
316
- target_artefact = next(filter(
317
- lambda x: x.title == artefact_name, artefacts
318
- ))
374
+ list_filter = ListFilter(
375
+ include_content=args.include_content,
376
+ exclude_content=args.exclude_content,
377
+ include_extension=args.include_extension,
378
+ exclude_extension=args.exclude_extension,
379
+ include_tags=args.include_tags,
380
+ exclude_tags=args.exclude_tags
381
+ )
319
382
 
320
- artefacts_by_classifier = {classifier: []}
383
+ command = ReadCommand(
384
+ classifier=classifier,
385
+ artefact_name=artefact_name,
386
+ read_mode=read_mode,
387
+ list_filter=list_filter
388
+ )
321
389
 
322
- match read_mode:
323
- case "branch":
324
- ArtefactReader.step_through_value_chain(
325
- artefact_name=artefact_name,
326
- classifier=classifier,
327
- artefacts_by_classifier=artefacts_by_classifier,
328
- classified_artefacts=classified_artefacts
329
- )
330
- file_classifier.print_classified_files(artefacts_by_classifier, print_content=True)
331
- case "children":
332
- artefacts = ArtefactReader.find_children(
333
- artefact_name=artefact_name,
334
- classifier=classifier,
335
- classified_artefacts=classified_artefacts
336
- )
337
- file_classifier.print_classified_files(
338
- files_by_classifier=artefacts,
339
- print_content=True
340
- )
341
- case _:
342
- artefacts_by_classifier[classifier].append(target_artefact)
343
- file_classifier.print_classified_files(artefacts_by_classifier, print_content=True)
390
+ command.execute()
344
391
 
345
392
 
393
+ @handle_errors(context="reconnect action", error_handler=error_handler)
346
394
  def reconnect_action(args):
347
395
  from ara_cli.artefact_models.artefact_load import artefact_from_content
348
396
  from ara_cli.artefact_models.artefact_model import Contribution
349
397
  from ara_cli.artefact_reader import ArtefactReader
398
+ from ara_cli.file_classifier import FileClassifier
350
399
  from ara_cli.artefact_fuzzy_search import find_closest_rule
351
400
 
352
401
  classifier = args.classifier
@@ -359,30 +408,26 @@ def reconnect_action(args):
359
408
 
360
409
  feedback_message = f"Updated contribution of {classifier} '{artefact_name}' to {parent_classifier} '{parent_name}'"
361
410
 
362
- content, artefact_info = ArtefactReader.read_artefact(
411
+ file_classifier = FileClassifier(os)
412
+ classified_file_info = file_classifier.classify_files()
413
+
414
+ artefact = ArtefactReader.read_artefact(
363
415
  artefact_name=artefact_name,
364
- classifier=classifier
416
+ classifier=classifier,
417
+ classified_file_info=classified_file_info
365
418
  )
366
- if not content:
367
- print(read_error_message)
368
- return
369
419
 
370
- parent_content, parent_info = ArtefactReader.read_artefact(
371
- artefact_name=parent_name,
372
- classifier=parent_classifier
373
- )
374
- if not parent_content:
375
- print(read_error_message)
376
- return
420
+ if not artefact:
421
+ raise AraError(read_error_message)
377
422
 
378
- artefact = artefact_from_content(
379
- content=content,
423
+ parent = ArtefactReader.read_artefact(
424
+ artefact_name=parent_name,
425
+ classifier=parent_classifier,
426
+ classified_file_info=classified_file_info
380
427
  )
381
- artefact._file_path = artefact_info["file_path"]
382
428
 
383
- parent = artefact_from_content(
384
- content=parent_content
385
- )
429
+ if not parent:
430
+ raise AraError(read_error_message)
386
431
 
387
432
  contribution = Contribution(
388
433
  artefact_name=parent.title,
@@ -390,22 +435,19 @@ def reconnect_action(args):
390
435
  )
391
436
 
392
437
  if rule:
393
- try:
394
- closest_rule = find_closest_rule(parent, rule)
395
- contribution.rule = closest_rule
396
- feedback_message += f" using rule '{closest_rule}'"
397
- except TypeError as e:
398
- print(f"{type(e).__name__}:", e)
399
- exit(1)
438
+ closest_rule = find_closest_rule(parent, rule)
439
+ contribution.rule = closest_rule
440
+ feedback_message += f" using rule '{closest_rule}'"
400
441
 
401
442
  artefact.contribution = contribution
402
- with open(artefact.file_path, 'w') as file:
443
+ with open(artefact.file_path, 'w', encoding='utf-8') as file:
403
444
  artefact_content = artefact.serialize()
404
445
  file.write(artefact_content)
405
446
 
406
447
  print(feedback_message + ".")
407
448
 
408
449
 
450
+ @handle_errors(context="read-status action", error_handler=error_handler)
409
451
  def read_status_action(args):
410
452
  from ara_cli.file_classifier import FileClassifier
411
453
  from ara_cli.artefact_models.artefact_load import artefact_from_content
@@ -419,14 +461,14 @@ def read_status_action(args):
419
461
 
420
462
  all_artefact_names = [artefact_info["title"] for artefact_info in artefact_info_dicts]
421
463
  if artefact_name not in all_artefact_names:
422
- suggest_close_name_matches(artefact_name, all_artefact_names)
464
+ suggest_close_name_matches(artefact_name, all_artefact_names, report_as_error=True)
423
465
  return
424
466
 
425
467
  artefact_info = next(filter(
426
468
  lambda x: x["title"] == artefact_name, artefact_info_dicts
427
469
  ))
428
470
 
429
- with open(artefact_info["file_path"], 'r') as file:
471
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
430
472
  content = file.read()
431
473
  artefact = artefact_from_content(content)
432
474
 
@@ -438,6 +480,7 @@ def read_status_action(args):
438
480
  print(status)
439
481
 
440
482
 
483
+ @handle_errors(context="read-user action", error_handler=error_handler)
441
484
  def read_user_action(args):
442
485
  from ara_cli.artefact_models.artefact_load import artefact_from_content
443
486
  from ara_cli.file_classifier import FileClassifier
@@ -451,14 +494,14 @@ def read_user_action(args):
451
494
 
452
495
  all_artefact_names = [artefact_info["title"] for artefact_info in artefact_info_dicts]
453
496
  if artefact_name not in all_artefact_names:
454
- suggest_close_name_matches(artefact_name, all_artefact_names)
497
+ suggest_close_name_matches(artefact_name, all_artefact_names, report_as_error=True)
455
498
  return
456
499
 
457
500
  artefact_info = next(filter(
458
501
  lambda x: x["title"] == artefact_name, artefact_info_dicts
459
502
  ))
460
503
 
461
- with open(artefact_info["file_path"], 'r') as file:
504
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
462
505
  content = file.read()
463
506
  artefact = artefact_from_content(content)
464
507
 
@@ -471,6 +514,7 @@ def read_user_action(args):
471
514
  print(f" - {tag}")
472
515
 
473
516
 
517
+ @handle_errors(context="set-status action", error_handler=error_handler)
474
518
  def set_status_action(args):
475
519
  from ara_cli.artefact_models.artefact_model import ALLOWED_STATUS_VALUES
476
520
  from ara_cli.artefact_models.artefact_load import artefact_from_content
@@ -500,19 +544,20 @@ def set_status_action(args):
500
544
  lambda x: x["title"] == artefact_name, classified_artefact_dict
501
545
  ))
502
546
 
503
- with open(artefact_info["file_path"], 'r') as file:
547
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
504
548
  content = file.read()
505
549
  artefact = artefact_from_content(content)
506
550
 
507
551
  artefact.status = new_status
508
552
 
509
553
  serialized_content = artefact.serialize()
510
- with open(f"{artefact_info['file_path']}", 'w') as file:
554
+ with open(f"{artefact_info['file_path']}", 'w', encoding='utf-8') as file:
511
555
  file.write(serialized_content)
512
556
 
513
557
  print(f"Status of task '{artefact_name}' has been updated to '{new_status}'.")
514
558
 
515
559
 
560
+ @handle_errors(context="set-user action", error_handler=error_handler)
516
561
  def set_user_action(args):
517
562
  from ara_cli.file_classifier import FileClassifier
518
563
  from ara_cli.artefact_models.artefact_load import artefact_from_content
@@ -537,7 +582,7 @@ def set_user_action(args):
537
582
  lambda x: x["title"] == artefact_name, classified_artefact_dict
538
583
  ))
539
584
 
540
- with open(artefact_info["file_path"], 'r') as file:
585
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
541
586
  content = file.read()
542
587
  artefact = artefact_from_content(content)
543
588
 
@@ -545,12 +590,13 @@ def set_user_action(args):
545
590
 
546
591
  serialized_content = artefact.serialize()
547
592
 
548
- with open(artefact_info["file_path"], 'w') as file:
593
+ with open(artefact_info["file_path"], 'w', encoding='utf-8') as file:
549
594
  file.write(serialized_content)
550
595
 
551
596
  print(f"User of task '{artefact_name}' has been updated to '{new_user}'.")
552
597
 
553
598
 
599
+ @handle_errors(context="classifier-directory action", error_handler=error_handler)
554
600
  def classifier_directory_action(args):
555
601
  from ara_cli.classifier import Classifier
556
602
 
@@ -559,6 +605,7 @@ def classifier_directory_action(args):
559
605
  print(subdirectory)
560
606
 
561
607
 
608
+ @handle_errors(context="scan action", error_handler=error_handler)
562
609
  def scan_action(args):
563
610
  from ara_cli.file_classifier import FileClassifier
564
611
  from ara_cli.artefact_scan import find_invalid_files, show_results
@@ -573,8 +620,10 @@ def scan_action(args):
573
620
  show_results(invalid_artefacts)
574
621
 
575
622
 
623
+ @handle_errors(context="autofix_action", error_handler=error_handler)
576
624
  def autofix_action(args):
577
625
  from ara_cli.artefact_autofix import parse_report, apply_autofix, read_report_file
626
+ from ara_cli.file_classifier import FileClassifier
578
627
 
579
628
  # If the user passes --non-deterministic, only_deterministic_fix becomes False.
580
629
  # If the user passes --deterministic, only_non_deterministic_fix becomes False.
@@ -591,6 +640,9 @@ def autofix_action(args):
591
640
  print("No issues found in the report. Nothing to fix.")
592
641
  return
593
642
 
643
+ file_classifier = FileClassifier(os)
644
+ classified_artefact_info = file_classifier.classify_files()
645
+
594
646
  # print("\nStarting autofix process...")
595
647
  for classifier, files in issues.items():
596
648
  print(f"\nClassifier: {classifier}")
@@ -599,9 +651,26 @@ def autofix_action(args):
599
651
  file_path,
600
652
  classifier,
601
653
  reason,
654
+ single_pass=args.single_pass,
602
655
  deterministic=run_deterministic,
603
- non_deterministic=run_non_deterministic
656
+ non_deterministic=run_non_deterministic,
657
+ classified_artefact_info=classified_artefact_info
604
658
  )
605
659
 
606
660
  print("\nAutofix process completed. Please review the changes.")
607
661
 
662
+
663
+ @handle_errors(context="extract action", error_handler=error_handler)
664
+ def extract_action(args):
665
+ from ara_cli.commands.extract_command import ExtractCommand
666
+
667
+ filename = args.filename
668
+ force = args.force
669
+ write = getattr(args, 'write', False)
670
+ command = ExtractCommand(
671
+ file_name=filename,
672
+ force=force,
673
+ write=write,
674
+ output=lambda msg: print(msg, file=sys.stdout)
675
+ )
676
+ command.execute()