ara-cli 0.1.4.30__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 (116) hide show
  1. ara_cli-0.1.4.30/MANIFEST.in +1 -0
  2. ara_cli-0.1.4.30/PKG-INFO +3 -0
  3. ara_cli-0.1.4.30/README.md +67 -0
  4. ara_cli-0.1.4.30/ara_cli/__init__.py +1 -0
  5. ara_cli-0.1.4.30/ara_cli/__main__.py +259 -0
  6. ara_cli-0.1.4.30/ara_cli/ara_config.py +52 -0
  7. ara_cli-0.1.4.30/ara_cli/artefact.py +47 -0
  8. ara_cli-0.1.4.30/ara_cli/artefact_creator.py +120 -0
  9. ara_cli-0.1.4.30/ara_cli/artefact_deleter.py +42 -0
  10. ara_cli-0.1.4.30/ara_cli/artefact_link_updater.py +72 -0
  11. ara_cli-0.1.4.30/ara_cli/artefact_lister.py +17 -0
  12. ara_cli-0.1.4.30/ara_cli/artefact_renamer.py +86 -0
  13. ara_cli-0.1.4.30/ara_cli/chat.py +93 -0
  14. ara_cli-0.1.4.30/ara_cli/classifier.py +60 -0
  15. ara_cli-0.1.4.30/ara_cli/classifier_validator.py +4 -0
  16. ara_cli-0.1.4.30/ara_cli/directory_navigator.py +62 -0
  17. ara_cli-0.1.4.30/ara_cli/file_classifier.py +32 -0
  18. ara_cli-0.1.4.30/ara_cli/file_lister.py +31 -0
  19. ara_cli-0.1.4.30/ara_cli/filename_validator.py +4 -0
  20. ara_cli-0.1.4.30/ara_cli/prompt_extractor.py +130 -0
  21. ara_cli-0.1.4.30/ara_cli/prompt_handler.py +370 -0
  22. ara_cli-0.1.4.30/ara_cli/run_file_lister.py +72 -0
  23. ara_cli-0.1.4.30/ara_cli/template_manager.py +155 -0
  24. ara_cli-0.1.4.30/ara_cli/templates/agile.artefacts +171 -0
  25. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_businessgoal.md +18 -0
  26. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_capability.md +18 -0
  27. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_epic.md +18 -0
  28. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_feature.md +18 -0
  29. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_keyfeature.md +18 -0
  30. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_task.md +18 -0
  31. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_userstory.md +18 -0
  32. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_vision.md +18 -0
  33. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_businessgoal.md +2 -0
  34. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_capability.md +2 -0
  35. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_epic.md +2 -0
  36. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_feature.md +2 -0
  37. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_keyfeature.md +2 -0
  38. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_task.md +2 -0
  39. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_userstory.md +2 -0
  40. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_vision.md +2 -0
  41. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_businessgoal.md +22 -0
  42. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_capability.md +22 -0
  43. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_epic.md +22 -0
  44. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_feature.md +22 -0
  45. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_keyfeature.md +22 -0
  46. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_task.md +22 -0
  47. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_userstory.md +22 -0
  48. ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_vision.md +22 -0
  49. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_artefact_classification_commands.md +9 -0
  50. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_artefact_extension_commands.md +17 -0
  51. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_artefact_formulation_commands.md +14 -0
  52. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_code_generation_complex_commands.md +20 -0
  53. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_code_generation_simple_commands.md +13 -0
  54. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_empty_commands.md +14 -0
  55. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_error_fixing_commands.md +20 -0
  56. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_refactoring_analysis_commands.md +9 -0
  57. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_refactoring_commands.md +15 -0
  58. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_classify_task_intention_and_context.md +6 -0
  59. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_empty_intention_and_context.md +2 -0
  60. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_extend_feature_and_implementation_intention_and_context.md +7 -0
  61. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_feature_scenario_adaption_intention_and_context.md +8 -0
  62. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_feature_scenario_implementation_intention_and_context.md +5 -0
  63. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_cli_implementation_with_test_intention_and_context.md +6 -0
  64. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_code_understanding_intention_and_context.md +18 -0
  65. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_error_fixing_intention_and_context.md +9 -0
  66. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_implementation_from_task_description_intention_and_context.md +4 -0
  67. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_empty_rules.md +2 -0
  68. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_error_analysis_expert_rules.md +14 -0
  69. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_product_owner_rules.md +22 -0
  70. ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_python_expert_developer_rules.md +8 -0
  71. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.concept.md +27 -0
  72. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.concept_exploration.md +76 -0
  73. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.customer.md +30 -0
  74. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.customer_exploration.md +62 -0
  75. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.persona.md +71 -0
  76. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.persona_exploration.md +106 -0
  77. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.step.md +43 -0
  78. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.step_exploration.md +0 -0
  79. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.technology.md +23 -0
  80. ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.technology_exploration.md +77 -0
  81. ara_cli-0.1.4.30/ara_cli/templates/template.businessgoal +10 -0
  82. ara_cli-0.1.4.30/ara_cli/templates/template.businessgoal_exploration.md +7 -0
  83. ara_cli-0.1.4.30/ara_cli/templates/template.capability +10 -0
  84. ara_cli-0.1.4.30/ara_cli/templates/template.capability_exploration.md +7 -0
  85. ara_cli-0.1.4.30/ara_cli/templates/template.epic +15 -0
  86. ara_cli-0.1.4.30/ara_cli/templates/template.epic_exploration.md +7 -0
  87. ara_cli-0.1.4.30/ara_cli/templates/template.example +6 -0
  88. ara_cli-0.1.4.30/ara_cli/templates/template.example_exploration.md +7 -0
  89. ara_cli-0.1.4.30/ara_cli/templates/template.feature +25 -0
  90. ara_cli-0.1.4.30/ara_cli/templates/template.feature_exploration.md +7 -0
  91. ara_cli-0.1.4.30/ara_cli/templates/template.issue +14 -0
  92. ara_cli-0.1.4.30/ara_cli/templates/template.keyfeature +15 -0
  93. ara_cli-0.1.4.30/ara_cli/templates/template.keyfeature_exploration.md +7 -0
  94. ara_cli-0.1.4.30/ara_cli/templates/template.steps_exploration.md +7 -0
  95. ara_cli-0.1.4.30/ara_cli/templates/template.task +8 -0
  96. ara_cli-0.1.4.30/ara_cli/templates/template.task_exploration.md +7 -0
  97. ara_cli-0.1.4.30/ara_cli/templates/template.userstory +17 -0
  98. ara_cli-0.1.4.30/ara_cli/templates/template.userstory_exploration.md +7 -0
  99. ara_cli-0.1.4.30/ara_cli/templates/template.vision +14 -0
  100. ara_cli-0.1.4.30/ara_cli/templates/template.vision_exploration.md +7 -0
  101. ara_cli-0.1.4.30/ara_cli/tests/__init__.py +0 -0
  102. ara_cli-0.1.4.30/ara_cli/tests/test_artefact_link_updater.py +56 -0
  103. ara_cli-0.1.4.30/ara_cli/tests/test_artefact_renamer.py +116 -0
  104. ara_cli-0.1.4.30/ara_cli/tests/test_directory_navigator.py +13 -0
  105. ara_cli-0.1.4.30/ara_cli/tests/test_file_creator.py +108 -0
  106. ara_cli-0.1.4.30/ara_cli/tests/test_template_manager.py +118 -0
  107. ara_cli-0.1.4.30/ara_cli/vectorDB.py +203 -0
  108. ara_cli-0.1.4.30/ara_cli/version.py +2 -0
  109. ara_cli-0.1.4.30/ara_cli.egg-info/PKG-INFO +3 -0
  110. ara_cli-0.1.4.30/ara_cli.egg-info/SOURCES.txt +114 -0
  111. ara_cli-0.1.4.30/ara_cli.egg-info/dependency_links.txt +1 -0
  112. ara_cli-0.1.4.30/ara_cli.egg-info/entry_points.txt +3 -0
  113. ara_cli-0.1.4.30/ara_cli.egg-info/requires.txt +6 -0
  114. ara_cli-0.1.4.30/ara_cli.egg-info/top_level.txt +1 -0
  115. ara_cli-0.1.4.30/setup.cfg +4 -0
  116. ara_cli-0.1.4.30/setup.py +30 -0
