ara-cli 0.1.9.69__tar.gz → 0.1.9.71__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 (166) hide show
  1. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/PKG-INFO +1 -1
  2. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/ara_command_action.py +16 -12
  3. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/ara_config.py +24 -10
  4. ara_cli-0.1.9.71/ara_cli/artefact_autofix.py +446 -0
  5. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_creator.py +3 -3
  6. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_fuzzy_search.py +9 -4
  7. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_link_updater.py +4 -4
  8. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/artefact_model.py +14 -7
  9. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/artefact_templates.py +1 -1
  10. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/feature_artefact_model.py +72 -18
  11. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/serialize_helper.py +1 -1
  12. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_reader.py +16 -38
  13. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_renamer.py +2 -2
  14. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_scan.py +28 -3
  15. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/chat.py +1 -1
  16. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/file_classifier.py +3 -3
  17. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/file_lister.py +1 -1
  18. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/list_filter.py +1 -1
  19. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/output_suppressor.py +1 -1
  20. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/prompt_extractor.py +3 -3
  21. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/prompt_handler.py +9 -10
  22. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/prompt_rag.py +2 -2
  23. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/template_manager.py +2 -2
  24. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +1 -1
  25. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/update_config_prompt.py +2 -2
  26. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/version.py +1 -1
  27. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli.egg-info/PKG-INFO +1 -1
  28. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli.egg-info/SOURCES.txt +1 -1
  29. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/setup.py +1 -1
  30. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_ara_command_action.py +7 -7
  31. ara_cli-0.1.9.69/tests/test_ara_autofix.py → ara_cli-0.1.9.71/tests/test_artefact_autofix.py +163 -29
  32. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_artefact_link_updater.py +3 -3
  33. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_artefact_renamer.py +2 -2
  34. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_artefact_scan.py +52 -19
  35. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_file_classifier.py +1 -1
  36. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_file_lister.py +1 -1
  37. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_list_filter.py +2 -2
  38. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_update_config_prompt.py +2 -2
  39. ara_cli-0.1.9.69/ara_cli/artefact_autofix.py +0 -191
  40. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/MANIFEST.in +0 -0
  41. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/README.md +0 -0
  42. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/__init__.py +0 -0
  43. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/__main__.py +0 -0
  44. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/ara_command_parser.py +0 -0
  45. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_deleter.py +0 -0
  46. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_lister.py +0 -0
  47. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/__init__.py +0 -0
  48. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/artefact_load.py +0 -0
  49. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/artefact_mapping.py +0 -0
  50. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/businessgoal_artefact_model.py +0 -0
  51. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/capability_artefact_model.py +0 -0
  52. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/epic_artefact_model.py +0 -0
  53. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/example_artefact_model.py +0 -0
  54. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/issue_artefact_model.py +0 -0
  55. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/keyfeature_artefact_model.py +0 -0
  56. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/task_artefact_model.py +0 -0
  57. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/userstory_artefact_model.py +0 -0
  58. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/artefact_models/vision_artefact_model.py +0 -0
  59. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/classifier.py +0 -0
  60. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/codefusionretriever.py +0 -0
  61. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/codehierachieretriever.py +0 -0
  62. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/commandline_completer.py +0 -0
  63. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/directory_navigator.py +0 -0
  64. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/filename_validator.py +0 -0
  65. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/prompt_chat.py +0 -0
  66. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/run_file_lister.py +0 -0
  67. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/tag_extractor.py +0 -0
  68. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/agile.artefacts +0 -0
  69. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/blueprints/empty.blueprint.md +0 -0
  70. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/blueprints/task_todo_list_C4_architecture_analysis.blueprint.md +0 -0
  71. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -0
  72. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/architecture_C4_analysis.commands.md +0 -0
  73. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/architecture_radon_cc_score.commands.md +0 -0
  74. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/architecture_radon_halstead_v.commands.md +0 -0
  75. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/architecture_radon_maintainability_score.commands.md +0 -0
  76. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -0
  77. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -0
  78. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -0
  79. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -0
  80. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -0
  81. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -0
  82. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/empty.commands.md +0 -0
  83. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -0
  84. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -0
  85. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -0
  86. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -0
  87. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -0
  88. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -0
  89. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -0
  90. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -0
  91. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/classify_task.intention.md +0 -0
  92. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/empty.intention.md +0 -0
  93. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/error_fixing.intention.md +0 -0
  94. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/feature_fix_steps_for_scenario.intention.md +0 -0
  95. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/feature_formulation.intention.md +0 -0
  96. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/feature_reverse_formulation_from_code.intention.md +0 -0
  97. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/feature_scenario_implementation.intention.md +0 -0
  98. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/feature_scenario_implementation_update.intention.md +0 -0
  99. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/feature_scenario_outline_extension.intention.md +0 -0
  100. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/feature_update_formulation.intention.md +0 -0
  101. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/fibonacci_example_implementation.intention.md +0 -0
  102. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/js_implementation_from_task_description.intention.md +0 -0
  103. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/js_steps_implementation.intention.md +0 -0
  104. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/python_cli_implementation_with_test.intention.md +0 -0
  105. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/python_code_understanding.intention.md +0 -0
  106. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/task_implementation.intention.md +0 -0
  107. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/task_prompt_control_by_status.intention.md +0 -0
  108. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/task_stepwise_implementation_by_number.intention.md +0 -0
  109. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/intentions/task_stepwise_implementation_by_status.intention.md +0 -0
  110. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/architecture_analyst.rules.md +0 -0
  111. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/code_analyst.rules.md +0 -0
  112. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/empty.rules.md +0 -0
  113. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/error_analyst.rules.md +0 -0
  114. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/gherkin_expert.rules.md +0 -0
  115. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/js_expert_developer.rules.md +0 -0
  116. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/product_owner.rules.md +0 -0
  117. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/python_behave.rules.md +0 -0
  118. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/prompt-modules/rules/python_developer.rules.md +0 -0
  119. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.concept.exploration.md +0 -0
  120. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.concept.md +0 -0
  121. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.customer.exploration.md +0 -0
  122. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.customer.md +0 -0
  123. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.persona.exploration.md +0 -0
  124. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.persona.md +0 -0
  125. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.step.exploration.md +0 -0
  126. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.step.md +0 -0
  127. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.technology.exploration.md +0 -0
  128. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/specification_breakdown_files/template.technology.md +0 -0
  129. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.businessgoal +0 -0
  130. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.businessgoal.prompt_log.md +0 -0
  131. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.capability +0 -0
  132. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.capability.prompt_log.md +0 -0
  133. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.epic +0 -0
  134. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.epic.prompt_log.md +0 -0
  135. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.example +0 -0
  136. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.example.prompt_log.md +0 -0
  137. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.feature +0 -0
  138. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.feature.prompt_log.md +0 -0
  139. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.issue +0 -0
  140. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.issue.prompt_log.md +0 -0
  141. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.keyfeature +0 -0
  142. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.keyfeature.prompt_log.md +0 -0
  143. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.steps.prompt_log.md +0 -0
  144. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.task +0 -0
  145. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.task.prompt_log.md +0 -0
  146. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.userstory +0 -0
  147. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.userstory.prompt_log.md +0 -0
  148. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.vision +0 -0
  149. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli/templates/template.vision.prompt_log.md +0 -0
  150. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli.egg-info/dependency_links.txt +0 -0
  151. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli.egg-info/entry_points.txt +0 -0
  152. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli.egg-info/requires.txt +0 -0
  153. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/ara_cli.egg-info/top_level.txt +0 -0
  154. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/docker/base/requirements.txt +0 -0
  155. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/setup.cfg +0 -0
  156. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/__init__.py +0 -0
  157. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_ara_config.py +0 -0
  158. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_artefact_fuzzy_search.py +0 -0
  159. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_artefact_lister.py +0 -0
  160. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_artefact_reader.py +0 -0
  161. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_chat.py +0 -0
  162. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_classifier.py +0 -0
  163. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_directory_navigator.py +0 -0
  164. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_file_creator.py +0 -0
  165. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_tag_extractor.py +0 -0
  166. {ara_cli-0.1.9.69 → ara_cli-0.1.9.71}/tests/test_template_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ara_cli
