ara-cli 0.1.9.95__tar.gz → 0.1.9.96__tar.gz

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 (177) hide show
  1. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/PKG-INFO +1 -1
  2. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/__init__.py +4 -1
  3. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/__main__.py +57 -11
  4. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/ara_command_action.py +31 -19
  5. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_autofix.py +131 -2
  6. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_creator.py +2 -7
  7. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_deleter.py +2 -4
  8. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_fuzzy_search.py +13 -6
  9. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/artefact_templates.py +3 -3
  10. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/feature_artefact_model.py +25 -0
  11. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_reader.py +4 -5
  12. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/chat.py +12 -13
  13. ara_cli-0.1.9.96/ara_cli/commands/extract_command.py +15 -0
  14. ara_cli-0.1.9.96/ara_cli/error_handler.py +134 -0
  15. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_classifier.py +3 -2
  16. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/prompt_extractor.py +1 -1
  17. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/version.py +1 -1
  18. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli.egg-info/PKG-INFO +1 -1
  19. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli.egg-info/SOURCES.txt +1 -0
  20. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_ara_command_action.py +66 -52
  21. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_artefact_autofix.py +361 -5
  22. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_chat.py +88 -6
  23. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_file_classifier.py +23 -0
  24. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_file_creator.py +3 -5
  25. ara_cli-0.1.9.95/ara_cli/commands/extract_command.py +0 -22
  26. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/MANIFEST.in +0 -0
  27. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/README.md +0 -0
  28. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/ara_command_parser.py +0 -0
  29. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/ara_config.py +0 -0
  30. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_link_updater.py +0 -0
  31. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_lister.py +0 -0
  32. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/__init__.py +0 -0
  33. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/artefact_data_retrieval.py +0 -0
  34. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/artefact_load.py +0 -0
  35. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/artefact_mapping.py +0 -0
  36. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/artefact_model.py +0 -0
  37. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/businessgoal_artefact_model.py +0 -0
  38. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/capability_artefact_model.py +0 -0
  39. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/epic_artefact_model.py +0 -0
  40. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/example_artefact_model.py +0 -0
  41. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/issue_artefact_model.py +0 -0
  42. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/keyfeature_artefact_model.py +0 -0
  43. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/serialize_helper.py +0 -0
  44. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/task_artefact_model.py +0 -0
  45. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/userstory_artefact_model.py +0 -0
  46. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_models/vision_artefact_model.py +0 -0
  47. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_renamer.py +0 -0
  48. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/artefact_scan.py +0 -0
  49. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/classifier.py +0 -0
  50. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/codefusionretriever.py +0 -0
  51. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/codehierachieretriever.py +0 -0
  52. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/commandline_completer.py +0 -0
  53. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/commands/__init__.py +0 -0
  54. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/commands/command.py +0 -0
  55. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/commands/load_command.py +0 -0
  56. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/commands/load_image_command.py +0 -0
  57. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/commands/read_command.py +0 -0
  58. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/directory_navigator.py +0 -0
  59. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_lister.py +0 -0
  60. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/__init__.py +0 -0
  61. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/binary_file_loader.py +0 -0
  62. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/document_file_loader.py +0 -0
  63. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/document_reader.py +0 -0
  64. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/document_readers.py +0 -0
  65. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/file_loader.py +0 -0
  66. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/file_loaders.py +0 -0
  67. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/image_processor.py +0 -0
  68. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/markdown_reader.py +0 -0
  69. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/file_loaders/text_file_loader.py +0 -0
  70. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/filename_validator.py +0 -0
  71. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/global_file_lister.py +0 -0
  72. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/list_filter.py +0 -0
  73. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/output_suppressor.py +0 -0
  74. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/prompt_chat.py +0 -0
  75. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/prompt_handler.py +0 -0
  76. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/prompt_rag.py +0 -0
  77. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/run_file_lister.py +0 -0
  78. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/tag_extractor.py +0 -0
  79. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/template_manager.py +0 -0
  80. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/agile.artefacts +0 -0
  81. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +0 -0
  82. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/blueprints/empty.blueprint.md +0 -0
  83. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/blueprints/task_todo_list_C4_architecture_analysis.blueprint.md +0 -0
  84. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -0
  85. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/architecture_C4_analysis.commands.md +0 -0
  86. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/architecture_radon_cc_score.commands.md +0 -0
  87. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/architecture_radon_halstead_v.commands.md +0 -0
  88. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/architecture_radon_maintainability_score.commands.md +0 -0
  89. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -0
  90. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -0
  91. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -0
  92. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -0
  93. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -0
  94. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -0
  95. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/empty.commands.md +0 -0
  96. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -0
  97. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -0
  98. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -0
  99. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -0
  100. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -0
  101. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -0
  102. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -0
  103. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -0
  104. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/classify_task.intention.md +0 -0
  105. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/empty.intention.md +0 -0
  106. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/error_fixing.intention.md +0 -0
  107. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/feature_fix_steps_for_scenario.intention.md +0 -0
  108. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/feature_formulation.intention.md +0 -0
  109. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/feature_reverse_formulation_from_code.intention.md +0 -0
  110. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/feature_scenario_implementation.intention.md +0 -0
  111. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/feature_scenario_implementation_update.intention.md +0 -0
  112. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/feature_scenario_outline_extension.intention.md +0 -0
  113. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/feature_update_formulation.intention.md +0 -0
  114. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/fibonacci_example_implementation.intention.md +0 -0
  115. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/js_implementation_from_task_description.intention.md +0 -0
  116. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/js_steps_implementation.intention.md +0 -0
  117. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/python_cli_implementation_with_test.intention.md +0 -0
  118. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/python_code_understanding.intention.md +0 -0
  119. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/task_implementation.intention.md +0 -0
  120. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/task_prompt_control_by_status.intention.md +0 -0
  121. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/task_stepwise_implementation_by_number.intention.md +0 -0
  122. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/intentions/task_stepwise_implementation_by_status.intention.md +0 -0
  123. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/architecture_analyst.rules.md +0 -0
  124. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/code_analyst.rules.md +0 -0
  125. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/empty.rules.md +0 -0
  126. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/error_analyst.rules.md +0 -0
  127. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/gherkin_expert.rules.md +0 -0
  128. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/js_expert_developer.rules.md +0 -0
  129. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/product_owner.rules.md +0 -0
  130. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/python_behave.rules.md +0 -0
  131. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/prompt-modules/rules/python_developer.rules.md +0 -0
  132. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.concept.exploration.md +0 -0
  133. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.concept.md +0 -0
  134. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.customer.exploration.md +0 -0
  135. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.customer.md +0 -0
  136. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.persona.exploration.md +0 -0
  137. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.persona.md +0 -0
  138. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.step.exploration.md +0 -0
  139. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.step.md +0 -0
  140. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.technology.exploration.md +0 -0
  141. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/specification_breakdown_files/template.technology.md +0 -0
  142. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.businessgoal.prompt_log.md +0 -0
  143. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.capability.prompt_log.md +0 -0
  144. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.epic.prompt_log.md +0 -0
  145. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.example.prompt_log.md +0 -0
  146. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.feature.prompt_log.md +0 -0
  147. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.issue.prompt_log.md +0 -0
  148. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.keyfeature.prompt_log.md +0 -0
  149. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.steps.prompt_log.md +0 -0
  150. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.task.prompt_log.md +0 -0
  151. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.userstory.prompt_log.md +0 -0
  152. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/templates/template.vision.prompt_log.md +0 -0
  153. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli/update_config_prompt.py +0 -0
  154. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli.egg-info/dependency_links.txt +0 -0
  155. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli.egg-info/entry_points.txt +0 -0
  156. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli.egg-info/requires.txt +0 -0
  157. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/ara_cli.egg-info/top_level.txt +0 -0
  158. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/docker/base/requirements.txt +0 -0
  159. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/setup.cfg +0 -0
  160. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/setup.py +0 -0
  161. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/__init__.py +0 -0
  162. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_ara_config.py +0 -0
  163. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_artefact_fuzzy_search.py +0 -0
  164. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_artefact_link_updater.py +0 -0
  165. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_artefact_lister.py +0 -0
  166. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_artefact_reader.py +0 -0
  167. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_artefact_renamer.py +0 -0
  168. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_artefact_scan.py +0 -0
  169. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_classifier.py +0 -0
  170. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_directory_navigator.py +0 -0
  171. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_file_lister.py +0 -0
  172. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_global_file_lister.py +0 -0
  173. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_list_filter.py +0 -0
  174. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_prompt_handler.py +0 -0
  175. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_tag_extractor.py +0 -0
  176. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_template_manager.py +0 -0
  177. {ara_cli-0.1.9.95 → ara_cli-0.1.9.96}/tests/test_update_config_prompt.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ara_cli
