ara-cli 0.1.9.50__tar.gz → 0.1.9.51__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.
Files changed (170) hide show
  1. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/PKG-INFO +1 -1
  2. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/__main__.py +3 -1
  3. ara_cli-0.1.9.51/ara_cli/analyse_artefacts.py +133 -0
  4. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/ara_command_action.py +71 -50
  5. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/ara_command_parser.py +5 -0
  6. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/ara_config.py +65 -38
  7. ara_cli-0.1.9.51/ara_cli/artefact_lister.py +138 -0
  8. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/artefact_model.py +9 -7
  9. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/feature_artefact_model.py +4 -1
  10. ara_cli-0.1.9.51/ara_cli/artefact_reader.py +181 -0
  11. ara_cli-0.1.9.51/ara_cli/artefact_scan.py +46 -0
  12. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/file_classifier.py +21 -13
  13. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/prompt_extractor.py +10 -2
  14. ara_cli-0.1.9.51/ara_cli/tag_extractor.py +28 -0
  15. ara_cli-0.1.9.51/ara_cli/templates/specification_breakdown_files/template.concept.md +25 -0
  16. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_ara_command_action.py +242 -108
  17. ara_cli-0.1.9.51/ara_cli/tests/test_artefact_lister.py +573 -0
  18. ara_cli-0.1.9.51/ara_cli/tests/test_artefact_reader.py +57 -0
  19. ara_cli-0.1.9.51/ara_cli/tests/test_artefact_scan.py +126 -0
  20. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_file_classifier.py +68 -29
  21. ara_cli-0.1.9.51/ara_cli/tests/test_tag_extractor.py +45 -0
  22. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/version.py +1 -1
  23. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli.egg-info/PKG-INFO +1 -1
  24. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli.egg-info/SOURCES.txt +3 -0
  25. ara_cli-0.1.9.50/ara_cli/artefact_lister.py +0 -127
  26. ara_cli-0.1.9.50/ara_cli/artefact_reader.py +0 -134
  27. ara_cli-0.1.9.50/ara_cli/tag_extractor.py +0 -38
  28. ara_cli-0.1.9.50/ara_cli/templates/specification_breakdown_files/template.concept.md +0 -27
  29. ara_cli-0.1.9.50/ara_cli/tests/test_artefact_lister.py +0 -204
  30. ara_cli-0.1.9.50/ara_cli/tests/test_artefact_reader.py +0 -85
  31. ara_cli-0.1.9.50/ara_cli/tests/test_tag_extractor.py +0 -64
  32. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/MANIFEST.in +0 -0
  33. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/README.md +0 -0
  34. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/__init__.py +0 -0
  35. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact.py +0 -0
  36. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_creator.py +0 -0
  37. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_deleter.py +0 -0
  38. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_fuzzy_search.py +0 -0
  39. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_link_updater.py +0 -0
  40. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/artefact_load.py +0 -0
  41. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/artefact_mapping.py +0 -0
  42. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/artefact_templates.py +0 -0
  43. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/businessgoal_artefact_model.py +0 -0
  44. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/capability_artefact_model.py +0 -0
  45. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/epic_artefact_model.py +0 -0
  46. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/example_artefact_model.py +0 -0
  47. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/issue_artefact_model.py +0 -0
  48. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/keyfeature_artefact_model.py +0 -0
  49. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/task_artefact_model.py +0 -0
  50. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/userstory_artefact_model.py +0 -0
  51. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_models/vision_artefact_model.py +0 -0
  52. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/artefact_renamer.py +0 -0
  53. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/chat.py +0 -0
  54. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/classifier.py +0 -0
  55. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/codefusionretriever.py +0 -0
  56. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/codehierachieretriever.py +0 -0
  57. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/commandline_completer.py +0 -0
  58. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/directory_navigator.py +0 -0
  59. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/file_lister.py +0 -0
  60. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/filename_validator.py +0 -0
  61. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/list_filter.py +0 -0
  62. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/output_suppressor.py +0 -0
  63. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/prompt_chat.py +0 -0
  64. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/prompt_handler.py +0 -0
  65. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/prompt_rag.py +0 -0
  66. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/run_file_lister.py +0 -0
  67. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/template_manager.py +0 -0
  68. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/agile.artefacts +0 -0
  69. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +0 -0
  70. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/blueprints/empty.blueprint.md +0 -0
  71. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/blueprints/task_todo_list_C4_architecture_analysis.blueprint.md +0 -0
  72. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -0
  73. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/architecture_C4_analysis.commands.md +0 -0
  74. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/architecture_radon_cc_score.commands.md +0 -0
  75. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/architecture_radon_halstead_v.commands.md +0 -0
  76. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/architecture_radon_maintainability_score.commands.md +0 -0
  77. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -0
  78. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -0
  79. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -0
  80. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -0
  81. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -0
  82. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -0
  83. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/empty.commands.md +0 -0
  84. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -0
  85. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -0
  86. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -0
  87. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -0
  88. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -0
  89. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -0
  90. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -0
  91. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -0
  92. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/classify_task.intention.md +0 -0
  93. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/empty.intention.md +0 -0
  94. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/error_fixing.intention.md +0 -0
  95. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/feature_fix_steps_for_scenario.intention.md +0 -0
  96. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/feature_formulation.intention.md +0 -0
  97. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/feature_reverse_formulation_from_code.intention.md +0 -0
  98. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/feature_scenario_implementation.intention.md +0 -0
  99. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/feature_scenario_implementation_update.intention.md +0 -0
  100. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/feature_scenario_outline_extension.intention.md +0 -0
  101. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/feature_update_formulation.intention.md +0 -0
  102. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/fibonacci_example_implementation.intention.md +0 -0
  103. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/js_implementation_from_task_description.intention.md +0 -0
  104. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/js_steps_implementation.intention.md +0 -0
  105. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/python_cli_implementation_with_test.intention.md +0 -0
  106. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/python_code_understanding.intention.md +0 -0
  107. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/task_implementation.intention.md +0 -0
  108. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/task_prompt_control_by_status.intention.md +0 -0
  109. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/task_stepwise_implementation_by_number.intention.md +0 -0
  110. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/intentions/task_stepwise_implementation_by_status.intention.md +0 -0
  111. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/architecture_analyst.rules.md +0 -0
  112. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/code_analyst.rules.md +0 -0
  113. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/empty.rules.md +0 -0
  114. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/error_analyst.rules.md +0 -0
  115. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/gherkin_expert.rules.md +0 -0
  116. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/js_expert_developer.rules.md +0 -0
  117. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/product_owner.rules.md +0 -0
  118. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/python_behave.rules.md +0 -0
  119. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/prompt-modules/rules/python_developer.rules.md +0 -0
  120. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.concept.exploration.md +0 -0
  121. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.customer.exploration.md +0 -0
  122. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.customer.md +0 -0
  123. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.persona.exploration.md +0 -0
  124. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.persona.md +0 -0
  125. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.step.exploration.md +0 -0
  126. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.step.md +0 -0
  127. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.technology.exploration.md +0 -0
  128. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/specification_breakdown_files/template.technology.md +0 -0
  129. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.businessgoal +0 -0
  130. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.businessgoal.prompt_log.md +0 -0
  131. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.capability +0 -0
  132. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.capability.prompt_log.md +0 -0
  133. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.epic +0 -0
  134. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.epic.prompt_log.md +0 -0
  135. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.example +0 -0
  136. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.example.prompt_log.md +0 -0
  137. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.feature +0 -0
  138. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.feature.prompt_log.md +0 -0
  139. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.issue +0 -0
  140. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.issue.prompt_log.md +0 -0
  141. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.keyfeature +0 -0
  142. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.keyfeature.prompt_log.md +0 -0
  143. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.steps.prompt_log.md +0 -0
  144. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.task +0 -0
  145. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.task.prompt_log.md +0 -0
  146. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.userstory +0 -0
  147. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.userstory.prompt_log.md +0 -0
  148. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.vision +0 -0
  149. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/templates/template.vision.prompt_log.md +0 -0
  150. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/__init__.py +0 -0
  151. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_ara_config.py +0 -0
  152. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_artefact.py +0 -0
  153. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_artefact_fuzzy_search.py +0 -0
  154. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_artefact_link_updater.py +0 -0
  155. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_artefact_renamer.py +0 -0
  156. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_chat.py +0 -0
  157. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_classifier.py +0 -0
  158. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_directory_navigator.py +0 -0
  159. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_file_creator.py +0 -0
  160. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_file_lister.py +0 -0
  161. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_list_filter.py +0 -0
  162. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_template_manager.py +0 -0
  163. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/tests/test_update_config_prompt.py +0 -0
  164. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli/update_config_prompt.py +0 -0
  165. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli.egg-info/dependency_links.txt +0 -0
  166. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli.egg-info/entry_points.txt +0 -0
  167. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli.egg-info/requires.txt +0 -0
  168. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/ara_cli.egg-info/top_level.txt +0 -0
  169. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/setup.cfg +0 -0
  170. {ara_cli-0.1.9.50 → ara_cli-0.1.9.51}/setup.py +0 -0