3
- Version: 0.1.9.69
3
+ Version: 0.1.9.71
4
4
  Requires-Dist: litellm
5
5
  Requires-Dist: llama-index
6
6
  Requires-Dist: llama-index-llms-openai
@@ -33,7 +33,7 @@ def create_action(args):
33
33
  if parent_classifier and parent_name and rule:
34
34
  check_validity(Classifier.is_valid_classifier(parent_classifier), invalid_classifier_message)
35
35
  check_validity(is_valid_filename(parent_name), invalid_name_message)
36
- parent_artefact = ArtefactReader.read_single_artefact(artefact_name=parent_name, classifier=parent_classifier)
36
+ parent_artefact = ArtefactReader.read_artefact(artefact_name=parent_name, classifier=parent_classifier)
37
37
  rule = find_closest_rule(parent_artefact, rule)
38
38
  return parent_classifier, parent_name, rule
39
39
  if parent_classifier and parent_name:
@@ -359,7 +359,7 @@ def reconnect_action(args):
359
359
 
360
360
  feedback_message = f"Updated contribution of {classifier} '{artefact_name}' to {parent_classifier} '{parent_name}'"
361
361
 
362
- content, artefact_info = ArtefactReader.read_artefact(
362
+ content, artefact_info = ArtefactReader.read_artefact_data(
363
363
  artefact_name=artefact_name,
364
364
  classifier=classifier
365
365
  )
@@ -367,7 +367,7 @@ def reconnect_action(args):
367
367
  print(read_error_message)
368
368
  return
369
369
 
370
- parent_content, parent_info = ArtefactReader.read_artefact(
370
+ parent_content, parent_info = ArtefactReader.read_artefact_data(
371
371
  artefact_name=parent_name,
372
372
  classifier=parent_classifier
373
373
  )
@@ -399,7 +399,7 @@ def reconnect_action(args):
399
399
  exit(1)
400
400
 
401
401
  artefact.contribution = contribution
402
- with open(artefact.file_path, 'w') as file:
402
+ with open(artefact.file_path, 'w', encoding='utf-8') as file:
403
403
  artefact_content = artefact.serialize()
404
404
  file.write(artefact_content)
405
405
 
@@ -426,7 +426,7 @@ def read_status_action(args):
426
426
  lambda x: x["title"] == artefact_name, artefact_info_dicts
427
427
  ))