3
- Version: 0.1.9.95
3
+ Version: 0.1.9.96
4
4
  Summary: Powerful, open source command-line tool for managing, structuring and automating software development artifacts in line with Business-Driven Development (BDD) and AI-assisted processes
5
5
  Description-Content-Type: text/markdown
6
6
  Requires-Dist: litellm
@@ -1,10 +1,13 @@
1
1
  import warnings
2
- from .version import __version__
2
+ from .error_handler import ErrorHandler
3
3
 
4
4
 
5
5
  whitelisted_commands = ["RERUN", "SEND", "EXTRACT", "LOAD_IMAGE", "CHOOSE_MODEL", "CHOOSE_EXTRACTION_MODEL", "CURRENT_MODEL", "CURRENT_EXTRACTION_MODEL", "LIST_MODELS"]
6
6
 
7
7
 
8
+ error_handler = ErrorHandler()
9
+
10
+
8
11
  # ANSI escape codes for coloring
9
12
  YELLOW = '\033[93m'
10
13
  RESET = '\033[0m'
@@ -1,5 +1,6 @@
1
1
  # PYTHON_ARGCOMPLETE_OK
2
2
  from ara_cli.ara_command_parser import action_parser
3
+ from ara_cli.error_handler import AraError
3
4
  from ara_cli.version import __version__