@@ -1,3 +1,3 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ara_cli
3
- Version: 0.1.9.50
3
+ Version: 0.1.9.51
@@ -18,6 +18,7 @@ from ara_cli.ara_command_action import (
18
18
  set_status_action,
19
19
  set_user_action,
20
20
  classifier_directory_action,
21
+ scan_action
21
22
  )
22
23
  import argcomplete
23
24
  import sys
@@ -40,7 +41,8 @@ def define_action_mapping():
40
41
  "read-user": read_user_action,
41
42
  "set-status": set_status_action,
42
43
  "set-user": set_user_action,
43
- "classifier-directory": classifier_directory_action
44
+ "classifier-directory": classifier_directory_action,
45
+ "scan": scan_action
44
46
  }
45
47
 
46
48
 
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ analyse_artefacts.py
4
+
5
+ Walk a directory tree, try to deserialize every *.vision *.epic *.task … file
6
+ with the appropriate Pydantic artefact model, and write the list of files that
7
+ fail validation (plus the reason) to 'invalid_artefacts.txt'.
8
+ """
9
+
10
+ """
11
+ python analyse_artefacts.py <path_to_ara_folder ex: ./ara/>
12
+ """
13
+
14
+ from ara_cli.artefact_models import businessgoal_artefact_model, capability_artefact_model, epic_artefact_model, example_artefact_model, feature_artefact_model, issue_artefact_model, keyfeature_artefact_model, userstory_artefact_model, task_artefact_model, vision_artefact_model
15
+ from ara_cli.artefact_models.artefact_model import Artefact, ArtefactType
16
+ from pydantic import ValidationError
17
+ from typing import Dict, Type, List, Tuple
18
+ from pathlib import Path
19
+ import os
20
+ import sys
21
+
22
+
23
+ # --- import your domain model ----------------------------------------------
24
+ # Make sure this import path matches your project layout.
25
+ # (e.g. from ara_cli.artefact_model import Artefact, ArtefactType)
26
+ # ---------------------------------------------------------------------------
27
+
28
+
29
+ def build_type_map() -> Dict[ArtefactType, Type[Artefact]]:
30
+ type_map: Dict[ArtefactType, Type[Artefact]] = {}
31
+ queue: List[Type[Artefact]] = list(Artefact.__subclasses__())
32
+ while queue:
33
+ cls = queue.pop()
34
+ try:
35
+ artefact_type = cls._artefact_type()
36
+ type_map[artefact_type] = cls
37
+ except Exception:
38
+ pass # abstract / helper subclass
39
+ queue.extend(cls.__subclasses__())
40
+ if not type_map:
41
+ raise RuntimeError("No concrete Artefact subclasses found!")
42
+ return type_map
43
+
44
+
45
+ def find_artefact_files(root: Path, valid_exts: List[str]) -> List[Path]:
46
+ return [
47
+ p for p in root.rglob("*")
48
+ if p.is_file() and p.suffix.lstrip(".") in valid_exts
49
+ ]
50
+
51
+
52
+ def scan_folder(
53
+ root_folder: Path,
54
+ detailed_report: Path,
55
+ names_only_report: Path,
56
+ checklist_report: Path
57
+ ) -> Tuple[int, int]:
58
+ type_map = build_type_map()
59
+ valid_exts = [t.value for t in type_map]
60
+
61
+ artefact_files = find_artefact_files(root_folder, valid_exts)
62
+ bad: List[Tuple[Path, str]] = []
63
+
64
+ for file_path in artefact_files:
65
+ artefact_type = ArtefactType(file_path.suffix.lstrip("."))
66
+ artefact_cls = type_map[artefact_type]
67
+ text = file_path.read_text(encoding="utf-8")
68
+
69
+ try:
70
+ artefact_cls.deserialize(text)
71
+ except (ValidationError, ValueError, AssertionError) as e:
72
+ bad.append((file_path, str(e)))
73
+ except Exception as e:
74
+ bad.append((file_path, f"Unexpected error: {e!r}"))
75
+
76
+ # ───────────── write reports ────────────────────────────────────────────
77
+ if bad:
78
+ # 1) detailed txt
79
+ with detailed_report.open("w", encoding="utf-8") as f:
80
+ f.write("Invalid artefacts (file → reason)\n\n")
81
+ for path, err in bad:
82
+ f.write(f"{path} --> {err}\n")
83
+
84
+ # 2) names-only txt
85
+ with names_only_report.open("w", encoding="utf-8") as f:
86
+ for path, _ in bad:
87
+ f.write(f"{path}\n")
88
+
89
+ # 3) markdown checklist
90
+ with checklist_report.open("w", encoding="utf-8") as f:
91
+ f.write("# 📋 Artefact-fix checklist\n\n")
92
+ f.write("Tick a box once you’ve fixed & validated the file.\n\n")
93
+ for path, err in bad:
94
+ f.write(f"- [ ] `{path}` – {err}\n")
95
+
96
+ print(
97
+ f"\nFinished. {len(bad)}/{len(artefact_files)} files are invalid."
98
+ f"\nReports generated:"
99
+ f"\n • {detailed_report}"
100
+ f"\n • {names_only_report}"
101
+ f"\n • {checklist_report}"
102
+ )
103
+ else:
104
+ print(f"\nFinished. All {len(artefact_files)} artefacts are valid ✔️")
105
+ # clean up stale files from previous runs
106
+ for p in (detailed_report, names_only_report, checklist_report):
107
+ if p.exists():
108
+ p.unlink()
109
+
110
+ return len(artefact_files), len(bad)
111
+
112
+
113
+ # ─────────────────────────────── main ──────────────────────────────────────
114
+ def main() -> None:
115
+ if len(sys.argv) < 2:
116
+ print("Usage: python scan_artefacts.py <folder_to_scan>")
117
+ sys.exit(1)
118
+
119
+ root_folder = Path(sys.argv[1]).expanduser().resolve()
120
+ if not root_folder.is_dir():
121
+ print(f"Error: '{root_folder}' is not a directory.")
122
+ sys.exit(1)
123
+
124
+ scan_folder(
125
+ root_folder=root_folder,
126
+ detailed_report=Path("invalid_artefacts.txt"),
127
+ names_only_report=Path("invalid_artefact_names.txt"),
128
+ checklist_report=Path("invalid_artefacts_checklist.md"),
129
+ )
130
+
131
+
132
+ if __name__ == "__main__":
133
+ main()
@@ -269,7 +269,6 @@ def fetch_templates_action(args):
269
269
 
270
270
  def read_action(args):
271
271
  from ara_cli.artefact_reader import ArtefactReader
272
- from ara_cli.artefact import Artefact
273
272
  from ara_cli.file_classifier import FileClassifier
274
273
 
275
274
  classifier = args.classifier
@@ -277,17 +276,22 @@ def read_action(args):
277
276
  read_mode = args.read_mode
278
277
 
279
278
  file_classifier = FileClassifier(os)
280
- classified_artefacts = file_classifier.classify_files()
281
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
279
+ classified_artefacts = ArtefactReader.read_artefacts()
280
+ artefacts = classified_artefacts.get(classifier, [])
281
+ all_artefact_names = [a.title for a in artefacts]
282
+
282
283
  if artefact_name not in all_artefact_names:
283
- suggest_close_name_matches(artefact_name, all_artefact_names)
284
+ suggest_close_name_matches(
285
+ artefact_name,
286
+ all_artefact_names
287
+ )
284
288
  return
285
289
 
286
- content, file_path = ArtefactReader.read_artefact(artefact_name=artefact_name, classifier=classifier)
290
+ target_artefact = next(filter(
291
+ lambda x: x.title == artefact_name, artefacts
292
+ ))
287
293
 
288
294
  artefacts_by_classifier = {classifier: []}
289
- file_classifier = FileClassifier(os)
290
- classified_artefacts = file_classifier.classify_files()
291
295
 
292
296
  match read_mode:
293
297
  case "branch":
@@ -309,10 +313,7 @@ def read_action(args):
309
313
  print_content=True
310
314
  )
311
315
  case _:
312
- artefact = Artefact.from_content(content)
313
- artefact_path = next((classified_artefact.file_path for classified_artefact in classified_artefacts.get(classifier, []) if classified_artefact.name == artefact.name), artefact)
314
- artefact._file_path = artefact_path
315
- artefacts_by_classifier[classifier].append(artefact)
316
+ artefacts_by_classifier[classifier].append(target_artefact)
316
317
  file_classifier.print_classified_files(artefacts_by_classifier, print_content=True)
317
318
 
318
319
 
@@ -328,14 +329,14 @@ def reconnect_action(args):
328
329
  parent_name = args.parent_name
329
330
 
330
331
  file_classifier = FileClassifier(os)
331
- classified_artefacts = file_classifier.classify_files()
332
+ classified_artefacts_info = file_classifier.classify_files_new()
332
333
 
333
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
334
+ all_artefact_names = [info["title"] for info in classified_artefacts_info.get(classifier, [])]
334
335
  if artefact_name not in all_artefact_names:
335
336
  suggest_close_name_matches(artefact_name, all_artefact_names)
336
337
  return
337
338
 
338
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(parent_classifier, [])]
339
+ all_artefact_names = [info["title"] for info in classified_artefacts_info.get(parent_classifier, [])]
339
340
  if parent_name not in all_artefact_names:
340
341
  suggest_close_name_matches(parent_name, all_artefact_names)
341
342
  return
@@ -369,23 +370,27 @@ def reconnect_action(args):
369
370
 
370
371
 
371
372
  def read_status_action(args):
372
- from ara_cli.artefact_models.artefact_load import artefact_from_content
373
- from ara_cli.artefact_reader import ArtefactReader
374
373
  from ara_cli.file_classifier import FileClassifier
374
+ from ara_cli.artefact_models.artefact_load import artefact_from_content
375
375
 
376
376
  classifier = args.classifier
377
377
  artefact_name = args.parameter
378
378
 
379
379
  file_classifier = FileClassifier(os)
380
- classified_artefacts = file_classifier.classify_files()
380
+ artefact_info = file_classifier.classify_files_new()
381
+ artefact_info_dicts = artefact_info.get(classifier, [])
381
382
 
382
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
383
+ all_artefact_names = [artefact_info["title"] for artefact_info in artefact_info_dicts]
383
384
  if artefact_name not in all_artefact_names:
384
385
  suggest_close_name_matches(artefact_name, all_artefact_names)
385
386
  return
386
387
 
387
- content, file_path = ArtefactReader.read_artefact(artefact_name=artefact_name, classifier=classifier)
388
+ artefact_info = next(filter(
389
+ lambda x: x["title"] == artefact_name, artefact_info_dicts
390
+ ))
388
391
 
392
+ with open(artefact_info["file_path"], 'r') as file:
393
+ content = file.read()
389
394
  artefact = artefact_from_content(content)
390
395
 
391
396
  status = artefact.status
@@ -398,21 +403,26 @@ def read_status_action(args):
398
403
 
399
404
  def read_user_action(args):
400
405
  from ara_cli.artefact_models.artefact_load import artefact_from_content
401
- from ara_cli.artefact_reader import ArtefactReader
402
406
  from ara_cli.file_classifier import FileClassifier
403
407
 
404
408
  classifier = args.classifier
405
409
  artefact_name = args.parameter
406
410
 
407
411
  file_classifier = FileClassifier(os)
408
- classified_artefacts = file_classifier.classify_files()
412
+ artefact_info = file_classifier.classify_files_new()
413
+ artefact_info_dicts = artefact_info.get(classifier, [])
409
414
 
410
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
415
+ all_artefact_names = [artefact_info["title"] for artefact_info in artefact_info_dicts]
411
416
  if artefact_name not in all_artefact_names:
412
417
  suggest_close_name_matches(artefact_name, all_artefact_names)
413
418
  return
414
419
 
415
- content, _ = ArtefactReader.read_artefact(artefact_name=artefact_name, classifier=classifier)
420
+ artefact_info = next(filter(
421
+ lambda x: x["title"] == artefact_name, artefact_info_dicts
422
+ ))
423
+
424
+ with open(artefact_info["file_path"], 'r') as file:
425
+ content = file.read()
416
426
  artefact = artefact_from_content(content)
417
427
 
418
428
  user_tags = artefact.users
@@ -427,8 +437,6 @@ def read_user_action(args):
427
437
  def set_status_action(args):
428
438
  from ara_cli.artefact_models.artefact_model import ALLOWED_STATUS_VALUES
429
439
  from ara_cli.artefact_models.artefact_load import artefact_from_content
430
- from ara_cli.directory_navigator import DirectoryNavigator
431
- from ara_cli.artefact_reader import ArtefactReader
432
440
  from ara_cli.file_classifier import FileClassifier
433
441
 
434
442
  status_tags = ALLOWED_STATUS_VALUES
@@ -443,36 +451,34 @@ def set_status_action(args):
443
451
  check_validity(new_status in status_tags, "Invalid status provided. Please provide a valid status.")
444
452
 
445
453
  file_classifier = FileClassifier(os)
446
- classified_artefacts = file_classifier.classify_files()
447
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
454
+ classified_artefacts_info = file_classifier.classify_files_new()
455
+ classified_artefact_dict = classified_artefacts_info.get(classifier, [])
456
+ all_artefact_names = [artefact_info["title"] for artefact_info in classified_artefact_dict]
448
457
 
449
458
  if artefact_name not in all_artefact_names:
450
459
  suggest_close_name_matches(artefact_name, all_artefact_names)
451
460
  return
452
461
 
453
- content, file_path = ArtefactReader.read_artefact(artefact_name=artefact_name, classifier=classifier)
454
-
455
- directory_navigator = DirectoryNavigator()
456
- original_directory = directory_navigator.navigate_to_target()
462
+ artefact_info = next(filter(
463
+ lambda x: x["title"] == artefact_name, classified_artefact_dict
464
+ ))
457
465
 
466
+ with open(artefact_info["file_path"], 'r') as file:
467
+ content = file.read()
458
468
  artefact = artefact_from_content(content)
469
+
459
470
  artefact.status = new_status
460
471
 
461
472
  serialized_content = artefact.serialize()
462
- with open(f"{file_path}", 'w') as file:
473
+ with open(f"{artefact_info['file_path']}", 'w') as file:
463
474
  file.write(serialized_content)
464
475
 
465
- os.chdir(original_directory)
466
-
467
476
  print(f"Status of task '{artefact_name}' has been updated to '{new_status}'.")
468
477
 
469
478
 
470
479
  def set_user_action(args):
471
- from ara_cli.artefact import Artefact
472
- from ara_cli.artefact_reader import ArtefactReader
473
480
  from ara_cli.file_classifier import FileClassifier
474
-
475
- user_prefix = "user_"
481
+ from ara_cli.artefact_models.artefact_load import artefact_from_content
476
482
 
477
483
  classifier = args.classifier
478
484
  artefact_name = args.parameter
@@ -482,27 +488,28 @@ def set_user_action(args):
482
488
  new_user = new_user.lstrip('@')
483
489
 
484
490
  file_classifier = FileClassifier(os)
485
- classified_artefacts = file_classifier.classify_files()
486
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
491
+ classified_artefacts_info = file_classifier.classify_files_new()
492
+ classified_artefact_dict = classified_artefacts_info.get(classifier, [])
493
+ all_artefact_names = [artefact_info["title"] for artefact_info in classified_artefact_dict]
487
494
 
488
495
  if artefact_name not in all_artefact_names:
489
496
  suggest_close_name_matches(artefact_name, all_artefact_names)
490
497
  return
491
498
 
492
- content, file_path = ArtefactReader.read_artefact(artefact_name=artefact_name, classifier=classifier)
493
- artefact = Artefact.from_content(content)
494
- artefact_path = next((classified_artefact.file_path for classified_artefact in classified_artefacts.get(classifier, []) if classified_artefact.name == artefact.name), artefact.file_path)
495
- artefact._file_path = artefact_path
496
-
497
- current_tags = artefact.tags
499
+ artefact_info = next(filter(
500
+ lambda x: x["title"] == artefact_name, classified_artefact_dict
501
+ ))
498
502
 
499
- current_tags = {tag for tag in current_tags if not tag.startswith(user_prefix)}
503
+ with open(artefact_info["file_path"], 'r') as file:
504
+ content = file.read()
505
+ artefact = artefact_from_content(content)
500
506
 
501
- current_tags.add(f"{user_prefix}{new_user}")
507
+ artefact.users = [new_user]
502
508
 
503
- artefact._tags = set(current_tags)
509
+ serialized_content = artefact.serialize()
504
510
 
505
- artefact.write_to_file()
511
+ with open(artefact_info["file_path"], 'w') as file:
512
+ file.write(serialized_content)
506
513
 
507
514
  print(f"User of task '{artefact_name}' has been updated to '{new_user}'.")
508
515
 
@@ -513,3 +520,17 @@ def classifier_directory_action(args):
513
520
  classifier = args.classifier
514
521
  subdirectory = Classifier.get_sub_directory(classifier)
515
522
  print(subdirectory)
523
+
524
+
525
+ def scan_action(args):
526
+ from ara_cli.file_classifier import FileClassifier
527
+ from ara_cli.artefact_scan import find_invalid_files, show_results
528
+ import os
529
+
530
+ classified_artefact_info = FileClassifier(os).classify_files_new()
531
+ invalid_artefacts = {}
532
+ for classifier in classified_artefact_info:
533
+ invalid = find_invalid_files(classified_artefact_info, classifier)
534
+ if invalid:
535
+ invalid_artefacts[classifier] = invalid
536
+ show_results(invalid_artefacts)
@@ -215,6 +215,10 @@ def classifier_directory_parser(subparsers):
215
215
  classifier_directory_parser.add_argument("classifier", choices=classifiers, help="Classifier of the artefact type")
216
216
 
217
217
 
218
+ def scan_parser(subparsers):
219
+ subparsers.add_parser("scan", help="Scan ARA tree for incompatible artefacts.")
220
+
221
+
218
222
  class CustomHelpFormatter(argparse.HelpFormatter):
219
223
  def format_help(self):
220
224
  from sys import argv
@@ -301,5 +305,6 @@ def action_parser():
301
305
  set_status_parser(subparsers)
302
306
  set_user_parser(subparsers)
303
307
  classifier_directory_parser(subparsers)
308
+ scan_parser(subparsers)
304
309
 
305
310
  return parser
@@ -11,51 +11,76 @@ DEFAULT_CONFIG_LOCATION = "./ara/.araconfig/ara_config.json"
11
11
 
12
12
 
13
13
  class ARAconfig(BaseModel):
14
- ext_code_dirs: List[Dict[str, str]] = [{"source_dir_1": "./src"}, {"source_dir_2": "./tests"}]
14
+ ext_code_dirs: List[Dict[str, str]] = [
15
+ {"source_dir_1": "./src"},
16
+ {"source_dir_2": "./tests"},
17
+ ]
15
18
  glossary_dir: str = "./glossary"
16
19
  doc_dir: str = "./docs"
17
20
  local_prompt_templates_dir: str = "./ara/.araconfig"
18
21
  local_ara_templates_dir: str = "./ara/.araconfig/templates/"
19
22
  ara_prompt_given_list_includes: List[str] = [
20
- "*.businessgoal", "*.vision", "*.capability", "*.keyfeature",
21
- "*.epic", "*.userstory", "*.example", "*.feature", "*.task", "*.py", "*.md", "*.png", "*.jpg", "*.jpeg"
23
+ "*.businessgoal",
24
+ "*.vision",
25
+ "*.capability",
26
+ "*.keyfeature",
27
+ "*.epic",
28
+ "*.userstory",
29
+ "*.example",
30
+ "*.feature",
31
+ "*.task",
32
+ "*.py",
33
+ "*.md",
34
+ "*.png",
35
+ "*.jpg",
36
+ "*.jpeg",
22
37
  ]
23
38
  llm_config: Dict[str, Dict[str, Union[str, float]]] = {
24
- "gpt-4o":
25
- {
26
- "provider": "openai",
27
- "model": "openai/gpt-4o",
28
- "temperature": 0.8
29
- },
39
+ "gpt-4o": {
40
+ "provider": "openai",
41
+ "model": "openai/gpt-4o",
42
+ "temperature": 0.8
43
+ },
30
44
  "gpt-4.5-preview": {
31
45
  "provider": "openai",
32
46
  "model": "openai/gpt-4.5-preview",
33
- "temperature": 0.8
47
+ "temperature": 0.8,
48
+ },
49
+ "o3-mini": {
50
+ "provider": "openai",
51
+ "model": "openai/o3-mini",
52
+ "temperature": 1.0,
53
+ },
54
+ "claude-3.7": {
55
+ "provider": "anthropic",
56
+ "model": "anthropic/claude-3-7-sonnet-20250219",
57
+ "temperature": 0.8,
58
+ },
59
+ "together-ai-llama-2": {
60
+ "provider": "together_ai",
61
+ "model": "together_ai/togethercomputer/llama-2-70b",
62
+ "temperature": 0.8,
63
+ },
64
+ "groq-llama-3": {
65
+ "provider": "groq",
66
+ "model": "groq/llama3-70b-8192",
67
+ "temperature": 0.8,
68
+ },
69
+ "opus-4": {
70
+ "provider": "anthropic",
71
+ "model": "anthropic/claude-opus-4-20250514",
72
+ "temperature": 0.8,
73
+ },
74
+ "sonnet-3.7": {
75
+ "provider": "anthropic",
76
+ "model": "anthropic/claude-3-7-sonnet-20250219",
77
+ "temperature": 0.8,
78
+ },
79
+ "sonnet-4": {
80
+ "provider": "anthropic",
81
+ "model": "anthropic/claude-sonnet-4-20250514",
82
+ "temperature": 0.8,
34
83
  },
35
- "o3-mini":
36
- {
37
- "provider": "openai",
38
- "model": "openai/o3-mini",
39
- "temperature": 1.0
40
- },
41
- "claude-3.7":
42
- {
43
- "provider": "anthropic",
44
- "model": "anthropic/claude-3-7-sonnet-20250219",
45
- "temperature": 0.8
46
- },
47
- "together-ai-llama-2":
48
- {
49
- "provider": "together_ai",
50
- "model": "together_ai/togethercomputer/llama-2-70b",
51
- "temperature": 0.8
52
- },
53
- "groq-llama-3":
54
- {
55
- "provider": "groq",
56
- "model": "groq/llama3-70b-8192",
57
- "temperature": 0.8
58
- }
59
84
  }
60
85
  default_llm: Optional[str] = "gpt-4o"
61
86
 
@@ -70,7 +95,7 @@ def ensure_directory_exists(directory: str):
70
95
 
71
96
 
72
97
  def validate_config_data(filepath: str):
73
- with open(filepath, 'r') as file:
98
+ with open(filepath, "r") as file:
74
99
  data = json.load(file)
75
100
  return data
76
101
 
@@ -82,10 +107,12 @@ def read_data(filepath: str) -> ARAconfig:
82
107
  # If file does not exist, create it with default values
83
108
  default_config = ARAconfig()
84
109
 
85
- with open(filepath, 'w') as file:
110
+ with open(filepath, "w") as file:
86
111
  json.dump(default_config.model_dump(), file, indent=4)
87
112
 
88
- print(f"ara-cli configuration file '{filepath}' created with default configuration. Please modify it as needed and re-run your command")
113
+ print(
114
+ f"ara-cli configuration file '{filepath}' created with default configuration. Please modify it as needed and re-run your command"
115
+ )
89
116
  exit() # Exit the application
90
117
 
91
118
  data = validate_config_data(filepath)
@@ -94,7 +121,7 @@ def read_data(filepath: str) -> ARAconfig:
94
121
 
95
122
  # Function to save the modified configuration back to the JSON file
96
123
  def save_data(filepath: str, config: ARAconfig):
97
- with open(filepath, 'w') as file:
124
+ with open(filepath, "w") as file:
98
125
  json.dump(config.dict(), file, indent=4)
99
126
 
100
127