@@ -0,0 +1 @@
1
+ recursive-include ara_cli/templates *
@@ -0,0 +1,3 @@
1
+ Metadata-Version: 2.1
2
+ Name: ara_cli
3
+ Version: 0.1.4.30
@@ -0,0 +1,67 @@
1
+ - [ara-tool](#ara-tool)
2
+ - [best practices commit and merge and recreate workspace](#best-practices-commit-and-merge-and-recreate-workspace)
3
+ - [test and run during development](#test-and-run-during-development)
4
+ - [set version and build and install locally for testing outside of container](#set-version-and-build-and-install-locally-for-testing-outside-of-container)
5
+ - [upload to test pypi with test pypi API key](#upload-to-test-pypi-with-test-pypi-api-key)
6
+ - [upload to live pypi with talsen team production API key (from main branch)](#upload-to-live-pypi-with-talsen-team-production-api-key-from-main-branch)
7
+
8
+
9
+ # ara-tool
10
+ ## best practices commit and merge and recreate workspace
11
+ 1. commit and publish everything in the branch
12
+ 2. go to git and merge
13
+ 3. destroy old workspace from merged branch from within the working directory
14
+ > workspace destroy
15
+ 4. go back in to top level working directory and check which repos are available for branching
16
+ > workspace repos
17
+ 5. create new workspacce with workspace command: workspace new <repo> <new-workspace-name>
18
+ > workspace new ara-cmd hans-ara-cmd
19
+ 6. switch to new workspace
20
+
21
+ ## test and run during development
22
+ 1. run `bash deploy.sh`
23
+ 2. run `bash login.sh`
24
+ 3. --> in container --> for behave BDD tests `bash test-feature.sh`
25
+ 3. a) --> in container --> for only 1 test: behave ara/features/<name>.feature
26
+ 3. b) --> in container --> for unit tests and (if successful) feature tests: `bash test-all.sh`
27
+ 4. --> in container --> for unit tests in folder ara_cli `pytest --cov=. --cov-report term-missing tests/ `
28
+ 5. --> in container --> example for running a single unit test in ara_cli folder `pytest tests/test_template_manager.py::test_files_created_from_template`
29
+ 6. if change is successfull always commit before proceeding with next change
30
+ 7. if change was successfully reviewd merge in gitlab: https://git.talsen.team/talsen-products/ara-tool/-/merge_requests/new
31
+
32
+ ## set version and build and install locally for testing outside of container
33
+ 1. set the new verion in the ara_cli/version.py file
34
+ 2. adapt the version number in the 'local_install.sh' file
35
+ 3. use `bash local_install.sh` to control local setup procedure
36
+ 4. Test the functionality
37
+
38
+ ## upload to test pypi with test pypi API key
39
+ 1. run `bash deploy.sh`
40
+ 2. run `login.sh`
41
+ 3. in `setup.py` and `local_install.sh` increment `version` otherwise upload will fail!
42
+ 3. a) merge to staging and continue from a new workspace
43
+ 4. from inside container run `python setup.py sdist bdist_wheel`
44
+ 5. run the following command:
45
+
46
+ ```bash
47
+ twine upload --repository testpypi dist/* --verbose -u __token__ -p pypi-AgENdGVzdC5weXBpLm9yZwIkZGI5YzUyZTUtNDhjMy00NmI3LTgxNmMtY2QwMTRjYjZmZjlmAAIqWzMsImM3ZTM0MDRmLWU1MzUtNDliMi05ZDhiLWQ0NGUyNzlmYTU0MiJdAAAGID-dX7aQZZimTyUQeKPzbP0TlqMEpLQlzRW7VJr1JKab
48
+ ```
49
+
50
+ this will upload to a test pypi account.
51
+
52
+
53
+ 6. run `python3 -m pip install --index-url https://test.pypi.org/simple/ ara_cli==<VERSION>`
54
+ 7. run `ara -h`
55
+ 8. if everything has worked (upload, installation and usage) you can now continue to upload the package to pypi (live)
56
+
57
+
58
+ ## upload to live pypi with talsen team production API key (from main branch)
59
+ 1. run `bash deploy.sh`
60
+ 2. run `login.sh`
61
+ 3. `dist` folder should still be there from the testupload (otherwise do `python setup.py sdist bdist_wheel` inside the container again), do NOT upload to live without previously testing in test pypi!
62
+ 4. Get the API-Key from [nextcloud](https://cloud.talsen.team/apps/keeweb/?open=%2Finfrastructure%2Fpublic-services%2Fapi-keys.kdbx)
63
+ 5. Get the Password from Hans or DevOps
64
+ 6. run the following command:
65
+ ```bash
66
+ twine upload dist/* --verbose -u __token__ -p <API-Key>
67
+ ```
@@ -0,0 +1 @@
1
+ from .version import __version__
@@ -0,0 +1,259 @@
1
+ from os.path import join, dirname
2
+ import os
3
+ import sys
4
+ import argparse
5
+ from ara_cli.version import __version__
6
+ from ara_cli.artefact_creator import ArtefactCreator
7
+ from ara_cli.artefact_renamer import ArtefactRenamer
8
+ from ara_cli.classifier import Classifier
9
+ from ara_cli.filename_validator import is_valid_filename
10
+ from ara_cli.classifier_validator import is_valid_classifier
11
+ from ara_cli.template_manager import SpecificationBreakdownAspects, TemplatePathManager
12
+ from ara_cli.artefact_deleter import ArtefactDeleter
13
+ from ara_cli.artefact_lister import ArtefactLister
14
+ from ara_cli.vectorDB import create_DB, add_paths, reset_config, reset_DB, search_DB, update_DB
15
+ from ara_cli.prompt_handler import read_prompt, send_prompt, append_headings, write_prompt_result, default_prompt_creation, initialize_prompt_templates, load_selected_prompt_templates, create_and_send_custom_prompt
16
+ from ara_cli.prompt_extractor import extract_and_save_prompt_results
17
+
18
+ from ara_cli.chat import Chat
19
+
20
+ def check_validity(condition, error_message):
21
+ if not condition:
22
+ print(error_message)
23
+ sys.exit(1)
24
+
25
+ def create_action(args):
26
+ if args.parameter and args.classifier and args.aspect:
27
+ sba = SpecificationBreakdownAspects()
28
+ try:
29
+ sba.create(args.parameter, args.classifier, args.aspect)
30
+ except ValueError as ve:
31
+ print(f"Error: {ve}")
32
+ sys.exit(1)
33
+
34
+ check_validity(is_valid_filename(args.parameter), "Invalid filename provided. Please provide a valid filename.")
35
+ check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
36
+
37
+ template_path = join(dirname(__file__), 'templates')
38
+ artefact_creator = ArtefactCreator()
39
+ artefact_creator.run(args.parameter, args.classifier, template_path)
40
+
41
+ def delete_action(args):
42
+ artefact_deleter = ArtefactDeleter()
43
+ artefact_deleter.delete(args.parameter, args.classifier)
44
+
45
+
46
+ def rename_action(args):
47
+ check_validity(is_valid_filename(args.parameter), "Invalid filename provided. Please provide a valid filename.")
48
+ check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
49
+ check_validity(is_valid_filename(args.aspect), "Invalid new filename provided. Please provide a valid filename.")
50
+
51
+ artefact_renamer = ArtefactRenamer()
52
+ artefact_renamer.rename(args.parameter, args.aspect, args.classifier)
53
+
54
+ def list_action(args):
55
+ artefact_lister = ArtefactLister()
56
+ if args.tags:
57
+ artefact_lister.list_files(tags=args.tags)
58
+ else:
59
+ artefact_lister.list_files()
60
+
61
+
62
+ def prompt_action(args):
63
+ check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
64
+ check_validity(is_valid_filename(args.parameter), "Invalid filename provided. Please provide a valid filename.")
65
+
66
+ classifier = args.classifier
67
+ param = args.parameter
68
+ init = args.init
69
+
70
+ if (init == 'init'):
71
+ initialize_prompt_templates(classifier, param)
72
+ elif (init == 'load'):
73
+ load_selected_prompt_templates(classifier, param)
74
+ elif (init == 'send'):
75
+ create_and_send_custom_prompt(classifier, param) # Use the new method when the 'send' command is used
76
+ elif (init == 'extract'):
77
+ extract_and_save_prompt_results(classifier, param) # Use the new method when the 'send' command is used
78
+
79
+ else: # default rules.md, givens.md, prompt.md and commands.md files are used
80
+ default_prompt_creation(classifier, param)
81
+ prompt = read_prompt(classifier, param)
82
+
83
+ if(prompt):
84
+ append_headings(classifier, param, "prompt")
85
+ write_prompt_result(classifier, param, prompt)
86
+
87
+ response = send_prompt(prompt)
88
+ append_headings(classifier, param, "result")
89
+ write_prompt_result(classifier, param, response)
90
+
91
+
92
+ def chat_action(args):
93
+ if args.name:
94
+ # Start or continue specific chat
95
+ chat_name = args.name
96
+ else:
97
+ # Start or continue default chat
98
+ chat_name = "chat"
99
+ chat = Chat(chat_name)
100
+ chat.start()
101
+
102
+ def vector_action(args):
103
+ match args.vector_command:
104
+ case 'init':
105
+ create_DB()
106
+
107
+ case 'update':
108
+ if args.path:
109
+ add_paths(args.path)
110
+ if not args.path:
111
+ update_DB()
112
+
113
+ case 'reset':
114
+ if args.config:
115
+ reset_config()
116
+ if not args.config:
117
+ reset_DB()
118
+
119
+ case 'search':
120
+ search_DB(args.amount, args.user_input)
121
+
122
+ def template_action(args):
123
+ check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
124
+ check_validity(Classifier.is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
125
+
126
+ template_manager = TemplatePathManager()
127
+ content = template_manager.get_template_content(args.classifier)
128
+
129
+ def handle_invalid_action(args):
130
+ sys.exit("Invalid action provided. Type ara -h for help")
131
+
132
+ def create_parser(subparsers):
133
+ create_parser = subparsers.add_parser("create", help="Create a file with a classifier and aspect")
134
+ create_parser.add_argument("parameter", help="Filename for create action")
135
+ create_parser.add_argument("classifier", help="Classifier for the file to be created")
136
+ create_parser.add_argument("aspect", help="Specification breakdown aspect", nargs='?', default=None)
137
+
138
+ def delete_parser(subparsers):
139
+ delete_parser = subparsers.add_parser("delete", help="Delete a file with a classifier")
140
+ delete_parser.add_argument("parameter", help="Filename for delete action")
141
+ delete_parser.add_argument("classifier", help="Classifier for the file to be deleted")
142
+
143
+ def rename_parser(subparsers):
144
+ rename_parser = subparsers.add_parser("rename", help="Rename a file with a classifier and new filename")
145
+ rename_parser.add_argument("parameter", help="Current filename for rename action")
146
+ rename_parser.add_argument("classifier", help="Classifier for the file to be renamed")
147
+ rename_parser.add_argument("aspect", help="New filename for the file")
148
+
149
+ def list_parser(subparsers):
150
+ list_parser = subparsers.add_parser("list", help="List files with optional tags")
151
+ list_parser.add_argument("tags", nargs="*", help="Tags for listing files")
152
+
153
+ def prompt_parser(subparsers):
154
+ prompt_parser = subparsers.add_parser("prompt", help="Creates a prompt and sends it to ChatGPT and save the result")
155
+ prompt_parser.add_argument("parameter", help="Filename for prompt action")
156
+ prompt_parser.add_argument("classifier", help="Classifier for the file to be prompted")
157
+ prompt_parser.add_argument("init", help="initialize | load | send the prompt template config selection file in the prompt directory", nargs='?', default=None)
158
+
159
+ def vector_init_parser(vector_subparsers):
160
+ init_parser = vector_subparsers.add_parser("init", help="Initialize vectorDB")
161
+
162
+ def vector_update_parser(vector_subparsers):
163
+ update_parser = vector_subparsers.add_parser("update", help="Update vectorDB")
164
+ update_parser.add_argument("path", nargs='*', help="Path(s) to add to config file", default=None)
165
+
166
+ def vector_reset_parser(vector_subparsers):
167
+ reset_parser = vector_subparsers.add_parser("reset", help="Reset vectorDB")
168
+ reset_parser.add_argument("config", nargs="?", help="Optional config to reset", default=None)
169
+
170
+ def vector_search_parser(vector_subparsers):
171
+ search_parser = vector_subparsers.add_parser("search", help="Search vectorDB")
172
+ search_parser.add_argument("amount", nargs="?", help="Amount of paths to return from search", default=4, type=int)
173
+ search_parser.add_argument("user_input", help="Required query to be executed on vectorDB")
174
+
175
+ def vector_parser(subparsers):
176
+ vector_parser = subparsers.add_parser("vector")
177
+ vector_subparsers = vector_parser.add_subparsers(dest='vector_command')
178
+
179
+ vector_init_parser(vector_subparsers)
180
+ vector_update_parser(vector_subparsers)
181
+ vector_reset_parser(vector_subparsers)
182
+ vector_search_parser(vector_subparsers)
183
+
184
+ def chat_parser(subparsers):
185
+ chat_parser = subparsers.add_parser("chat", help="Command line chatbot")
186
+ chat_parser.add_argument("name", help="Optional name for a specific chat. Pass the .md file to continue an existing chat", nargs='?', default=None)
187
+
188
+ def template_parser(subparsers):
189
+ template_parser = subparsers.add_parser("template", help="Output ara template")
190
+ template_parser.add_argument("classifier", help="Classifier for ara artefact type")
191
+
192
+ # TODO hack for ara-list command for listing python files
193
+ def crawl_directory(start_dir):
194
+ python_files = []
195
+ for root, dirs, files in os.walk(start_dir):
196
+ for file in files:
197
+ if file.endswith(".py"):
198
+ python_files.append(os.path.join(root, file))
199
+ return python_files
200
+
201
+ def format_output(files):
202
+ formatted_output = "Source files\n"
203
+ for file in files:
204
+ formatted_output += f" - [ ] {file}\n"
205
+ return formatted_output
206
+
207
+ def save_to_file(output, filename):
208
+ with open(filename, "w") as f:
209
+ f.write(output)
210
+
211
+ def list():
212
+ if len(sys.argv) != 3:
213
+ print("Usage: python script.py <start_directory> <output_filename>")
214
+ sys.exit(1)
215
+
216
+ start_dir = sys.argv[1]
217
+ output_filename = sys.argv[2]
218
+
219
+ python_files = crawl_directory(start_dir)
220
+ output = format_output(python_files)
221
+ save_to_file(output, output_filename)
222
+ print(f"File list saved to {output_filename}")
223
+
224
+ def cli():
225
+ parser = argparse.ArgumentParser(description="Ara tools for creating files and directories.")
226
+ # Add version argument
227
+ parser.add_argument('-v', '--version', action='version', version=f'%(prog)s {__version__}')
228
+
229
+ subparsers = parser.add_subparsers(dest="action", help="Action to perform")
230
+
231
+ create_parser(subparsers)
232
+ delete_parser(subparsers)
233
+ rename_parser(subparsers)
234
+ list_parser(subparsers)
235
+ prompt_parser(subparsers)
236
+ vector_parser(subparsers)
237
+ chat_parser(subparsers)
238
+ template_parser(subparsers)
239
+
240
+ action_mapping = {
241
+ "create": create_action,
242
+ "delete": delete_action,
243
+ "rename": rename_action,
244
+ "list": list_action,
245
+ "prompt": prompt_action,
246
+ "vector": vector_action,
247
+ "chat": chat_action,
248
+ "template": template_action
249
+ }
250
+
251
+ args = parser.parse_args()
252
+ if hasattr(args, 'action') and args.action:
253
+ action = action_mapping.get(args.action, handle_invalid_action)
254
+ action(args)
255
+ else:
256
+ parser.print_help()
257
+
258
+ if __name__ == "__main__":
259
+ cli()
@@ -0,0 +1,52 @@
1
+ from typing import List, Dict
2
+ from pydantic import BaseModel
3
+ import json
4
+ import os
5
+
6
+ # Updated Pydantic model for ARA configuration
7
+ class ARAconfig(BaseModel):
8
+ ext_code_dirs: List[Dict[str, str]] = [{"source_dir": "./src"}, {"tests_dir": "./tests"}]
9
+ glossary_dir: str = "./glossary"
10
+ doc_dir: str = "./docs"
11
+ local_prompt_templates_dir: str = "./ara/.araconfig/prompt-modules"
12
+ local_ara_templates_dir: str = "./ara/.araconfig/templates/"
13
+ ara_prompt_given_list_includes: List[str] = [
14
+ "*.businessgoal", "*.vision", "*.capability", "*.keyfeature",
15
+ "*.epic", "*.userstory", "*.example", "*.feature", "*.task", "*.py", "*.md"
16
+ ]
17
+
18
+ # Function to ensure the necessary directories exist
19
+ def ensure_directory_exists(directory: str):
20
+ if not os.path.exists(directory):
21
+ os.makedirs(directory)
22
+ print(f"New directory created at {directory}")
23
+ return directory
24
+
25
+ # Function to read the JSON file and return an ARAconfig model
26
+ def read_data(filepath: str) -> ARAconfig:
27
+ if not os.path.exists(filepath):
28
+ # If file does not exist, create it with default values
29
+ default_config = ARAconfig()
30
+ with open(filepath, 'w') as file:
31
+ json.dump(default_config.dict(), file, indent=4)
32
+ print(f"ara-tool configuration file '{filepath}' created with default configuration. Please modify it as needed and re-run your command")
33
+ exit() # Exit the application
34
+
35
+ with open(filepath, 'r') as file:
36
+ data = json.load(file)
37
+ return ARAconfig(**data)
38
+
39
+ # Function to save the modified configuration back to the JSON file
40
+ def save_data(filepath: str, config: ARAconfig):
41
+ with open(filepath, 'w') as file:
42
+ json.dump(config.dict(), file, indent=4)
43
+
44
+ # Singleton for configuration management
45
+ class ConfigManager:
46
+ _config_instance = None
47
+
48
+ @classmethod
49
+ def get_config(cls, filepath='./ara/.araconfig/ara_config.json'):
50
+ if cls._config_instance is None:
51
+ cls._config_instance = read_data(filepath)
52
+ return cls._config_instance
@@ -0,0 +1,47 @@
1
+ from ara_cli.classifier import Classifier
2
+ import subprocess
3
+
4
+ def execute_command(command, mock_input=None):
5
+ # print(f"DEBUG: Executing command: {command}")
6
+ if mock_input:
7
+ # print(f"DEBUG: Mock input provided: {mock_input}")
8
+ process = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
9
+ stdout_data, stderr_data = process.communicate(input=mock_input.encode())
10
+
11
+ # print(f"DEBUG: Command stdout: {stdout_data.decode().strip()}")
12
+ # print(f"DEBUG: Command stderr: {stderr_data.decode().strip()}")
13
+ else:
14
+ # print(f"DEBUG: No Mock input provided")
15
+ process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
16
+
17
+ return process
18
+
19
+ class Artefact:
20
+ def __init__(self, name, classifier):
21
+ self.name = name
22
+ self.classifier = classifier
23
+ # print(f"DEBUG: Initialized Artefact with name='{name}' and classifier='{classifier}'")
24
+
25
+ def create(self):
26
+ command = f"ara create {self.name} {self.classifier}"
27
+ # print(f"DEBUG: Creating artefact with command: {command}")
28
+ result = execute_command(command, mock_input="y")
29
+ if result.returncode != 0:
30
+ # print(f"DEBUG: Error encountered during artefact creation.")
31
+ pass
32
+ else:
33
+ # print(f"DEBUG: Artefact created successfully.")
34
+ pass
35
+ return result
36
+
37
+ def delete(self):
38
+ command = f"ara delete {self.name} {self.classifier}"
39
+ # print(f"DEBUG: Deleting artefact with command: {command}")
40
+ result = execute_command(command, mock_input="y")
41
+ if result.returncode != 0:
42
+ # print(f"DEBUG: Error encountered during artefact deletion.")
43
+ pass
44
+ else:
45
+ # print(f"DEBUG: Artefact deleted successfully.")
46
+ pass
47
+ return result
@@ -0,0 +1,120 @@
1
+ import os
2
+ from ara_cli.classifier import Classifier
3
+ from ara_cli.file_classifier import FileClassifier
4
+ from ara_cli.template_manager import DirectoryNavigator
5
+ from pathlib import Path
6
+ import shutil
7
+ from shutil import rmtree
8
+ from shutil import copyfile
9
+
10
+ class ArtefactCreator:
11
+
12
+ def __init__(self, file_system=None):
13
+ self.file_system = file_system or os
14
+
15
+ def create_artefact(self, dir_path, template_path, classifier):
16
+ if not template_path:
17
+ raise ValueError("template_path must not be None or empty!")
18
+
19
+ if not classifier:
20
+ raise ValueError("classifier must not be None or empty!")
21
+
22
+ # Standard exploration artefact
23
+ self._copy_template_file(dir_path, template_path, f"template.{classifier}_exploration.md", f"{classifier}_exploration.md")
24
+
25
+ # Additional exploration artefact for 'feature' classifier
26
+ if classifier == 'feature':
27
+ self._copy_template_file(dir_path, template_path, "template.steps_exploration.md", "steps_exploration.md")
28
+
29
+ def _copy_template_file(self, dir_path, template_path, source_name, dest_name):
30
+ source = Path(template_path) / source_name
31
+ destination = Path(dir_path) / dest_name
32
+
33
+ if not source.exists():
34
+ print("[ERROR] Source file does not exist!")
35
+ raise FileNotFoundError(f"Source file {source} not found!")
36
+
37
+ if not destination.parent.exists():
38
+ print("[ERROR] Destination directory does not exist!")
39
+ raise NotADirectoryError(f"Destination directory {destination.parent} does not exist!")
40
+
41
+ copyfile(source, destination)
42
+
43
+
44
+ def create_file(self, file_path, template_path=None, classifier=None, filename=None):
45
+ if template_path and classifier:
46
+ template_file_path = self.file_system.path.join(template_path, f"template.{classifier}")
47
+ if self.file_system.path.exists(template_file_path):
48
+ with open(template_file_path, "r") as template_file:
49
+ template_content = template_file.read()
50
+
51
+ formatted_filename = filename.replace("-", " ").replace("_", " ")
52
+ capitalized_filename = formatted_filename.capitalize()
53
+
54
+ template_content = template_content.replace("<descriptive title>", capitalized_filename)
55
+
56
+ with open(file_path, "w") as file:
57
+ file.write(template_content)
58
+ else:
59
+ with open(file_path, "w") as file:
60
+ pass
61
+ else:
62
+ with open(file_path, "w") as file:
63
+ pass
64
+
65
+ def create_directory(self, dir_path):
66
+ self.file_system.makedirs(dir_path, exist_ok=True)
67
+
68
+ def template_exists(self, template_path, template_name):
69
+ if not template_path:
70
+ return False
71
+
72
+ full_path = self.file_system.path.join(template_path, template_name)
73
+
74
+ if not self.file_system.path.isfile(full_path):
75
+ print(f"Template file '{template_name}' not found at: {full_path}")
76
+ return False
77
+
78
+ return True
79
+
80
+
81
+ def run(self, filename, classifier, template_path=None):
82
+ # make sure this function is always called from the ara top level directory
83
+ navigator = DirectoryNavigator()
84
+ navigator.navigate_to_target()
85
+
86
+ if not Classifier.is_valid_classifier(classifier):
87
+ print("Invalid classifier provided. Please provide a valid classifier.")
88
+ return
89
+
90
+ sub_directory = Classifier.get_sub_directory(classifier)
91
+ self.file_system.makedirs(sub_directory, exist_ok=True)
92
+
93
+ file_path = self.file_system.path.join(sub_directory, f"{filename}.{classifier}")
94
+ dir_path = self.file_system.path.join(sub_directory, f"{filename}.data")
95
+
96
+ if self.file_system.path.exists(file_path) or self.file_system.path.exists(dir_path):
97
+ user_choice = input("File or directory already exists. Do you want to overwrite the existing file and directory? (Y/N): ")
98
+
99
+ if user_choice.lower() != "y":
100
+ print("No changes were made to the existing file and directory.")
101
+ return
102
+
103
+ template_name = f"template.{classifier}"
104
+ if template_path and not self.template_exists(template_path, template_name):
105
+ print(f"Template file '{template_name}' not found in the specified template path.")
106
+ return
107
+
108
+
109
+
110
+ self.create_file(file_path, template_path, classifier, filename)
111
+ self.create_directory(dir_path)
112
+ self.create_artefact(dir_path, template_path, classifier)
113
+
114
+ print(f"Created file: {file_path}")
115
+ print(f"Created directory: {dir_path}")
116
+ print(f"Created artefact exploration: {dir_path}/{classifier}_exploration.md")
117
+
118
+
119
+
120
+
@@ -0,0 +1,42 @@
1
+ # artefact_deleter.py
2
+ import os
3
+ import shutil
4
+ from ara_cli.template_manager import DirectoryNavigator
5
+ from ara_cli.classifier import Classifier
6
+ from ara_cli.artefact_link_updater import ArtefactLinkUpdater
7
+
8
+ class ArtefactDeleter:
9
+ def __init__(self, file_system=None):
10
+ self.file_system = file_system or os
11
+ self.link_updater = ArtefactLinkUpdater()
12
+
13
+ def delete(self, filename, classifier):
14
+ navigator = DirectoryNavigator()
15
+ navigator.navigate_to_target()
16
+
17
+ if not Classifier.is_valid_classifier(classifier):
18
+ print("Invalid classifier provided. Please provide a valid classifier.")
19
+ return
20
+
21
+ sub_directory = Classifier.get_sub_directory(classifier)
22
+ file_path = self.file_system.path.join(sub_directory, f"{filename}.{classifier}")
23
+ dir_path = self.file_system.path.join(sub_directory, f"{filename}.data")
24
+
25
+ if not self.file_system.path.exists(file_path) or not self.file_system.path.exists(dir_path):
26
+ print("File or directory not found.")
27
+ return
28
+
29
+ user_choice = input("Are you sure you want to delete the file and directory? (Y/N): ")
30
+
31
+ if user_choice.lower() != "y":
32
+ print("No changes were made.")
33
+ return
34
+
35
+ # Remove references to this artefact in other artefacts before deletion
36
+ self.link_updater.remove_links_in_related_artefacts(filename)
37
+
38
+ self.file_system.remove(file_path)
39
+ shutil.rmtree(dir_path)
40
+
41
+ print(f"Deleted file: {file_path}")
42
+ print(f"Deleted directory: {dir_path}")
@@ -0,0 +1,72 @@
1
+ # artefact_link_updater.py
2
+ import os
3
+ import re
4
+ from ara_cli.classifier import Classifier
5
+
6
+ class ArtefactLinkUpdater:
7
+
8
+ def __init__(self, file_system=None):
9
+ self.file_system = file_system or os
10
+
11
+ def update_links_in_related_artefacts(self, old_name, new_name, dir_path='.'):
12
+ new_name_formatted = new_name.replace('_', ' ').capitalize()
13
+ old_name_pattern = re.compile(f"\\b{old_name.replace(' ', '[ _]').replace('_', '[ _]')}\\b", re.IGNORECASE)
14
+
15
+ patterns = {
16
+ re.compile(f"^(\\s*)Contributes to[ ]+([A-Za-z ]+)?{old_name_pattern.pattern}", re.IGNORECASE | re.MULTILINE): r"\1Contributes to \2" + new_name_formatted,
17
+ re.compile(f"^(\\s*)Illustrates[ ]+([A-Za-z ]+)?{old_name_pattern.pattern}", re.IGNORECASE | re.MULTILINE): r"\1Illustrates \2" + new_name_formatted
18
+ }
19
+
20
+ # Iterate over all items in the directory
21
+ for item in self.file_system.listdir(dir_path):
22
+ item_path = self.file_system.path.join(dir_path, item)
23
+ extension = os.path.splitext(item)[-1][1:]
24
+
25
+ # Check if it's a directory, then recurse
26
+ if self.file_system.path.isdir(item_path):
27
+ self.update_links_in_related_artefacts(old_name, new_name, item_path)
28
+
29
+ # Check if it's a file and not a directory
30
+ elif self.file_system.path.isfile(item_path) and Classifier.is_valid_classifier(extension):
31
+ # Read the content of the file
32
+ with open(item_path, 'r') as file:
33
+ content = file.read()
34
+
35
+ # Replace all occurrences of the old name with the new name using regular expressions
36
+ for pattern, replacement in patterns.items():
37
+ content = pattern.sub(replacement, content)
38
+
39
+ # Write the updated content back to the file
40
+ with open(item_path, 'w') as file:
41
+ file.write(content)
42
+
43
+ def remove_links_in_related_artefacts(self, artefact_name, dir_path="."):
44
+ artefact_name_pattern = re.compile(rf"\b{re.escape(artefact_name)}\b", re.IGNORECASE)
45
+
46
+ # Pattern for removing the artefact name from 'Contributes to' lines
47
+ contribute_pattern = re.compile(rf"^(Contributes to).*{artefact_name_pattern.pattern}.*$", re.IGNORECASE | re.MULTILINE)
48
+
49
+ # Pattern for removing the artefact name from 'Illustrates' lines (no colon)
50
+ illustrates_pattern = re.compile(rf"^(Illustrates).*{artefact_name_pattern.pattern}.*$", re.IGNORECASE | re.MULTILINE)
51
+
52
+ # Iterate over all items in the directory
53
+ for item in self.file_system.listdir(dir_path):
54
+ item_path = self.file_system.path.join(dir_path, item)
55
+ extension = os.path.splitext(item)[-1][1:]
56
+
57
+ # Check if it's a directory, then recurse
58
+ if self.file_system.path.isdir(item_path):
59
+ self.remove_links_in_related_artefacts(artefact_name, item_path)
60
+
61
+ # Check if it's a file and not a directory, and if extension is a valid artefact classifier
62
+ elif self.file_system.path.isfile(item_path) and Classifier.is_valid_classifier(extension):
63
+ with open(item_path, 'r') as file:
64
+ content = file.read()
65
+
66
+ # Remove the artefact name from 'Contributes to' and 'Illustrates' lines
67
+ content = contribute_pattern.sub("Contributes to", content)
68
+ content = illustrates_pattern.sub("Illustrates", content)
69
+
70
+ with open(item_path, 'w') as file:
71
+ file.write(content)
72
+