4
5
  from ara_cli.ara_command_action import (
5
6
  create_action,
@@ -22,8 +23,10 @@ from ara_cli.ara_command_action import (
22
23
  autofix_action,
23
24
  extract_action
24
25
  )
26
+ from . import error_handler
25
27
  import argcomplete
26
28
  import sys
29
+ from os import getenv
27
30
 
28
31
 
29
32
  def define_action_mapping():
@@ -51,31 +54,74 @@ def define_action_mapping():
51
54
 
52
55
 
53
56
  def handle_invalid_action(args):
54
- sys.exit("Invalid action provided. Type ara -h for help")
57
+ raise AraError("Invalid action provided. Type ara -h for help", error_code=1)
55
58
 
56
59
 
57
- def cli():
58
- parser = action_parser()
60
+ def is_debug_mode_enabled():
61
+ """Check if debug mode is enabled via environment variable."""
62
+ return getenv('ARA_DEBUG', '').lower() in ('1', 'true', 'yes')
59
63
 
64
+
65
+ def setup_parser():
66
+ """Create and configure the argument parser."""
67
+ parser = action_parser()
68
+
60
69
  # Show examples when help is called
61
70
  if any(arg in sys.argv for arg in ["-h", "--help"]):
62
71
  parser.add_examples = True
63
-
72
+
64
73
  parser.add_argument(
65
74
  "-v", "--version", action="version", version=f"%(prog)s {__version__}"
66
75
  )
76
+
77
+ parser.add_argument(
78
+ "--debug", action="store_true", help="Enable debug mode for detailed error output"
79
+ )
80
+
81
+ return parser
67
82
 
68
- action_mapping = define_action_mapping()
69
83
 
70
- argcomplete.autocomplete(parser)
84
+ def configure_debug_mode(args, env_debug_mode):
85
+ """Configure debug mode based on arguments and environment."""
86
+ if (hasattr(args, 'debug') and args.debug) or env_debug_mode:
87
+ error_handler.debug_mode = True
71
88
 
72
- args = parser.parse_args()
73
- if not hasattr(args, "action") or not args.action:
74
- parser.print_help()
75
- return
89
+
90
+ def should_show_help(args):
91
+ """Check if help should be displayed."""
92
+ return not hasattr(args, "action") or not args.action
93
+
94
+
95
+ def execute_action(args, action_mapping):
96
+ """Execute the specified action."""
76
97
  action = action_mapping.get(args.action, handle_invalid_action)
77
98
  action(args)
78
99
 
79
100
 
101
+ def cli():
102
+ debug_mode = is_debug_mode_enabled()
103
+
104
+ try:
105
+ parser = setup_parser()
106
+ action_mapping = define_action_mapping()
107
+
108
+ argcomplete.autocomplete(parser)
109
+ args = parser.parse_args()
110
+
111
+ configure_debug_mode(args, debug_mode)
112
+
113
+ if should_show_help(args):
114
+ parser.print_help()
115
+ return
116
+
117
+ execute_action(args, action_mapping)
118
+
119
+ except KeyboardInterrupt:
120
+ print("\n[INFO] Operation cancelled by user", file=sys.stderr)
121
+ sys.exit(130) # Standard exit code for Ctrl+C
122
+ except Exception as e:
123
+ error_handler.handle_error(e, context="cli")
124
+
125
+
80
126
  if __name__ == "__main__":
81
- cli()
127
+ cli()
@@ -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
@@ -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
@@ -131,6 +136,7 @@ def list_action(args):
131
136
  artefact_lister.list_files(list_filter=list_filter)
132
137
 
133
138
 
139
+ @handle_errors(context="list-tags action", error_handler=error_handler)
134
140
  def list_tags_action(args):
135
141
  from ara_cli.tag_extractor import TagExtractor
136
142
  from ara_cli.list_filter import ListFilter
@@ -155,6 +161,7 @@ def list_tags_action(args):
155
161
  print(output)
156
162
 
157
163
 
164
+ @handle_errors(context="prompt action", error_handler=error_handler)
158
165
  def prompt_action(args):
159
166
  from ara_cli.classifier import Classifier
160
167
  from ara_cli.filename_validator import is_valid_filename
@@ -227,6 +234,7 @@ def prompt_action(args):
227
234
  raise ValueError(f"Unknown command '{init}' provided.")
228
235
 
229
236
 
237
+ @handle_errors(context="chat action", error_handler=error_handler)
230
238
  def chat_action(args):
231
239
  from ara_cli.chat import Chat
232
240
 
@@ -253,6 +261,7 @@ def chat_action(args):
253
261
  chat.start()
254
262
 
255
263
 
264
+ @handle_errors(context="template action", error_handler=error_handler)
256
265
  def template_action(args):
257
266
  from ara_cli.classifier import Classifier
258
267
  from ara_cli.template_manager import TemplatePathManager
@@ -265,6 +274,7 @@ def template_action(args):
265
274
  print(content)
266
275
 
267
276
 
277
+ @handle_errors(context="fetch-templates action", error_handler=error_handler)
268
278
  def fetch_templates_action(args):
269
279
  import shutil
270
280
  from ara_cli.ara_config import ConfigManager
@@ -294,6 +304,7 @@ def fetch_templates_action(args):
294
304
  os.makedirs(join(local_prompt_modules_dir, subdir), exist_ok=True)
295
305
 
296
306
 
307
+ @handle_errors(context="read action", error_handler=error_handler)
297
308
  def read_action(args):
298
309
  from ara_cli.commands.read_command import ReadCommand
299
310
  from ara_cli.list_filter import ListFilter
@@ -321,6 +332,7 @@ def read_action(args):
321
332
  command.execute()
322
333
 
323
334
 
335
+ @handle_errors(context="reconnect action", error_handler=error_handler)
324
336
  def reconnect_action(args):
325
337
  from ara_cli.artefact_models.artefact_load import artefact_from_content
326
338
  from ara_cli.artefact_models.artefact_model import Contribution
@@ -348,8 +360,7 @@ def reconnect_action(args):
348
360
  )