428
428
 
429
- with open(artefact_info["file_path"], 'r') as file:
429
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
430
430
  content = file.read()
431
431
  artefact = artefact_from_content(content)
432
432
 
@@ -458,7 +458,7 @@ def read_user_action(args):
458
458
  lambda x: x["title"] == artefact_name, artefact_info_dicts
459
459
  ))
460
460
 
461
- with open(artefact_info["file_path"], 'r') as file:
461
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
462
462
  content = file.read()
463
463
  artefact = artefact_from_content(content)
464
464
 
@@ -500,14 +500,14 @@ def set_status_action(args):
500
500
  lambda x: x["title"] == artefact_name, classified_artefact_dict
501
501
  ))
502
502
 
503
- with open(artefact_info["file_path"], 'r') as file:
503
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
504
504
  content = file.read()
505
505
  artefact = artefact_from_content(content)
506
506
 
507
507
  artefact.status = new_status
508
508
 
509
509
  serialized_content = artefact.serialize()
510
- with open(f"{artefact_info['file_path']}", 'w') as file:
510
+ with open(f"{artefact_info['file_path']}", 'w', encoding='utf-8') as file:
511
511
  file.write(serialized_content)
512
512
 
513
513
  print(f"Status of task '{artefact_name}' has been updated to '{new_status}'.")
@@ -537,7 +537,7 @@ def set_user_action(args):
537
537
  lambda x: x["title"] == artefact_name, classified_artefact_dict
538
538
  ))
539
539
 
540
- with open(artefact_info["file_path"], 'r') as file:
540
+ with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
541
541
  content = file.read()
542
542
  artefact = artefact_from_content(content)
543
543
 
@@ -545,7 +545,7 @@ def set_user_action(args):
545
545
 
546
546
  serialized_content = artefact.serialize()
547
547
 
548
- with open(artefact_info["file_path"], 'w') as file:
548
+ with open(artefact_info["file_path"], 'w', encoding='utf-8') as file:
549
549
  file.write(serialized_content)
550
550
 
551
551
  print(f"User of task '{artefact_name}' has been updated to '{new_user}'.")
@@ -575,6 +575,7 @@ def scan_action(args):
575
575
 
576
576
  def autofix_action(args):
577
577
  from ara_cli.artefact_autofix import parse_report, apply_autofix, read_report_file
578
+ from ara_cli.file_classifier import FileClassifier
578
579
 
579
580
  # If the user passes --non-deterministic, only_deterministic_fix becomes False.
580
581
  # If the user passes --deterministic, only_non_deterministic_fix becomes False.
@@ -591,6 +592,9 @@ def autofix_action(args):
591
592
  print("No issues found in the report. Nothing to fix.")
592
593
  return
593
594
 
595
+ file_classifier = FileClassifier(os)
596
+ classified_artefact_info = file_classifier.classify_files()
597
+
594
598
  # print("\nStarting autofix process...")
