ara-cli 0.1.10.0__py3-none-any.whl → 0.1.10.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ara-cli might be problematic. Click here for more details.

Files changed (41) hide show
  1. ara_cli/__main__.py +141 -105
  2. ara_cli/ara_command_action.py +11 -6
  3. ara_cli/ara_subcommands/__init__.py +0 -0
  4. ara_cli/ara_subcommands/autofix.py +26 -0
  5. ara_cli/ara_subcommands/chat.py +27 -0
  6. ara_cli/ara_subcommands/classifier_directory.py +16 -0
  7. ara_cli/ara_subcommands/common.py +100 -0
  8. ara_cli/ara_subcommands/create.py +75 -0
  9. ara_cli/ara_subcommands/delete.py +22 -0
  10. ara_cli/ara_subcommands/extract.py +22 -0
  11. ara_cli/ara_subcommands/fetch_templates.py +14 -0
  12. ara_cli/ara_subcommands/list.py +65 -0
  13. ara_cli/ara_subcommands/list_tags.py +25 -0
  14. ara_cli/ara_subcommands/load.py +48 -0
  15. ara_cli/ara_subcommands/prompt.py +136 -0
  16. ara_cli/ara_subcommands/read.py +47 -0
  17. ara_cli/ara_subcommands/read_status.py +20 -0
  18. ara_cli/ara_subcommands/read_user.py +20 -0
  19. ara_cli/ara_subcommands/reconnect.py +27 -0
  20. ara_cli/ara_subcommands/rename.py +22 -0
  21. ara_cli/ara_subcommands/scan.py +14 -0
  22. ara_cli/ara_subcommands/set_status.py +22 -0
  23. ara_cli/ara_subcommands/set_user.py +22 -0
  24. ara_cli/ara_subcommands/template.py +16 -0
  25. ara_cli/artefact_models/artefact_model.py +88 -19
  26. ara_cli/artefact_models/artefact_templates.py +18 -9
  27. ara_cli/artefact_models/userstory_artefact_model.py +2 -2
  28. ara_cli/artefact_scan.py +2 -2
  29. ara_cli/chat.py +1 -0
  30. ara_cli/commands/read_command.py +17 -4
  31. ara_cli/completers.py +144 -0
  32. ara_cli/tag_extractor.py +33 -16
  33. ara_cli/version.py +1 -1
  34. {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.1.dist-info}/METADATA +2 -1
  35. {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.1.dist-info}/RECORD +40 -18
  36. tests/test_artefact_scan.py +1 -1
  37. tests/test_tag_extractor.py +19 -13
  38. ara_cli/ara_command_parser.py +0 -605
  39. {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.1.dist-info}/WHEEL +0 -0
  40. {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.1.dist-info}/entry_points.txt +0 -0
  41. {ara_cli-0.1.10.0.dist-info → ara_cli-0.1.10.1.dist-info}/top_level.txt +0 -0
@@ -29,7 +29,8 @@ def _default_vision(title: str, use_default_contribution: bool) -> VisionArtefac
29
29
  our_product="<statement of primary differentiation>"
30
30
  )
31
31
  return VisionArtefact(
32
- tags=["sample_tag"],
32
+ tags=[],
33
+ author="creator_unknown",
33
34
  title=title,
34
35
  description="<further optional description to understand the vision, markdown capable text formatting>",
35
36
  intent=intent,
@@ -44,7 +45,8 @@ def _default_businessgoal(title: str, use_default_contribution: bool) -> Busines
44
45
  i_want="<something that helps me to reach my monetary goal>"
45
46
  )
46
47
  return BusinessgoalArtefact(
47
- tags=["sample_tag"],
48
+ tags=[],
49
+ author="creator_unknown",
48
50
  title=title,
49
51
  description="<further optional description to understand the businessgoal, markdown capable text formatting>",
50
52
  intent=intent,
@@ -57,7 +59,8 @@ def _default_capability(title: str, use_default_contribution: bool) -> Capabilit
57
59
  to_be_able_to="<needed capability for stakeholders that are the enablers/relevant for reaching the business goal>"
58
60
  )
59
61
  return CapabilityArtefact(
60
- tags=["sample_tag"],
62
+ tags=[],
63
+ author="creator_unknown",
61
64
  title=title,
62
65
  description="<further optional description to understand the capability, markdown capable text formatting>",
63
66
  intent=intent,
@@ -77,7 +80,8 @@ def _default_epic(title: str, use_default_contribution: bool) -> EpicArtefact:
77
80
  "<rule needed to fulfill the wanted product behavior>"
78
81
  ]
79
82
  return EpicArtefact(
80
- tags=["sample_tag"],
83
+ tags=[],
84
+ author="creator_unknown",
81
85
  title=title,
82
86
  description="<further optional description to understand the epic, markdown capable text formatting>",
83
87
  intent=intent,
@@ -98,7 +102,8 @@ def _default_userstory(title: str, use_default_contribution: bool) -> UserstoryA
98
102
  "<rule needed to fulfill the wanted product behavior>"
99
103
  ]