349
361
 
350
362
  if not artefact:
351
- print(read_error_message)
352
- return
363
+ raise AraError(read_error_message)
353
364
 
354
365
  parent = ArtefactReader.read_artefact(
355
366
  artefact_name=parent_name,
@@ -358,8 +369,7 @@ def reconnect_action(args):
358
369
  )
359
370
 
360
371
  if not parent:
361
- print(read_error_message)
362
- return
372
+ raise AraError(read_error_message)
363
373
 
364
374
  contribution = Contribution(
365
375
  artefact_name=parent.title,
@@ -367,13 +377,9 @@ def reconnect_action(args):
367
377
  )
368
378
 
369
379
  if rule:
370
- try:
371
- closest_rule = find_closest_rule(parent, rule)
372
- contribution.rule = closest_rule
373
- feedback_message += f" using rule '{closest_rule}'"
374
- except TypeError as e:
375
- print(f"{type(e).__name__}:", e)
376
- exit(1)
380
+ closest_rule = find_closest_rule(parent, rule)
381
+ contribution.rule = closest_rule
382
+ feedback_message += f" using rule '{closest_rule}'"
377
383
 
378
384
  artefact.contribution = contribution
379
385
  with open(artefact.file_path, 'w', encoding='utf-8') as file:
@@ -383,6 +389,7 @@ def reconnect_action(args):
383
389
  print(feedback_message + ".")
384
390
 
385
391
 
392
+ @handle_errors(context="read-status action", error_handler=error_handler)
386
393
  def read_status_action(args):
387
394
  from ara_cli.file_classifier import FileClassifier
388
395
  from ara_cli.artefact_models.artefact_load import artefact_from_content
@@ -396,7 +403,7 @@ def read_status_action(args):
396
403
 
397
404
  all_artefact_names = [artefact_info["title"] for artefact_info in artefact_info_dicts]