595
599
  for classifier, files in issues.items():
596
600
  print(f"\nClassifier: {classifier}")
@@ -600,8 +604,8 @@ def autofix_action(args):
600
604
  classifier,
601
605
  reason,
602
606
  deterministic=run_deterministic,
603
- non_deterministic=run_non_deterministic
607
+ non_deterministic=run_non_deterministic,
608
+ classified_artefact_info=classified_artefact_info
604
609
  )
605
610
 
606
611
  print("\nAutofix process completed. Please review the changes.")
607
-
@@ -1,4 +1,4 @@
1
- from typing import List, Dict, Union, Optional
1
+ from typing import List, Dict, Optional
2
2
  from pydantic import BaseModel
3
3
  import json
4
4
  import os
@@ -10,6 +10,13 @@ from functools import lru_cache
10
10
  DEFAULT_CONFIG_LOCATION = "./ara/.araconfig/ara_config.json"
11
11
 
12
12
 
13
+ class LLMConfigItem(BaseModel):
14
+ provider: str
15
+ model: str
16
+ temperature: float
17
+ max_tokens: Optional[int] = None
18
+
19
+
13
20
  class ARAconfig(BaseModel):
14
21
  ext_code_dirs: List[Dict[str, str]] = [
15
22
  {"source_dir_1": "./src"},
@@ -36,42 +43,49 @@ class ARAconfig(BaseModel):
36
43
  "*.jpg",
37
44
  "*.jpeg",
38
45
  ]
39
- llm_config: Dict[str, Dict[str, Union[str, float]]] = {
46
+ llm_config: Dict[str, LLMConfigItem] = {
40
47
  "gpt-4o": {
41
48
  "provider": "openai",
42
49
  "model": "openai/gpt-4o",
43
- "temperature": 0.8
50
+ "temperature": 0.8,
51
+ "max_tokens": 16384
44
52
  },
45
53
  "gpt-4.1": {
46
54
  "provider": "openai",
47
55
  "model": "openai/gpt-4.1",
48
56
  "temperature": 0.8,
57
+ "max_tokens": 1024
49
58
  },
50
59
  "o3-mini": {
51
60
  "provider": "openai",
52
61
  "model": "openai/o3-mini",
53
62
  "temperature": 1.0,
63
+ "max_tokens": 1024
54
64
  },
55
65
  "opus-4": {
56
66
  "provider": "anthropic",
57
67
  "model": "anthropic/claude-opus-4-20250514",
58
68
  "temperature": 0.8,
69
+ "max_tokens": 32000
59
70
  },
60
71
  "sonnet-4": {
61
72
  "provider": "anthropic",
62
73
  "model": "anthropic/claude-sonnet-4-20250514",
63
74
  "temperature": 0.8,
75
+ "max_tokens": 1024
64
76
  },
65
77
  "together-ai-llama-2": {
66
78
  "provider": "together_ai",
67
79
  "model": "together_ai/togethercomputer/llama-2-70b",
68
80
  "temperature": 0.8,
81
+ "max_tokens": 1024
69
82
  },
70
83
  "groq-llama-3": {
71
84
  "provider": "groq",
72
85
  "model": "groq/llama3-70b-8192",
73
86
  "temperature": 0.8,
74
- },
87
+ "max_tokens": 1024
88
+ }
75
89
  }
76
90
  default_llm: Optional[str] = "gpt-4o"
77
91
 
@@ -86,7 +100,7 @@ def ensure_directory_exists(directory: str):
86
100
 
87
101
 
88
102
  def validate_config_data(filepath: str):
89
- with open(filepath, "r") as file:
103
+ with open(filepath, "r", encoding="utf-8") as file:
90
104
  data = json.load(file)
91
105
  return data
92
106
 
@@ -98,8 +112,8 @@ def read_data(filepath: str) -> ARAconfig:
98
112
  # If file does not exist, create it with default values
99
113
  default_config = ARAconfig()
100
114
 
101
- with open(filepath, "w") as file:
102
- json.dump(default_config.model_dump(), file, indent=4)
115
+ with open(filepath, "w", encoding="utf-8") as file:
116
+ json.dump(default_config.model_dump(mode='json'), file, indent=4)
103
117
 