100
104
  return UserstoryArtefact(
101
- tags=["sample_tag"],
105
+ tags=[],
106
+ author="creator_unknown",
102
107
  title=title,
103
108
  description="<further optional description to understand the userstory, markdown capable text formatting>",
104
109
  intent=intent,
@@ -110,7 +115,8 @@ def _default_userstory(title: str, use_default_contribution: bool) -> UserstoryA
110
115
 
111
116
  def _default_example(title: str, use_default_contribution: bool) -> ExampleArtefact:
112
117
  return ExampleArtefact(
113
- tags=["sample_tag"],
118
+ tags=[],
119
+ author="creator_unknown",
114
120
  title=title,
115
121
  description="<further optional description to understand the example, markdown capable text formatting>",
116
122
  contribution=default_contribution() if use_default_contribution else None
@@ -130,7 +136,8 @@ def _default_keyfeature(title: str, use_default_contribution: bool) -> Keyfeatur
130
136
  THEN some result is to be expected
131
137
  AND some other result is to be expected>"""
132
138
  return KeyfeatureArtefact(
133
- tags=["sample_tag"],
139
+ tags=[],
140
+ author="creator_unknown",
134
141
  title=title,
135
142
  description=description,
136
143
  intent=intent,
@@ -185,7 +192,8 @@ def _default_feature(title: str, use_default_contribution: bool) -> FeatureArtef
185
192
  description = """<further optional description to understand the feature, no format defined, the example artefact is only a placeholder>"""
186
193
 
187
194
  return FeatureArtefact(
188
- tags=["sample_tag"],
195
+ tags=[],
196
+ author="creator_unknown",
189
197
  title=title,
190
198
  description=description,
191
199
  intent=intent,
@@ -214,7 +222,8 @@ def _default_issue(title: str, use_default_contribution: bool) -> IssueArtefact:
214
222
  *or optional free text description*"""
215
223
 
216
224
  return IssueArtefact(
217
- tags=["sample_tag"],
225
+ tags=[],
226
+ author="creator_unknown",
218
227
  title=title,
219
228
  description=description,
220
229
  additional_description=additional_description,
@@ -171,7 +171,7 @@ class UserstoryArtefact(Artefact):
171
171
  rules = self._serialize_rules()
172
172
 
173
173
  lines = []
174
- if self.tags:
174
+ if tags: # Changed from self.tags to tags to include all tag types
175
175
  lines.append(tags)
176
176
  lines.append(title)
177
177
  lines.append("")
@@ -188,4 +188,4 @@ class UserstoryArtefact(Artefact):
188
188
  lines.append(description)
189
189
  lines.append("")
190
190
 
191
- return '\n'.join(lines)
191
+ return '\n'.join(lines)
ara_cli/artefact_scan.py CHANGED
@@ -25,10 +25,10 @@ def is_rule_valid(contribution, classified_artefact_info) -> bool:
25
25
  if not rule:
26
26
  return True
27
27
  parent = ArtefactReader.read_artefact(contribution.artefact_name, contribution.classifier)
28
- if not parent or not parent.rules:
28
+ if not parent:
29
29
  return True
30
30
  rules = parent.rules
31
- if rule not in rules:
31
+ if not rules or rule not in rules:
32
32
  return False
33
33
  return True
34
34
 
ara_cli/chat.py CHANGED
@@ -763,6 +763,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
763
763
  return
764
764
  self.create_empty_chat_file(self.chat_name)
765
765
  self.chat_history = self.load_chat_history(self.chat_name)
766
+ self.message_buffer.clear()
766
767
  print(f"Cleared content of {self.chat_name}")
767
768
 
768
769
  @cmd2.with_category(CATEGORY_CHAT_CONTROL)
@@ -30,6 +30,11 @@ class ReadCommand(Command):
30
30
  """Execute the read command and return success status."""
31
31
  file_classifier = FileClassifier(os)
32
32
  classified_artefacts = ArtefactReader.read_artefacts()
33
+
34
+ if not self.classifier or not self.artefact_name:
35
+ self._filter_and_print(classified_artefacts, file_classifier)
36
+ return True
37
+
33
38
  artefacts = classified_artefacts.get(self.classifier, [])
34
39
  all_artefact_names = [a.title for a in artefacts]
35
40
 
@@ -62,10 +67,11 @@ class ReadCommand(Command):
62
67
  )
63
68
 
64
69
  # Apply filtering and print results
65
- filtered_artefacts = self._apply_filtering(artefacts_by_classifier)
66
- file_classifier.print_classified_files(
67
- filtered_artefacts, print_content=True
68
- )
70
+ self._filter_and_print(artefacts_by_classifier, file_classifier)
71
+ # filtered_artefacts = self._apply_filtering(artefacts_by_classifier)
72
+ # file_classifier.print_classified_files(
73
+ # filtered_artefacts, print_content=True
74
+ # )
69
75
  return True
70
76
 
71
77
  except Exception as e:
@@ -102,3 +108,10 @@ class ReadCommand(Command):
102
108
  file_path_retrieval=artefact_path_retrieval,
103
109
  tag_retrieval=artefact_tags_retrieval
104
110
  )
111
+
112
+ def _filter_and_print(self, artefacts_by_classifier, file_classifier):
113
+ """Apply list filtering and print results"""
114
+ filtered_artefacts = self._apply_filtering(artefacts_by_classifier)
115
+ file_classifier.print_classified_files(
116
+ filtered_artefacts, print_content=True
117
+ )
ara_cli/completers.py ADDED
@@ -0,0 +1,144 @@
1
+ import os
2
+ from typing import List, Optional
3
+ from pathlib import Path
4
+ import typer
5
+
6
+ from ara_cli.classifier import Classifier
7
+ from ara_cli.template_manager import SpecificationBreakdownAspects
8
+
9
+
10
+ def complete_classifier(incomplete: str) -> List[str]:
11
+ """Complete classifier names."""
12
+ classifiers = Classifier.ordered_classifiers()
13
+ return [c for c in classifiers if c.startswith(incomplete)]
14
+
15
+
16
+ def complete_aspect(incomplete: str) -> List[str]:
17
+ """Complete aspect names."""
18
+ aspects = SpecificationBreakdownAspects.VALID_ASPECTS
19
+ return [a for a in aspects if a.startswith(incomplete)]
20
+
21
+
22
+ def complete_status(incomplete: str) -> List[str]:
23
+ """Complete task status values."""
24
+ statuses = ["to-do", "in-progress", "review", "done", "closed"]
25
+ return [s for s in statuses if s.startswith(incomplete)]
26
+
27
+
28
+ def complete_template_type(incomplete: str) -> List[str]:
29
+ """Complete template type values."""
30
+ template_types = ["rules", "intention", "commands", "blueprint"]
31
+ return [t for t in template_types if t.startswith(incomplete)]
32
+
33
+
34
+ def complete_artefact_name(classifier: str) -> List[str]:
35
+ """Complete artefact names for a given classifier."""
36
+ try:
37
+ # Get the directory for the classifier
38
+ classifier_dir = f"ara/{Classifier.get_sub_directory(classifier)}"
39
+
40
+ if not os.path.exists(classifier_dir):
41
+ return []
42
+
43
+ # Find all files with the classifier extension
44
+ artefacts = []
45
+ for file in os.listdir(classifier_dir):
46
+ if file.endswith(f'.{classifier}'):
47
+ # Remove the extension to get the artefact name
48
+ name = file[:-len(f'.{classifier}')]
49
+ artefacts.append(name)
50
+
51
+ return sorted(artefacts)
52
+ except Exception:
53
+ return []
54
+
55
+
56
+ def complete_artefact_name_for_classifier(classifier: str):
57
+ """Create a completer function for artefact names of a specific classifier."""
58
+ def completer(incomplete: str) -> List[str]:
59
+ artefacts = complete_artefact_name(classifier)
60
+ return [a for a in artefacts if a.startswith(incomplete)]
61
+ return completer
62
+
63
+
64
+ def complete_chat_files(incomplete: str) -> List[str]:
65
+ """Complete chat file names (without .md extension)."""
66
+ try:
67
+ chat_files = []
68
+ current_dir = Path.cwd()
69
+
70
+ # Look for .md files in current directory
71
+ for file in current_dir.glob("*.md"):
72
+ name = file.stem
73
+ if name.startswith(incomplete):
74
+ chat_files.append(name)
75
+
76
+ return sorted(chat_files)
77
+ except Exception:
78
+ return []
79
+
80
+
81
+ # Dynamic completers that need context
82
+ class DynamicCompleters:
83
+ @staticmethod
84
+ def create_classifier_completer():
85
+ """Create a completer for classifiers."""
86
+ def completer(ctx: typer.Context, incomplete: str) -> List[str]:
87
+ return complete_classifier(incomplete)
88
+ return completer
89
+
90
+ @staticmethod
91
+ def create_aspect_completer():
92
+ """Create a completer for aspects."""
93
+ def completer(ctx: typer.Context, incomplete: str) -> List[str]:
94
+ return complete_aspect(incomplete)
95
+ return completer
96
+
97
+ @staticmethod
98
+ def create_status_completer():
99
+ """Create a completer for status values."""
100
+ def completer(ctx: typer.Context, incomplete: str) -> List[str]:
101
+ return complete_status(incomplete)
102
+ return completer
103
+
104
+ @staticmethod
105
+ def create_template_type_completer():
106
+ """Create a completer for template types."""
107
+ def completer(ctx: typer.Context, incomplete: str) -> List[str]:
108
+ return complete_template_type(incomplete)
109
+ return completer
110
+
111
+ @staticmethod
112
+ def create_artefact_name_completer():
113
+ """Create a completer for artefact names based on classifier context."""
114
+ def completer(ctx: typer.Context, incomplete: str) -> List[str]:
115
+ # Try to get classifier from context
116
+ if hasattr(ctx, 'params') and 'classifier' in ctx.params:
117
+ classifier = ctx.params['classifier']
118
+ if hasattr(classifier, 'value'):
119
+ classifier = classifier.value
120
+ artefacts = complete_artefact_name(classifier)
121
+ return [a for a in artefacts if a.startswith(incomplete)]
122
+ return []
123
+ return completer
124
+
125
+ @staticmethod
126
+ def create_parent_name_completer():
127
+ """Create a completer for parent artefact names based on parent classifier context."""
128
+ def completer(ctx: typer.Context, incomplete: str) -> List[str]:
129
+ # Try to get parent_classifier from context
130
+ if hasattr(ctx, 'params') and 'parent_classifier' in ctx.params:
131
+ parent_classifier = ctx.params['parent_classifier']
132
+ if hasattr(parent_classifier, 'value'):
133
+ parent_classifier = parent_classifier.value
134
+ artefacts = complete_artefact_name(parent_classifier)
135
+ return [a for a in artefacts if a.startswith(incomplete)]
136
+ return []
137
+ return completer
138
+
139
+ @staticmethod
140
+ def create_chat_file_completer():
141
+ """Create a completer for chat files."""
142
+ def completer(ctx: typer.Context, incomplete: str) -> List[str]:
143
+ return complete_chat_files(incomplete)
144
+ return completer
ara_cli/tag_extractor.py CHANGED
@@ -11,13 +11,13 @@ class TagExtractor:
11
11
  def __init__(self, file_system=None):
12
12
  self.file_system = file_system or os
13
13
 
14
- def filter_column(self, tags_set, filtered_artefacts):
14
+ def filter_column(self, tag_groups, filtered_artefacts):
15
15
  status_tags = {"to-do", "in-progress", "review", "done", "closed"}
16
16
 
17
17
  artefacts_to_process = self._get_artefacts_without_status_tags(
18
18
  filtered_artefacts, status_tags
19
19
  )
20
- self._add_non_status_tags_to_set(tags_set, artefacts_to_process, status_tags)
20
+ self._add_non_status_tags_to_set(tag_groups, artefacts_to_process, status_tags)
21
21
 
22
22
  def _get_artefacts_without_status_tags(self, filtered_artefacts, status_tags):
23
23
  artefacts_to_process = []
@@ -32,7 +32,7 @@ class TagExtractor:
32
32
  tags = artefact.tags + [artefact.status] if artefact.status else artefact.tags
33
33
  return set(tag for tag in tags if tag is not None)
34
34
 
35
- def _add_non_status_tags_to_set(self, tags_set, artefacts, status_tags):
35
+ def _add_non_status_tags_to_set(self, tag_groups, artefacts, status_tags):
36
36
  for artefact in artefacts:
37
37
  tags = [
38
38
  tag for tag in (artefact.tags + [artefact.status]) if tag is not None
@@ -40,23 +40,41 @@ class TagExtractor:
40
40
  for tag in tags:
41
41
  if self._is_skipped_tag(tag, status_tags):
42
42
  continue
43
- tags_set.add(tag)
43
+ key = tag.lower()
44
+ if key not in tag_groups:
45
+ tag_groups[key] = set()
46
+ tag_groups[key].add(tag)
44
47
 
45
48
  def _is_skipped_tag(self, tag, status_tags):
46
49
  return (
47
50
  tag in status_tags or tag.startswith("priority_") or tag.startswith("user_")
48
51
  )
49
52
 
50
- def add_to_tags_set(self, tags_set, filtered_artefacts):
53
+ def add_to_tags_set(self, tag_groups, filtered_artefacts):
51
54
  for artefact_list in filtered_artefacts.values():
52
55
  for artefact in artefact_list:
53
56
  user_tags = [f"user_{tag}" for tag in artefact.users]
54
- tags = [
55
- tag
56
- for tag in (artefact.tags + [artefact.status] + user_tags)
57
- if tag is not None
58
- ]
59
- tags_set.update(tags)
57
+
58
+ # Build list of all tags, filtering out None values
59
+ all_tags = []
60
+ all_tags.extend(artefact.tags)
61
+
62
+ if artefact.status:
63
+ all_tags.append(artefact.status)
64
+
65
+ all_tags.extend(user_tags)
66
+
67
+ # Safely handle author attribute
68
+ if hasattr(artefact, 'author') and artefact.author:
69
+ all_tags.append(artefact.author)
70
+
71
+ # Filter out None values and add to tag groups
72
+ for tag in all_tags:
73
+ if tag is not None:
74
+ key = tag.lower()
75
+ if key not in tag_groups:
76
+ tag_groups[key] = set()
77
+ tag_groups[key].add(tag)
60
78
 
61
79
  def extract_tags(
62
80
  self,
@@ -81,12 +99,11 @@ class TagExtractor:
81
99
  tag_retrieval=artefact_tags_retrieval,
82
100
  )
83
101
 
84
- unique_tags = set()
102
+ tag_groups = {}
85
103
 
86
104
  if filtered_extra_column:
87
- self.filter_column(unique_tags, filtered_artefacts)
105
+ self.filter_column(tag_groups, filtered_artefacts)
88
106
  else:
89
- self.add_to_tags_set(unique_tags, filtered_artefacts)
107
+ self.add_to_tags_set(tag_groups, filtered_artefacts)
90
108
 
91
- sorted_tags = sorted(unique_tags)
92
- return sorted_tags
109
+ return tag_groups
ara_cli/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # version.py
2
- __version__ = "0.1.10.0" # fith parameter like .0 for local install test purposes only. official numbers should be 4 digit numbers
2
+ __version__ = "0.1.10.1" # fith parameter like .0 for local install test purposes only. official numbers should be 4 digit numbers
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ara_cli
3
- Version: 0.1.10.0
3
+ Version: 0.1.10.1
4
4
  Summary: Powerful, open source command-line tool for managing, structuring and automating software development artifacts in line with Business-Driven Development (BDD) and AI-assisted processes
5
5
  Description-Content-Type: text/markdown
6
6
  Requires-Dist: langfuse
@@ -19,6 +19,7 @@ Requires-Dist: pydantic
19
19
  Requires-Dist: pydantic_ai
20
20
  Requires-Dist: python-docx
21
21
  Requires-Dist: pymupdf4llm
22
+ Requires-Dist: typer
22
23
  Dynamic: description
23
24
  Dynamic: description-content-type
24
25
  Dynamic: requires-dist
@@ -1,7 +1,6 @@
1
1
  ara_cli/__init__.py,sha256=DuzXKimZ6JtUEnp48qCQcnojDflBtYjT6Na_twO5EzM,505
2
- ara_cli/__main__.py,sha256=sumQaIYg6wJdcT-nQjJpK9DGaBUTszjPrgZLPN2bUVs,3520
3
- ara_cli/ara_command_action.py,sha256=VJSReKfgUQk62DeMcY4EN228FvgF1m8NiHf-ckrigdA,24450
4
- ara_cli/ara_command_parser.py,sha256=4_LXxj9w7eAY8d_s8pMlKmxtMr9cX9y2pD5azNeJjsg,22288
2
+ ara_cli/__main__.py,sha256=GA9iL-Hi8M4LMBALNdycCP5Uo-jLp5IHRPHrgsgwWvo,8188
3
+ ara_cli/ara_command_action.py,sha256=yWtZXxwGp-n5kl-I6bMvwESfyRVGHHBYHVapu-8knl4,24618
5
4
  ara_cli/ara_config.py,sha256=vZsY2zYJdlSExRE84L5LqRH3DjveeuMSmG5fC8HDIVc,9794
6
5
  ara_cli/artefact_autofix.py,sha256=9j_bh0HGnN6HVT9OGKVp85VgDklpx3XpSc9MxBCldU4,25050
7
6
  ara_cli/artefact_creator.py,sha256=fRrDaGZvOqJqDb_DLXqMTed2XfIvQMIHjLgOuHOi3Qg,5973
@@ -11,12 +10,13 @@ ara_cli/artefact_link_updater.py,sha256=nKdxTpDKqWTOAMD8viKmUaklSFGWzJZ8S8E8xW_A
11
10
  ara_cli/artefact_lister.py,sha256=M-ggazAgZ-OLeW9NB48r_sd6zPx0p4hEpeS63qHwI1A,4176
12
11
  ara_cli/artefact_reader.py,sha256=-6E1VhIlh2oJE1Rn8ARcHRc_E9N4uk8cEViKMoywm6E,7753
13
12
  ara_cli/artefact_renamer.py,sha256=8S4QWD19_FGKsKlWojnu_RUOxx0u9rmLugydM4s4VDc,4219
14
- ara_cli/artefact_scan.py,sha256=msPCm-vPWOAZ_e_z5GylXxq1MtNlmJ4zvKrsdOFCWF4,4813
15
- ara_cli/chat.py,sha256=Vp1HzSaaUsfOldOjxJc0ff68lQJWiIet0LJ22jjMYUs,40776
13
+ ara_cli/artefact_scan.py,sha256=qY2Gp4zVcqMXhtuP7rICW0UBG4pcj3W2ABofnL9SIG8,4806
14
+ ara_cli/chat.py,sha256=vpwVnknd_t8qihjxutw37efflPuXIce8ctMvcbLCa7c,40812
16
15
  ara_cli/classifier.py,sha256=zWskj7rBYdqYBGjksBm46iTgVU5IIf2PZsJr4qeiwVU,1878
17
16
  ara_cli/codefusionretriever.py,sha256=fCHgXdIBRzkVAnapX-KI2NQ44XbrrF4tEQmn5J6clUI,1980
18
17
  ara_cli/codehierachieretriever.py,sha256=Xd3EgEWWhkSf1TmTWtf8X5_YvyE_4B66nRrqarwSiTU,1182
19
18
  ara_cli/commandline_completer.py,sha256=b00Dqb5n7SecpxYIDLxAfYhp8X6e3c8a5qYz6ko0i3E,1192
19
+ ara_cli/completers.py,sha256=V4bcmUnuFkdgMpJ3bLAL7cnxinxZb8wwB17WnRHIrHM,5404
20
20
  ara_cli/directory_navigator.py,sha256=6QbSAjJrJ5a6Lutol9J4HFgVDMiAQ672ny9TATrh04U,3318
21
21
  ara_cli/error_handler.py,sha256=nNaJSq82f3xiz_QFRKPg5kX_-oI-UoFdRJ2OTj1AR18,4019
22
22
  ara_cli/file_classifier.py,sha256=nUcNrhflUydCyCRbXHjEEXYwwwfUm65lYnNEvc86fpM,4026
@@ -30,17 +30,39 @@ ara_cli/prompt_extractor.py,sha256=WloRgfcEdIVq37BpdWAd2X3EMu0bcNN_Wuws1T2YiUg,8
30
30
  ara_cli/prompt_handler.py,sha256=N0zH5k9T6udKAbMolxEAaAwiFo03h5aF-IY3BmMLEos,27924
31
31
  ara_cli/prompt_rag.py,sha256=ydlhe4CUqz0jdzlY7jBbpKaf_5fjMrAZKnriKea3ZAg,7485
32
32
  ara_cli/run_file_lister.py,sha256=XbrrDTJXp1LFGx9Lv91SNsEHZPP-PyEMBF_P4btjbDA,2360
33
- ara_cli/tag_extractor.py,sha256=k2yRl7dAMZ4YTARzUke4wgY0oEIOmWkOHGet7nXB6uw,3317
33
+ ara_cli/tag_extractor.py,sha256=9yX8Ss4jP_NI-NPxxJJKoVPD-1iEweXBThUh01IU8c8,4048
34
34
  ara_cli/template_loader.py,sha256=uEpYOchT5d-OO5r-W0-h605Xilvuv56i1VKSy4_9NaE,10734
35
35
  ara_cli/template_manager.py,sha256=l2c785YHB7m0e2TjE0CX-nwXrS4v3EiT9qrS5KuatAc,7105
36
36
  ara_cli/update_config_prompt.py,sha256=moqj2Kha7S7fEGzTReU0v2y8UjXC8QfnoiieOQr35C4,5157
37
- ara_cli/version.py,sha256=AvikXK1EI29z3MY864MZ0oxZJZ4-tSdFYdogqQEkDac,146
37
+ ara_cli/version.py,sha256=jCeFoAxaTryn9z3M-kDldZwmzGJM9NzWxhhEBjelIFA,146
38
+ ara_cli/ara_subcommands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ ara_cli/ara_subcommands/autofix.py,sha256=h7-6hV97Q6PisUJ_U1Qs4sHYwkHsDpeYH63y_LQsfSc,1095
40
+ ara_cli/ara_subcommands/chat.py,sha256=9zorWKbM0ulu9xFhW2tzV5vl8hCLOCjcp2E9hYgZJ90,1239
41
+ ara_cli/ara_subcommands/classifier_directory.py,sha256=7GH3w4DtvFCM1Sr6Qqk_kjp0EC8jNJDieJJMshYJ_6k,620
42
+ ara_cli/ara_subcommands/common.py,sha256=6bAfPbFHx3CzDSQMm4vL7keFgVnOpqiupgDDWj7QdUQ,2898
43
+ ara_cli/ara_subcommands/create.py,sha256=2tIpzKgzytTIdVV26p6cvrcBo8WLm_3qK7GJyn47Jaw,2527
44
+ ara_cli/ara_subcommands/delete.py,sha256=DxWRQ5Z8h5ZpMhyjLHNuLxONgxIQ97hVkQ8VkX15FDk,827
45
+ ara_cli/ara_subcommands/extract.py,sha256=11atXek579W2RP6PYHlGuyVjWBTuyh1viondCjuce_k,765
46
+ ara_cli/ara_subcommands/fetch_templates.py,sha256=f1bXOTlM67hyf3oGPZEQQjSwUsTte7Cd9-yqq76Ud08,432
47
+ ara_cli/ara_subcommands/list.py,sha256=HtX3kKQ9nrfCcJPxJng0ZnoOqLQ11-aui2zxVei8PlI,3562
48
+ ara_cli/ara_subcommands/list_tags.py,sha256=drEzJgJa4OqqYfIuvT7XkjG4o7VB-ikHE0ArIdljoTI,1113
49
+ ara_cli/ara_subcommands/load.py,sha256=czaflU5Xv-TBlpgalvm6yn5oBBAnNfxSeoIFuLPfi-U,1825
50
+ ara_cli/ara_subcommands/prompt.py,sha256=A8L0lJNBm5zkwJJrzz1kpdycwpm1y8hzd2iVleylpck,4630
51
+ ara_cli/ara_subcommands/read.py,sha256=zTPNMvEPf1WvhtUiauXu5HFiXHRIBJVCkHu44L_scSk,2396
52
+ ara_cli/ara_subcommands/read_status.py,sha256=ZqdxuYXC-idJ2JtMIcZzT4XYI55PnqA6sYv2FcMuchw,695
53
+ ara_cli/ara_subcommands/read_user.py,sha256=NuhaC7dBbi8PUHnGGpqbBVSbQ__nT_L52c7tdKkxjlA,681
54
+ ara_cli/ara_subcommands/reconnect.py,sha256=5Q90rbSnYf7YO6n_9esWsYv7o8GQ-Fnzgy4d8S-X-DQ,1088
55
+ ara_cli/ara_subcommands/rename.py,sha256=IggQdvXjTbZ5CkqzebydVVTcaxO4SDOyORqXDL5jnY8,784
56
+ ara_cli/ara_subcommands/scan.py,sha256=XXwIzq4T9sDMXV0ZcMTSakQ7SyosuCfKjMiiTz7533A,363
57
+ ara_cli/ara_subcommands/set_status.py,sha256=6zzuqLR9k-V63e5UQBpsooftbYHuENEP2s3AdI2jyG0,786
58
+ ara_cli/ara_subcommands/set_user.py,sha256=ADgZIj9xIWK9QKY95lIW_GJGYZysALV--y8j6IuvGxs,755
59
+ ara_cli/ara_subcommands/template.py,sha256=gp_BzrNHcVylU5xav1vmPe3-0vQR7UHm44G7w2i370Q,552
38
60
  ara_cli/artefact_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
61
  ara_cli/artefact_models/artefact_data_retrieval.py,sha256=CooXOJBYWSyiViN2xkC8baS8OUaslry3YGVVUeDxRAU,527
40
62
  ara_cli/artefact_models/artefact_load.py,sha256=IXzWxP-Q_j_oDGMno0m-OuXCQ7Vd5c_NctshGr4ROBw,621
41
63
  ara_cli/artefact_models/artefact_mapping.py,sha256=8aD0spBjkJ8toMAmFawc6UTUxB6-tEEViZXv2I-r88Q,1874
42
- ara_cli/artefact_models/artefact_model.py,sha256=qSbcrmFWAYgBqcNl9QARI1_uLQJm-TPVgP5q2AEFnjE,15983
43
- ara_cli/artefact_models/artefact_templates.py,sha256=CFa_vIA-cnbZEHuACd24vNJB_7LueQi-8x7ga_AyLKI,9830
64
+ ara_cli/artefact_models/artefact_model.py,sha256=nEXbHHrYFsB4mdjKzye-RAkmFkHDyhlOzXU2ba1E4SU,18471
65
+ ara_cli/artefact_models/artefact_templates.py,sha256=8N1gJlS1KLd79y2nasEgU8xeK-WaP6IenBK5Ojcmn9Y,10028
44
66
  ara_cli/artefact_models/businessgoal_artefact_model.py,sha256=GYT5S2xEnQHwv-k-lEeX5NMSqA-UEfV3PhNjgPDUJpw,4698
45
67
  ara_cli/artefact_models/capability_artefact_model.py,sha256=SZqHx4O2mj4urn77Stnj4_Jxtlq3-LgBBU9SMkByppI,3079
46
68
  ara_cli/artefact_models/epic_artefact_model.py,sha256=h9pC00ZxCL-t_NMjwTCeOnIJZPa9hhB-R05wr110LXs,5619
@@ -50,14 +72,14 @@ ara_cli/artefact_models/issue_artefact_model.py,sha256=v6CpKnkqiUh6Wch2kkEmyyW49
50
72
  ara_cli/artefact_models/keyfeature_artefact_model.py,sha256=J9oXLsCAo22AW31D5Z104y02ss0S0O4tPCcd09zYCD0,4066
51
73
  ara_cli/artefact_models/serialize_helper.py,sha256=Wks30wy-UrwJURetydKykLgJkdGRgXFHkDT24vHe5tU,595
52
74
  ara_cli/artefact_models/task_artefact_model.py,sha256=1BSMbz9D-RXvdpdd0RlAr9hUx84Rcuysk2YfQC8Qy14,6046
53
- ara_cli/artefact_models/userstory_artefact_model.py,sha256=2awH31ROtm7j4T44Bv4cylQDYLQtnfgXZMhDu_pgw-k,6435
75
+ ara_cli/artefact_models/userstory_artefact_model.py,sha256=xw1gsOjkAphd-4xwz5U6maZ6aASYn35_2DHCo1bPctA,6488
54
76
  ara_cli/artefact_models/vision_artefact_model.py,sha256=frjaUJj-mmIlVHEhzAQztCGs-CtvNu_odSborgztfzo,5251
55
77
  ara_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
78
  ara_cli/commands/command.py,sha256=Y_2dNeuxRjbyI3ScXNv55lptSe8Hs_ya78L0nPYNZHA,154
57
79
  ara_cli/commands/extract_command.py,sha256=CzUOwDembG587PYbxg5rge4XSfdsuTyOPUvkobkXCIs,573
58
80
  ara_cli/commands/load_command.py,sha256=H3CfeHIL-criDU5oi4BONTSpyzJ4m8DzJ0ZCIiAZFeI,2204
59
81
  ara_cli/commands/load_image_command.py,sha256=g9-PXAYdqx5Ed1PdVo-FIb4CyJGEpRFbgQf9Dxg6DmM,886
60
- ara_cli/commands/read_command.py,sha256=bo1BvRWuNKdFqBNN1EWORNrX_yuFAOyBruDUolHq1Vc,3791
82
+ ara_cli/commands/read_command.py,sha256=xne8jlertuJNcsyzjR0bJeUUHi4NkEfd0h0DRbU9rC4,4347
61
83
  ara_cli/file_loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
84
  ara_cli/file_loaders/binary_file_loader.py,sha256=1HHH1Nk4lEM83CTnf4z9wYz6rMLgpxydFoRcSgkBHmQ,940
63
85
  ara_cli/file_loaders/document_file_loader.py,sha256=VxGFChYyM9K-e6eOCK3yk5jQuEXgz01Mh_NoA6CA_RM,1017
@@ -150,7 +172,7 @@ tests/test_artefact_link_updater.py,sha256=biqbEp2jCOz8giv72hu2P2hDfeJfJ9OrVGdAv
150
172
  tests/test_artefact_lister.py,sha256=35R13UU-YsX1HOsEN8M2-vIiCUA9RSBm6SwestDaFhE,20388
151
173
  tests/test_artefact_reader.py,sha256=660K-d8ed-j8hulsUB_7baPD2-hhbg9TffUR5yVc4Uo,927
152
174
  tests/test_artefact_renamer.py,sha256=lSnKCCfoFGgKhTdDZrEaeBq1xJAak1QoqH5aSeOe9Ro,3494
153
- tests/test_artefact_scan.py,sha256=uNWgrt7ieZ4ogKACsPqzAsh59JF2BhTKSag31hpVrTQ,16887
175
+ tests/test_artefact_scan.py,sha256=SzMtJeh8_oOBec9yzy3vJRHxs9i1E5gEU2RfF6CJZqE,16888
154
176
  tests/test_chat.py,sha256=D2HRRTdnvcDvB9TWz4O91ZONbLJL6w4v8TRTDwjtzzI,86104
155
177
  tests/test_classifier.py,sha256=grYGPksydNdPsaEBQxYHZTuTdcJWz7VQtikCKA6BNaQ,1920
156
178
  tests/test_directory_navigator.py,sha256=7G0MVrBbtBvbrFUpL0zb_9EkEWi1dulWuHsrQxMJxDY,140
@@ -160,12 +182,12 @@ tests/test_file_lister.py,sha256=Q9HwhKKx540EPzTmfzOCnvtAgON0aMmpJE2eOe1J3EA,432
160
182
  tests/test_global_file_lister.py,sha256=ycvf2YL8q5QSEMwcnQfUdoWnQQ8xTSyEtccAeXwl6QU,5487
161
183
  tests/test_list_filter.py,sha256=fJA3d_SdaOAUkE7jn68MOVS0THXGghy1fye_64Zvo1U,7964
162
184
  tests/test_prompt_handler.py,sha256=9s1zavcW81uz8wOBM_2X2KqdLNoc3E9bt0Oqt2-Sgmk,33926
163
- tests/test_tag_extractor.py,sha256=nSiAYlTKZ7TLAOtcJpwK5zTWHhFYU0tI5xKnivLc1dU,2712
185
+ tests/test_tag_extractor.py,sha256=7eVD10Y1uLkoSrEgqkXzRvPFs8lJ1RiaJzDu7ml_FZE,3118
164
186
  tests/test_template_loader.py,sha256=R7s8HJZbKqja-1TRBMBkVKPTgajofUjjRKUJq7a3_Oc,7427
165
187
  tests/test_template_manager.py,sha256=qliEeYgAEakn8JIqIHa8u0Ht6DY4L3T6DcHBXkjzR4I,4167
166
188
  tests/test_update_config_prompt.py,sha256=xsqj1WTn4BsG5Q2t-sNPfu7EoMURFcS-hfb5VSXUnJc,6765
167
- ara_cli-0.1.10.0.dist-info/METADATA,sha256=9DcNT8mkoI9D6aDt0gRORWFl_MagH7yTw_ISo4uc_Tw,6813
168
- ara_cli-0.1.10.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
169
- ara_cli-0.1.10.0.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
170
- ara_cli-0.1.10.0.dist-info/top_level.txt,sha256=WM4cLHT5DYUaWzLtRj-gu3yVNFpGQ6lLRI3FMmC-38I,14
171
- ara_cli-0.1.10.0.dist-info/RECORD,,
189
+ ara_cli-0.1.10.1.dist-info/METADATA,sha256=-t9lEUM9L9Jf3Cc9LpgOqe8cSrcv2LMLe_qpTvV2aZU,6834
190
+ ara_cli-0.1.10.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
191
+ ara_cli-0.1.10.1.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
192
+ ara_cli-0.1.10.1.dist-info/top_level.txt,sha256=WM4cLHT5DYUaWzLtRj-gu3yVNFpGQ6lLRI3FMmC-38I,14
193
+ ara_cli-0.1.10.1.dist-info/RECORD,,
@@ -132,7 +132,7 @@ def test_is_rule_valid_rule_is_none():
132
132
  "parent,expected",
133
133
  [
134
134
  (None, True), # parent is None
135
- (MagicMock(rules=None), True), # parent.rules is None
135
+ (MagicMock(rules=None), False), # parent.rules is None
136
136
  ],
137
137
  )
138
138
  def test_is_rule_valid_parent_or_rules_none(parent, expected):
@@ -8,10 +8,11 @@ from ara_cli.list_filter import ListFilter
8
8
  def artefact():
9
9
  """Fixture to create a mock artefact object."""
10
10
  class Artefact:
11
- def __init__(self, tags, status, users, path="dummy.md", content=""):
11
+ def __init__(self, tags, status, users, author="creator_unknown", path="dummy.md", content=""):
12
12
  self.tags = tags
13
13
  self.status = status
14
14
  self.users = users
15
+ self.author = author
15
16
  self.path = path
16
17
  self.content = content
17
18
  return Artefact
@@ -21,33 +22,33 @@ def artefact():
21
22
  (
22
23
  False, False, None,
23
24
  {'artefacts': [
24
- (['tag1', 'tag2'], 'in-progress', ['user1']),
25
- (['tag3'], 'done', ['user2'])
25
+ (['tag1', 'tag2'], 'in-progress', ['user1'], "creator_unknown"),
26
+ (['tag3'], 'done', ['user2'], "creator_unknown")
26
27
  ]},
27
- ['done', 'in-progress', 'tag1', 'tag2', 'tag3', 'user_user1', 'user_user2']
28
+ ['creator_unknown', 'done', 'in-progress', 'tag1', 'tag2', 'tag3', 'user_user1', 'user_user2']
28
29
  ),
29
30
  (
30
31
  False, True, None,
31
32
  {'artefacts': [
32
- (['project_a', 'priority_high'], None, ['user1']),
33
- (['feature_x'], 'done', ['user2'])
33
+ (['project_a', 'priority_high'], None, ['user1'], "creator_unknown"),
34
+ (['feature_x'], 'done', ['user2'], "creator_unknown")
34
35
  ]},
35
36
  ['project_a']
36
37
  ),
37
38
  (
38
- False, False, ListFilter(include_tags=['@kritik']),
39
+ False, False, ListFilter(include_tags=['kritik']),
39
40
  {'artefacts': [
40
- (['release', 'kritik'], 'review', ['dev1']),
41
- (['bugfix'], 'to-do', ['dev2'])
41
+ (['release', 'kritik'], 'review', ['dev1'], "creator_unknown"),
42
+ (['bugfix'], 'to-do', ['dev2'], "creator_unknown")
42
43
  ]},
43
- ['kritik', 'release', 'review', 'user_dev1']
44
+ ['creator_unknown', 'kritik', 'release', 'review', 'user_dev1']
44
45
  ),
45
46
  (
46
47
  True, False, None,
47
48
  {'artefacts': [
48
- (['tag3'], 'status2', ['user3'])
49
+ (['tag3'], 'status2', ['user3'], "creator_unknown")
49
50
  ]},
50
- ['status2', 'tag3', 'user_user3']
51
+ ['creator_unknown', 'status2', 'tag3', 'user_user3']
51
52
  ),
52
53
  (
53
54
  False, False, None,
@@ -80,4 +81,9 @@ def test_extract_tags(mock_directory_navigator, mock_artefact_reader, artefact,
80
81
 
81
82
  mock_artefact_reader.read_artefacts.assert_called_once()
82
83
 
83
- assert sorted(result) == sorted(expected_tags)
84
+ # Convert dictionary result to flat list for comparison
85
+ actual_tags = []
86
+ for group in result.values():
87
+ actual_tags.extend(group)
88
+
89
+ assert sorted(actual_tags) == sorted(expected_tags)