398
405
  if artefact_name not in all_artefact_names:
399
- suggest_close_name_matches(artefact_name, all_artefact_names)
406
+ suggest_close_name_matches(artefact_name, all_artefact_names, report_as_error=True)
400
407
  return
401
408
 
402
409
  artefact_info = next(filter(
@@ -415,6 +422,7 @@ def read_status_action(args):
415
422
  print(status)
416
423
 
417
424
 
425
+ @handle_errors(context="read-user action", error_handler=error_handler)
418
426
  def read_user_action(args):
419
427
  from ara_cli.artefact_models.artefact_load import artefact_from_content
420
428
  from ara_cli.file_classifier import FileClassifier
@@ -428,7 +436,7 @@ def read_user_action(args):
428
436
 
429
437
  all_artefact_names = [artefact_info["title"] for artefact_info in artefact_info_dicts]
430
438
  if artefact_name not in all_artefact_names:
431
- suggest_close_name_matches(artefact_name, all_artefact_names)
439
+ suggest_close_name_matches(artefact_name, all_artefact_names, report_as_error=True)
432
440
  return
433
441
 
434
442
  artefact_info = next(filter(
@@ -448,6 +456,7 @@ def read_user_action(args):
448
456
  print(f" - {tag}")
449
457
 
450
458
 
459
+ @handle_errors(context="set-status action", error_handler=error_handler)
451
460
  def set_status_action(args):
452
461
  from ara_cli.artefact_models.artefact_model import ALLOWED_STATUS_VALUES
453
462
  from ara_cli.artefact_models.artefact_load import artefact_from_content
@@ -490,6 +499,7 @@ def set_status_action(args):
490
499
  print(f"Status of task '{artefact_name}' has been updated to '{new_status}'.")
491
500
 
492
501
 
502
+ @handle_errors(context="set-user action", error_handler=error_handler)
493
503
  def set_user_action(args):
494
504
  from ara_cli.file_classifier import FileClassifier
495
505
  from ara_cli.artefact_models.artefact_load import artefact_from_content
@@ -528,6 +538,7 @@ def set_user_action(args):
528
538
  print(f"User of task '{artefact_name}' has been updated to '{new_user}'.")
529
539
 
530
540
 
541
+ @handle_errors(context="classifier-directory action", error_handler=error_handler)
531
542
  def classifier_directory_action(args):
532
543
  from ara_cli.classifier import Classifier
533
544
 
@@ -536,6 +547,7 @@ def classifier_directory_action(args):
536
547
  print(subdirectory)
537
548
 
538
549
 
550
+ @handle_errors(context="scan action", error_handler=error_handler)
539
551
  def scan_action(args):
540
552
  from ara_cli.file_classifier import FileClassifier
541
553
  from ara_cli.artefact_scan import find_invalid_files, show_results
@@ -550,6 +562,7 @@ def scan_action(args):
550
562
  show_results(invalid_artefacts)
551
563
 
552
564
 
565
+ @handle_errors(context="autofix_action", error_handler=error_handler)
553
566
  def autofix_action(args):
554
567
  from ara_cli.artefact_autofix import parse_report, apply_autofix, read_report_file
555
568
  from ara_cli.file_classifier import FileClassifier
@@ -589,18 +602,17 @@ def autofix_action(args):
589
602
  print("\nAutofix process completed. Please review the changes.")
590
603
 
591
604
 
605
+ @handle_errors(context="extract action", error_handler=error_handler)
592
606
  def extract_action(args):
593
607
  from ara_cli.commands.extract_command import ExtractCommand
594
608
 
595
609
  filename = args.filename
596
610
  force = args.force
597
611
  write = getattr(args, 'write', False)
598
- print(filename)
599
612
  command = ExtractCommand(
600
613
  file_name=filename,
601
614
  force=force,
602
615
  write=write,
603
- output=lambda msg: print(msg, file=sys.stdout),
604
- error_output=lambda msg: print(msg, file=sys.stderr)
616
+ output=lambda msg: print(msg, file=sys.stdout)
605
617
  )
606
618
  command.execute()
@@ -1,3 +1,4 @@
1
+ from ara_cli.error_handler import AraError
1
2
  from ara_cli.artefact_scan import check_file
2
3
  from ara_cli.artefact_fuzzy_search import (
3
4
  find_closest_name_matches,
@@ -10,6 +11,7 @@ from ara_cli.artefact_models.artefact_model import Artefact
10
11
  from typing import Optional, Dict, List, Tuple
11
12
  import difflib
12
13
  import os
14
+ import re
13
15
 
14
16
 
15
17
  def populate_classified_artefact_info(
@@ -104,8 +106,9 @@ def determine_artefact_type_and_class(classifier):
104
106
 
105
107
  artefact_class = artefact_type_mapping.get(artefact_type)
106
108
  if not artefact_class:
107
- print(f"No artefact class found for {artefact_type}")
108
- return None, None
109
+ raise AraError(f"No artefact class found for {artefact_type}")
110
+ # print(f"No artefact class found for {artefact_type}")
111
+ # return None, None
109
112
 
110
113
  return artefact_type, artefact_class
111
114
 
@@ -372,6 +375,131 @@ def set_closest_contribution(
372
375
  return artefact, True
373
376
 
374
377
 
378
+ def fix_scenario_placeholder_mismatch(
379
+ file_path: str, artefact_text: str, artefact_class, **kwargs
380
+ ) -> str:
381
+ """
382
+ Converts a regular Scenario with placeholders to a Scenario Outline.
383
+ This is a deterministic fix that detects placeholders and converts the format.
384
+ """
385
+ lines = artefact_text.splitlines()
386
+ new_lines = []
387
+ i = 0
388
+
389
+ while i < len(lines):
390
+ line = lines[i]
391
+ stripped_line = line.strip()
392
+
393
+ if stripped_line.startswith('Scenario:'):
394
+ scenario_lines, next_index = _extract_scenario_block(lines, i)
395
+ processed_lines = _process_scenario_block(scenario_lines)
396
+ new_lines.extend(processed_lines)
397
+ i = next_index
398
+ else:
399
+ new_lines.append(line)
400
+ i += 1
401
+
402
+ return "\n".join(new_lines)
403
+
404
+
405
+ def _extract_scenario_block(lines: list, start_index: int) -> tuple[list, int]:
406
+ """Extract all lines belonging to a scenario block."""
407
+ scenario_lines = [lines[start_index]]
408
+ j = start_index + 1
409
+
410
+ while j < len(lines):
411
+ next_line = lines[j].strip()
412
+ if _is_scenario_boundary(next_line):
413
+ break
414
+ scenario_lines.append(lines[j])
415
+ j += 1
416
+
417
+ return scenario_lines, j
418
+
419
+
420
+ def _is_scenario_boundary(line: str) -> bool:
421
+ """Check if a line marks the boundary of a scenario block."""
422
+ boundaries = ['Scenario:', 'Scenario Outline:', 'Background:', 'Feature:']
423
+ return any(line.startswith(boundary) for boundary in boundaries)
424
+
425
+
426
+ def _process_scenario_block(scenario_lines: list) -> list:
427
+ """Process a scenario block and convert to outline if placeholders are found."""
428
+ if not scenario_lines:
429
+ return scenario_lines
430
+
431
+ first_line = scenario_lines[0]
432
+ indentation = _get_line_indentation(first_line)
433
+ placeholders = _extract_placeholders_from_scenario(scenario_lines[1:])
434
+
435
+ if not placeholders:
436
+ return scenario_lines
437
+
438
+ return _convert_to_scenario_outline(scenario_lines, placeholders, indentation)
439
+
440
+
441
+ def _get_line_indentation(line: str) -> str:
442
+ """Get the indentation of a line."""
443
+ return line[:len(line) - len(line.lstrip())]
444
+
445
+
446
+ def _extract_placeholders_from_scenario(step_lines: list) -> set:
447
+ """Extract placeholders from scenario step lines, ignoring docstrings."""
448
+ placeholders = set()
449
+ in_docstring = False
450
+
451
+ for line in step_lines:
452
+ step_line = line.strip()
453
+ if not step_line:
454
+ continue
455
+
456
+ in_docstring = _update_docstring_state(step_line, in_docstring)
457
+
458
+ if not in_docstring and '"""' not in step_line:
459
+ found = re.findall(r'<([^>]+)>', step_line)
460
+ placeholders.update(found)
461
+
462
+ return placeholders
463
+
464
+
465
+ def _update_docstring_state(line: str, current_state: bool) -> bool:
466
+ """Update the docstring state based on the current line."""
467
+ if '"""' in line:
468
+ return not current_state
469
+ return current_state
470
+
471
+
472
+ def _convert_to_scenario_outline(scenario_lines: list, placeholders: set, indentation: str) -> list:
473
+ """Convert scenario lines to scenario outline format with examples table."""
474
+ first_line = scenario_lines[0]
475
+ title = first_line.strip()[len('Scenario:'):].strip()
476
+
477
+ new_lines = [f"{indentation}Scenario Outline: {title}"]
478
+ new_lines.extend(scenario_lines[1:])
479
+ new_lines.append("")
480
+
481
+ examples_lines = _create_examples_table(placeholders, indentation)
482
+ new_lines.extend(examples_lines)
483
+
484
+ return new_lines
485
+
486
+
487
+ def _create_examples_table(placeholders: set, base_indentation: str) -> list:
488
+ """Create the Examples table for the scenario outline."""
489
+ examples_indentation = base_indentation + " "
490
+ table_indentation = examples_indentation + " "
491
+
492
+ sorted_placeholders = sorted(placeholders)
493
+ header = "| " + " | ".join(sorted_placeholders) + " |"
494
+ sample_row = "| " + " | ".join(f"<{p}_value>" for p in sorted_placeholders) + " |"
495
+
496
+ return [
497
+ f"{examples_indentation}Examples:",
498
+ f"{table_indentation}{header}",
499
+ f"{table_indentation}{sample_row}"
500
+ ]
501
+
502
+
375
503
  def fix_title_mismatch(
376
504
  file_path: str, artefact_text: str, artefact_class, **kwargs
377
505
  ) -> str:
@@ -584,6 +712,7 @@ def apply_autofix(
584
712
  "Filename-Title Mismatch": fix_title_mismatch,
585
713
  "Invalid Contribution Reference": fix_contribution,
586
714
  "Rule Mismatch": fix_rule,
715
+ "Scenario Contains Placeholders": fix_scenario_placeholder_mismatch,
587
716
  }
588
717
 
589
718
  artefact_type, artefact_class = determine_artefact_type_and_class(classifier)
@@ -38,11 +38,9 @@ class ArtefactCreator:
38
38
  destination = Path(dir_path) / dest_name
39
39
 
40
40
  if not source.exists():
41
- print("[ERROR] Source file does not exist!")
42
41
  raise FileNotFoundError(f"Source file {source} not found!")
43
42
 
44
43
  if not destination.parent.exists():
45
- print("[ERROR] Destination directory does not exist!")
46
44
  raise NotADirectoryError(f"Destination directory {destination.parent} does not exist!")
47
45
 
48
46
  copyfile(source, destination)
@@ -70,9 +68,7 @@ class ArtefactCreator:
70
68
  def validate_template(self, template_path, classifier):
71
69
  template_name = f"template.{classifier}"
72
70
  if not self.template_exists(template_path, template_name):
73
- print(f"Template file '{template_name}' not found in the specified template path.")
74
- return False
75
- return True
71
+ raise FileNotFoundError(f"Template file '{template_name}' not found in the specified template path.")
76
72
 
77
73
  def set_artefact_parent(self, artefact, parent_classifier, parent_file_name) -> Artefact:
78
74
  classified_artefacts = ArtefactReader.read_artefacts()
@@ -94,8 +90,7 @@ class ArtefactCreator:
94
90
  navigator.navigate_to_target()
95
91
 
96
92
  if not Classifier.is_valid_classifier(classifier):
97
- print("Invalid classifier provided. Please provide a valid classifier.")
98
- return
93
+ raise ValueError("Invalid classifier provided. Please provide a valid classifier.")
99
94
 
100
95
  sub_directory = Classifier.get_sub_directory(classifier)
101
96
  file_path = self.file_system.path.join(sub_directory, f"{filename}.{classifier}")
@@ -20,16 +20,14 @@ class ArtefactDeleter:
20
20
  self.navigate_to_target()
21
21
 
22
22
  if not Classifier.is_valid_classifier(classifier):
23
- print("Invalid classifier provided. Please provide a valid classifier.")
24
- return
23
+ raise ValueError("Invalid classifier provided. Please provide a valid classifier.")
25
24
 
26
25
  sub_directory = Classifier.get_sub_directory(classifier)
27
26
  file_path = self.file_system.path.join(sub_directory, f"{filename}.{classifier}")
28
27
  dir_path = self.file_system.path.join(sub_directory, f"{filename}.data")
29
28
 
30
29
  if not self.file_system.path.exists(file_path):
31
- print(f"Artefact {file_path} not found.")
32
- return
30
+ raise FileNotFoundError(f"Artefact {file_path} not found.")
33
31
  if not force:
34
32
  user_choice = input(f"Are you sure you want to delete the file {filename} and data directory if existing? (y/N): ")
35
33
 
@@ -1,11 +1,16 @@
1
1
  import difflib
2
2
  from textwrap import indent
3
3
  from typing import Optional
4
+ from . import error_handler
5
+ from ara_cli.error_handler import AraError
4
6
 
5
7
 
6
- def suggest_close_names(artefact_name: str, all_artefact_names: list[str], message: str, cutoff=0.5):
8
+ def suggest_close_names(artefact_name: str, all_artefact_names: list[str], message: str, cutoff=0.5, report_as_error: bool = False):
7
9
  closest_matches = difflib.get_close_matches(artefact_name, all_artefact_names, cutoff=cutoff)
8
- print(message)
10
+ if report_as_error:
11
+ error_handler.report_error(AraError(message))
12
+ else:
13
+ print(message)
9
14
  if not closest_matches:
10
15
  return
11
16
  print("Closest matches:")
@@ -13,23 +18,25 @@ def suggest_close_names(artefact_name: str, all_artefact_names: list[str], messa
13
18
  print(f" - {match}")
14
19
 
15
20
 
16
- def suggest_close_name_matches(artefact_name: str, all_artefact_names: list[str]):
21
+ def suggest_close_name_matches(artefact_name: str, all_artefact_names: list[str], report_as_error: bool = False):
17
22
  message = f"No match found for artefact with name '{artefact_name}'"
18
23
 
19
24
  suggest_close_names(
20
25
  artefact_name=artefact_name,
21
26
  all_artefact_names=all_artefact_names,
22
- message=message
27
+ message=message,
28
+ report_as_error=report_as_error
23
29
  )
24
30
 
25
31
 
26
- def suggest_close_name_matches_for_parent(artefact_name: str, all_artefact_names: list[str], parent_name: str):
32
+ def suggest_close_name_matches_for_parent(artefact_name: str, all_artefact_names: list[str], parent_name: str, report_as_error: bool = False):
27
33
  message = f"No match found for parent of '{artefact_name}' with name '{parent_name}'"
28
34
 
29
35
  suggest_close_names(
30
36
  artefact_name=parent_name,
31
37
  all_artefact_names=all_artefact_names,
32
- message=message
38
+ message=message,
39
+ report_as_error=report_as_error
33
40
  )
34
41
 
35
42
 
@@ -148,9 +148,9 @@ def _default_feature(title: str, use_default_contribution: bool) -> FeatureArtef
148
148
  Scenario(
149
149
  title="<descriptive_scenario_title>",
150
150
  steps=[
151
- "Given <precondition>",
152
- "When <action>",
153
- "Then <expected result>"
151
+ "Given [precondition]",
152
+ "When [action]",
153
+ "Then [expected result]"
154
154
  ],
155
155
  ),
156
156
  ScenarioOutline(
@@ -148,6 +148,30 @@ class Scenario(BaseModel):
148
148
  raise ValueError("steps list must not be empty")
149
149
  return steps
150
150
 
151
+ @model_validator(mode='after')
152
+ def check_no_placeholders(cls, values: 'Scenario') -> 'Scenario':
153
+ """Ensure regular scenarios don't contain placeholders that should be in scenario outlines."""
154
+ placeholders = set()
155
+ for step in values.steps:
156
+ # Skip validation if step contains docstring placeholders (during parsing)
157
+ if '__DOCSTRING_PLACEHOLDER_' in step:
158
+ continue
159
+
160
+ # Skip validation if step contains docstring markers (after reinjection)
161
+ if '"""' in step:
162
+ continue
163
+
164
+ found = re.findall(r'<([^>]+)>', step)
165
+ placeholders.update(found)
166
+
167
+ if placeholders:
168
+ placeholder_list = ', '.join(f"<{p}>" for p in sorted(placeholders))
169
+ raise ValueError(
170
+ f"Scenario Contains Placeholders ({placeholder_list}) but is not a Scenario Outline. "
171
+ f"Use 'Scenario Outline:' instead of 'Scenario:' and provide an Examples table."
172
+ )
173
+ return values
174
+
151
175
  @classmethod
152
176
  def from_lines(cls, lines: List[str], start_idx: int) -> Tuple['Scenario', int]:
153
177
  """Parse a Scenario from a list of lines starting at start_idx."""
@@ -277,6 +301,7 @@ class FeatureArtefact(Artefact):
277
301
  f"FeatureArtefact must have artefact_type of '{ArtefactType.feature}', not '{v}'")
278
302
  return v
279
303
 
304
+
280
305
  @classmethod
281
306
  def _title_prefix(cls) -> str:
282
307
  return "Feature:"