104
118
  print(
105
119
  f"ara-cli configuration file '{filepath}' created with default configuration. Please modify it as needed and re-run your command"
@@ -112,8 +126,8 @@ def read_data(filepath: str) -> ARAconfig:
112
126
 
113
127
  # Function to save the modified configuration back to the JSON file
114
128
  def save_data(filepath: str, config: ARAconfig):
115
- with open(filepath, "w") as file:
116
- json.dump(config.dict(), file, indent=4)
129
+ with open(filepath, "w", encoding="utf-8") as file:
130
+ json.dump(config.model_dump(mode='json'), file, indent=4)
117
131
 
118
132
 
119
133
  # Singleton for configuration management
@@ -129,4 +143,4 @@ class ConfigManager:
129
143
  makedirs(config_dir)
130
144
 
131
145
  cls._config_instance = read_data(filepath)
132
- return cls._config_instance
146
+ return cls._config_instance
@@ -0,0 +1,446 @@
1
+ from ara_cli.artefact_fuzzy_search import (
2
+ find_closest_name_matches,
3
+ extract_artefact_names_of_classifier,
4
+ )
5
+ from ara_cli.file_classifier import FileClassifier
6
+ from ara_cli.artefact_reader import ArtefactReader
7
+ from ara_cli.artefact_models.artefact_load import artefact_from_content
8
+ from ara_cli.artefact_models.artefact_model import Artefact
9
+ from typing import Optional, Dict, List, Tuple
10
+ import difflib
11
+ import os
12
+
13
+
14
+ def read_report_file():
15
+ file_path = "incompatible_artefacts_report.md"
16
+ try:
17
+ with open(file_path, "r", encoding="utf-8") as f:
18
+ content = f.read()
19
+ except OSError:
20
+ print(
21
+ 'Artefact scan results file not found. Did you run the "ara scan" command?'
22
+ )
23
+ return None
24
+ return content
25
+
26
+
27
+ def parse_report(content: str) -> Dict[str, List[Tuple[str, str]]]:
28
+ """
29
+ Parses the incompatible artefacts report and returns structured data.
30
+ Returns a dictionary where keys are artefact classifiers, and values are lists of (file_path, reason) tuples.
31
+ """
32
+ lines = content.splitlines()
33
+ issues = {}
34
+ current_classifier = None
35
+
36
+ if not lines or lines[0] != "# Artefact Check Report":
37
+ return issues
38
+ return issues
39
+
40
+ if len(lines) >= 3 and lines[2] == "No problems found.":
41
+ return issues
42
+ return issues
43
+
44
+ for line in lines[1:]:
45
+ line = line.strip()
46
+ if not line:
47
+ continue
48
+
49
+ if line.startswith("## "):
50
+ current_classifier = line[3:].strip()
51
+ issues[current_classifier] = []
52
+
53
+ elif line.startswith("- ") and current_classifier is not None:
54
+ parts = line.split("`", 2)
55
+ if len(parts) < 3:
56
+ continue
57
+
58
+ file_path = parts[1]
59
+ reason = parts[2].split(":", 1)[1].strip() if ":" in parts[2] else ""
60
+ issues[current_classifier].append((file_path, reason))
61
+
62
+ return issues
63
+
64
+
65
+ def read_artefact(file_path):
66
+ """Reads the artefact text from the given file path."""
67
+ try:
68
+ with open(file_path, "r", encoding="utf-8") as file:
69
+ return file.read()
70
+ except FileNotFoundError:
71
+ print(f"File not found: {file_path}")
72
+ return None
73
+
74
+
75
+ def determine_artefact_type_and_class(classifier):
76
+ from ara_cli.artefact_models.artefact_mapping import artefact_type_mapping
77
+ from ara_cli.artefact_models.artefact_model import ArtefactType
78
+
79
+ try:
80
+ artefact_type = ArtefactType(classifier)
81
+ except ValueError:
82
+ print(f"Invalid classifier: {classifier}")
83
+ return None, None
84
+
85
+ artefact_class = artefact_type_mapping.get(artefact_type)
86
+ if not artefact_class:
87
+ print(f"No artefact class found for {artefact_type}")
88
+ return None, None
89
+
90
+ return artefact_type, artefact_class
91
+
92
+
93
+ def construct_prompt(artefact_type, reason, file_path, artefact_text):
94
+ from ara_cli.artefact_models.artefact_model import ArtefactType
95
+
96
+ prompt = (
97
+ f"Correct the following {artefact_type.value} artefact to fix the issue: {reason}. "
98
+ "Provide the corrected artefact. Do not reformulate the artefact, "
99
+ "just fix the pydantic model errors, use correct grammar. "
100
+ "You should follow the name of the file "
101
+ f"from its path {file_path} for naming the artefact's title. "
102
+ "You are not allowed to use file extention in the artefact title. "
103
+ "You are not allowed to modify, delete or add tags. "
104
+ "User tag should be '@user_<username>'. The pydantic model already provides the '@user_' prefix. "
105
+ "So you should be careful to not make it @user_user_<username>. "
106
+ )
107
+
108
+ if artefact_type == ArtefactType.task:
109
+ prompt += (
110
+ "For task artefacts, if the action items looks like template or empty "
111
+ "then just delete those action items."
112
+ )
113
+
114
+ prompt += "\nThe current artefact is:\n" "```\n" f"{artefact_text}\n" "```"
115
+
116
+ return prompt
117
+
118
+
119
+ def run_agent(prompt, artefact_class):
120
+ from pydantic_ai import Agent
121
+
122
+ # gpt-4o
123
+ # anthropic:claude-3-7-sonnet-20250219
124
+ # anthropic:claude-4-sonnet-20250514
125
+ agent = Agent(
126
+ model="anthropic:claude-4-sonnet-20250514",
127
+ result_type=artefact_class,
128
+ instrument=True,
129
+ )
130
+ result = agent.run_sync(prompt)
131
+ return result.data
132
+
133
+
134
+ def write_corrected_artefact(file_path, corrected_text):
135
+ with open(file_path, "w", encoding="utf-8") as file:
136
+ file.write(corrected_text)
137
+ print(f"Fixed artefact at {file_path}")
138
+
139
+
140
+ def ask_for_correct_contribution(
141
+ artefact_info: Optional[tuple[str, str]] = None
142
+ ) -> tuple[str, str]:
143
+ """
144
+ Ask the user to provide a valid contribution when no match can be found.
145
+
146
+ Args:
147
+ artefact_info: Optional tuple containing (artefact_name, artefact_classifier)
148
+
149
+ Returns:
150
+ A tuple of (name, classifier) for the contribution
151
+ """
152
+
153
+ artefact_name, artefact_classifier = (
154
+ artefact_info if artefact_info else (None, None)
155
+ )
156
+ contribution_message = (
157
+ f"of {artefact_classifier} artefact '{artefact_name}'" if artefact_name else ""
158
+ )
159
+
160
+ print(
161
+ f"Can not determine a match for contribution {contribution_message}. "
162
+ f"Please provide a valid contribution or contribution will be empty (<classifier> <file_name>)."
163
+ )
164
+
165
+ user_input = input().strip()
166
+
167
+ if not user_input:
168
+ return None, None
169
+
170
+ parts = user_input.split(maxsplit=1)
171
+ if len(parts) != 2:
172
+ print("Invalid input format. Expected: <classifier> <file_name>")
173
+ return None, None
174
+
175
+ classifier, name = parts
176
+ return name, classifier
177
+
178
+
179
+ def ask_for_contribution_choice(
180
+ choices, artefact_info: Optional[tuple[str, str]] = None
181
+ ) -> Optional[str]:
182
+ artefact_name, artefact_classifier = artefact_info
183
+ message = "Found multiple close matches for the contribution"
184
+ if artefact_name and artefact_classifier:
185
+ message += f" of the {artefact_classifier} '{artefact_name}'"
186
+ print(f"{message}.")
187
+ for i, contribution in enumerate(choices):
188
+ print(f"{i + 1}: {contribution}")
189
+ choice_number = input(
190
+ "Please choose the artefact to use for contribution (enter number): "
191
+ )
192
+ try:
193
+ choice_index = int(choice_number) - 1
194
+ if choice_index < 0 or choice_index >= len(choices):
195
+ print("Invalid choice. Aborting contribution choice.")
196
+ return None
197
+ choice = choices[choice_index]
198
+ except ValueError:
199
+ print("Invalid input. Aborting contribution choice.")
200
+ return None
201
+ return choice
202
+
203
+
204
+ def _has_valid_contribution(artefact: Artefact) -> bool:
205
+ contribution = artefact.contribution
206
+ return contribution and contribution.artefact_name and contribution.classifier
207
+
208
+
209
+ def _update_rule(
210
+ artefact: Artefact, name: str, classifier: str, classified_file_info: dict
211
+ ) -> None:
212
+ """Updates the rule in the contribution if a close match is found."""
213
+ rule = artefact.contribution.rule
214
+
215
+ content, artefact_data = ArtefactReader.read_artefact_data(
216
+ artefact_name=name,
217
+ classifier=classifier,
218
+ classified_file_info=classified_file_info,
219
+ )
220
+
221
+ parent = artefact_from_content(content=content)
222
+ rules = parent.rules
223
+
224
+ closest_rule_match = difflib.get_close_matches(rule, rules, cutoff=0.5)
225
+ if closest_rule_match:
226
+ artefact.contribution.rule = closest_rule_match[0]
227
+
228
+
229
+ def _set_contribution_multiple_matches(
230
+ artefact: Artefact,
231
+ closest_matches: list,
232
+ artefact_tuple: tuple,
233
+ classified_file_info: dict,
234
+ ) -> tuple[Artefact, bool]:
235
+ contribution = artefact.contribution
236
+ classifier = contribution.classifier
237
+ original_name = contribution.artefact_name
238
+
239
+ closest_match = closest_matches[0]
240
+ if len(closest_matches) > 1:
241
+ closest_match = ask_for_contribution_choice(closest_matches, artefact_tuple)
242
+
243
+ if not closest_match:
244
+ print(
245
+ f"Contribution of {artefact_tuple[1]} '{artefact_tuple[0]}' will be empty."
246
+ )
247
+ artefact.contribution = None
248
+ return artefact, True
249
+
250
+ print(
251
+ f"Updating contribution of {artefact_tuple[1]} '{artefact_tuple[0]}' to {classifier} '{closest_match}'"
252
+ )
253
+ contribution.artefact_name = closest_match
254
+ artefact.contribution = contribution
255
+
256
+ if contribution.rule:
257
+ _update_rule(artefact, original_name, classifier, classified_file_info)
258
+
259
+ return artefact, True
260
+
261
+
262
+ def set_closest_contribution(
263
+ artefact: Artefact, classified_file_info=None
264
+ ) -> tuple[Artefact, bool]:
265
+ if not _has_valid_contribution(artefact):
266
+ return artefact, False
267
+ contribution = artefact.contribution
268
+ name = contribution.artefact_name
269
+ classifier = contribution.classifier
270
+ rule = contribution.rule
271
+
272
+ if not classified_file_info:
273
+ file_classifier = FileClassifier(os)
274
+ classified_file_info = file_classifier.classify_files()
275
+
276
+ all_artefact_names = extract_artefact_names_of_classifier(
277
+ classified_files=classified_file_info, classifier=classifier
278
+ )
279
+ closest_matches = find_closest_name_matches(
280
+ artefact_name=name, all_artefact_names=all_artefact_names
281
+ )
282
+
283
+ artefact_tuple = (artefact.title, artefact._artefact_type().value)
284
+
285
+ if not closest_matches:
286
+ name, classifier = ask_for_correct_contribution(artefact_tuple)
287
+ if not name or not classifier:
288
+ artefact.contribution = None
289
+ return artefact, True
290
+ print(f"Updating contribution of {artefact._artefact_type().value} '{artefact.title}' to {classifier} '{name}'")
291
+ contribution.artefact_name = name
292
+ contribution.classifier = classifier
293
+ artefact.contribution = contribution
294
+ return artefact, True
295
+
296
+ if closest_matches[0] == name:
297
+ return artefact, False
298
+
299
+ return _set_contribution_multiple_matches(
300
+ artefact=artefact,
301
+ closest_matches=closest_matches,
302
+ artefact_tuple=artefact_tuple,
303
+ classified_file_info=classified_file_info,
304
+ )
305
+
306
+ print(
307
+ f"Updating contribution of {artefact._artefact_type().value} '{artefact.title}' to {classifier} '{closest_match}'"
308
+ )
309
+ contribution.artefact_name = closest_match
310
+ artefact.contribution = contribution
311
+
312
+ if not rule:
313
+ return artefact, True
314
+
315
+ content, artefact = ArtefactReader.read_artefact_data(
316
+ artefact_name=name,
317
+ classifier=classifier,
318
+ classified_file_info=classified_file_info,
319
+ )
320
+ parent = artefact_from_content(content=content)
321
+ rules = parent.rules
322
+
323
+ closest_rule_match = difflib.get_close_matches(rule, rules, cutoff=0.5)
324
+ if closest_rule_match:
325
+ contribution.rule = closest_rule_match
326
+ artefact.contribution = contribution
327
+ return artefact, True
328
+
329
+
330
+ def fix_title_mismatch(
331
+ file_path: str, artefact_text: str, artefact_class, **kwargs
332
+ ) -> str:
333
+ """
334
+ Deterministically fixes the title in the artefact text to match the filename.
335
+ """
336
+ base_name = os.path.basename(file_path)
337
+ correct_title_underscores, _ = os.path.splitext(base_name)
338
+ correct_title_spaces = correct_title_underscores.replace("_", " ")
339
+
340
+ title_prefix = artefact_class._title_prefix()
341
+
342
+ lines = artefact_text.splitlines()
343
+ new_lines = []
344
+ title_found_and_replaced = False
345
+
346
+ for line in lines:
347
+ if not title_found_and_replaced and line.strip().startswith(title_prefix):
348
+ new_lines.append(f"{title_prefix} {correct_title_spaces}")
349
+ title_found_and_replaced = True
350
+ else:
351
+ new_lines.append(line)
352
+
353
+ if not title_found_and_replaced:
354
+ print(
355
+ f"Warning: Title prefix '{title_prefix}' not found in {file_path}. Title could not be fixed."
356
+ )
357
+ return artefact_text
358
+
359
+ return "\n".join(new_lines)
360
+
361
+
362
+ def fix_contribution(
363
+ file_path: str,
364
+ artefact_text: str,
365
+ artefact_class: str,
366
+ classified_artefact_info: dict,
367
+ **kwargs,
368
+ ):
369
+ if not classified_artefact_info:
370
+ file_classifier = FileClassifier(os)
371
+ classified_artefact_info = file_classifier.classify_files()
372
+ artefact = artefact_class.deserialize(artefact_text)
373
+ artefact, _ = set_closest_contribution(artefact)
374
+ artefact_text = artefact.serialize()
375
+ return artefact_text
376
+
377
+
378
+ def apply_autofix(
379
+ file_path: str,
380
+ classifier: str,
381
+ reason: str,
382
+ deterministic: bool = True,
383
+ non_deterministic: bool = True,
384
+ classified_artefact_info: Optional[Dict[str, List[Dict[str, str]]]] = None,
385
+ ) -> bool:
386
+ artefact_text = read_artefact(file_path)
387
+ if artefact_text is None:
388
+ return False
389
+
390
+ artefact_type, artefact_class = determine_artefact_type_and_class(classifier)
391
+ if artefact_type is None or artefact_class is None:
392
+ return False
393
+
394
+ if classified_artefact_info is None:
395
+ file_classifier = FileClassifier(os)
396
+ classified_file_info = file_classifier.classified_files()
397
+
398
+ deterministic_markers_to_functions = {
399
+ "Filename-Title Mismatch": fix_title_mismatch,
400
+ "Invalid Contribution Reference": fix_contribution,
401
+ }
402
+
403
+ try:
404
+ deterministic_issue = next(
405
+ (
406
+ marker
407
+ for marker in deterministic_markers_to_functions.keys()
408
+ if marker in reason
409
+ ),
410
+ None,
411
+ )
412
+ except StopIteration:
413
+ pass
414
+ is_deterministic_issue = deterministic_issue is not None
415
+
416
+ if deterministic and is_deterministic_issue:
417
+ print(f"Attempting deterministic fix for {file_path}...")
418
+ corrected_text = deterministic_markers_to_functions[deterministic_issue](
419
+ file_path=file_path,
420
+ artefact_text=artefact_text,
421
+ artefact_class=artefact_class,
422
+ classified_artefact_info=classified_artefact_info,
423
+ )
424
+ write_corrected_artefact(file_path, corrected_text)
425
+ return True
426
+
427
+ # Attempt non-deterministic fix if requested and the issue is NOT deterministic
428
+ if non_deterministic and not is_deterministic_issue:
429
+ print(f"Attempting non-deterministic (LLM) fix for {file_path}...")
430
+ prompt = construct_prompt(artefact_type, reason, file_path, artefact_text)
431
+ try:
432
+ corrected_artefact = run_agent(prompt, artefact_class)
433
+ corrected_text = corrected_artefact.serialize()
434
+ write_corrected_artefact(file_path, corrected_text)
435
+ return True
436
+ except Exception as e:
437
+ print(f"LLM agent failed to fix artefact at {file_path}: {e}")
438
+ return False
439
+
440
+ # Log if a fix was skipped due to flags
441
+ if is_deterministic_issue and not deterministic:
442
+ print(f"Skipping deterministic fix for {file_path} as per request.")
443
+ elif not is_deterministic_issue and not non_deterministic:
444
+ print(f"Skipping non-deterministic fix for {file_path} as per request.")
445
+
446
+ return False