siada-cli 0.0.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.
Files changed (215) hide show
  1. agent_config.yaml +34 -0
  2. siada/__init__.py +13 -0
  3. siada/agent_hub/__init__.py +10 -0
  4. siada/agent_hub/coder/bug_fix_agent.py +398 -0
  5. siada/agent_hub/coder/code_gen_agent.py +235 -0
  6. siada/agent_hub/coder/fe_gen_agent.py +37 -0
  7. siada/agent_hub/coder/issue_review_agent.py +68 -0
  8. siada/agent_hub/coder/prompt/__init__.py +0 -0
  9. siada/agent_hub/coder/prompt/base/__init__.py +0 -0
  10. siada/agent_hub/coder/prompt/base/capabilities.py +18 -0
  11. siada/agent_hub/coder/prompt/base/non_interactive.py +14 -0
  12. siada/agent_hub/coder/prompt/base/prompt_builder.py +33 -0
  13. siada/agent_hub/coder/prompt/base/rules.py +40 -0
  14. siada/agent_hub/coder/prompt/base/tool_use.py +14 -0
  15. siada/agent_hub/coder/prompt/bug_prompt/bug_fix_prompt.py +51 -0
  16. siada/agent_hub/coder/prompt/bug_prompt/rules.py +53 -0
  17. siada/agent_hub/coder/prompt/code_gen_prompt.py +45 -0
  18. siada/agent_hub/coder/prompt/fe_gen_prompt.py +45 -0
  19. siada/agent_hub/coder/prompt/issue_review_prompt.py +121 -0
  20. siada/agent_hub/coder/tracing/__init__.py +22 -0
  21. siada/agent_hub/coder/tracing/logger_tracing_processor.py +458 -0
  22. siada/agent_hub/hooks/__init__.py +0 -0
  23. siada/agent_hub/hooks/io_hooks.py +30 -0
  24. siada/agent_hub/siada_agent.py +214 -0
  25. siada/config/__init__.py +0 -0
  26. siada/config/config_loader.py +67 -0
  27. siada/entrypoint/__init__.py +3 -0
  28. siada/entrypoint/args_parser/__init__.py +0 -0
  29. siada/entrypoint/args_parser/args.py +195 -0
  30. siada/entrypoint/interaction/__init__.py +0 -0
  31. siada/entrypoint/interaction/base_turn.py +107 -0
  32. siada/entrypoint/interaction/config.py +30 -0
  33. siada/entrypoint/interaction/controller.py +122 -0
  34. siada/entrypoint/interaction/nointeractive_controller.py +27 -0
  35. siada/entrypoint/interaction/turn/interface.py +116 -0
  36. siada/entrypoint/interaction/turn/models.py +34 -0
  37. siada/entrypoint/interaction/turn/run_turn.py +641 -0
  38. siada/entrypoint/interaction/turn_factory.py +35 -0
  39. siada/entrypoint/interaction/turn_models.py +28 -0
  40. siada/entrypoint/siadahub.py +413 -0
  41. siada/foundation/__init__.py +0 -0
  42. siada/foundation/code_agent_context.py +48 -0
  43. siada/foundation/config.py +59 -0
  44. siada/foundation/constants.py +2 -0
  45. siada/foundation/context.py +76 -0
  46. siada/foundation/logging.py +341 -0
  47. siada/foundation/tools/__init__.py +0 -0
  48. siada/foundation/tools/get_git_diff.py +105 -0
  49. siada/io/__init__.py +0 -0
  50. siada/io/banner.py +148 -0
  51. siada/io/color_settings.py +207 -0
  52. siada/io/color_utils.py +16 -0
  53. siada/io/components/__init__.py +0 -0
  54. siada/io/components/mdstream.py +204 -0
  55. siada/io/console_printer.py +68 -0
  56. siada/io/io.py +661 -0
  57. siada/io/key_bindings.py +129 -0
  58. siada/io/notification_command.py +40 -0
  59. siada/io/test_banner.py +64 -0
  60. siada/models/__init__.py +0 -0
  61. siada/models/agent.py +47 -0
  62. siada/models/coder/__init__.py +0 -0
  63. siada/models/converter.py +27 -0
  64. siada/models/model_base_config.py +121 -0
  65. siada/models/model_run_config.py +153 -0
  66. siada/provider/__init__.py +0 -0
  67. siada/provider/client_factory.py +112 -0
  68. siada/provider/llm_client.py +11 -0
  69. siada/provider/openrouter/__init__.py +0 -0
  70. siada/provider/openrouter/coverter.py +17 -0
  71. siada/provider/openrouter/openroute_provider.py +33 -0
  72. siada/provider/provider_factory.py +53 -0
  73. siada/queries/tree-sitter-language-pack/README.md +7 -0
  74. siada/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
  75. siada/queries/tree-sitter-language-pack/c-tags.scm +9 -0
  76. siada/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
  77. siada/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
  78. siada/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
  79. siada/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
  80. siada/queries/tree-sitter-language-pack/d-tags.scm +26 -0
  81. siada/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
  82. siada/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
  83. siada/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
  84. siada/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
  85. siada/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
  86. siada/queries/tree-sitter-language-pack/go-tags.scm +42 -0
  87. siada/queries/tree-sitter-language-pack/java-tags.scm +20 -0
  88. siada/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
  89. siada/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
  90. siada/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
  91. siada/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
  92. siada/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
  93. siada/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
  94. siada/queries/tree-sitter-language-pack/python-tags.scm +14 -0
  95. siada/queries/tree-sitter-language-pack/r-tags.scm +21 -0
  96. siada/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
  97. siada/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
  98. siada/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
  99. siada/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
  100. siada/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
  101. siada/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
  102. siada/queries/tree-sitter-languages/README.md +23 -0
  103. siada/queries/tree-sitter-languages/c-tags.scm +9 -0
  104. siada/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
  105. siada/queries/tree-sitter-languages/cpp-tags.scm +15 -0
  106. siada/queries/tree-sitter-languages/dart-tags.scm +91 -0
  107. siada/queries/tree-sitter-languages/elisp-tags.scm +8 -0
  108. siada/queries/tree-sitter-languages/elixir-tags.scm +54 -0
  109. siada/queries/tree-sitter-languages/elm-tags.scm +19 -0
  110. siada/queries/tree-sitter-languages/go-tags.scm +30 -0
  111. siada/queries/tree-sitter-languages/hcl-tags.scm +77 -0
  112. siada/queries/tree-sitter-languages/java-tags.scm +20 -0
  113. siada/queries/tree-sitter-languages/javascript-tags.scm +88 -0
  114. siada/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
  115. siada/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
  116. siada/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
  117. siada/queries/tree-sitter-languages/php-tags.scm +26 -0
  118. siada/queries/tree-sitter-languages/python-tags.scm +12 -0
  119. siada/queries/tree-sitter-languages/ql-tags.scm +26 -0
  120. siada/queries/tree-sitter-languages/ruby-tags.scm +64 -0
  121. siada/queries/tree-sitter-languages/rust-tags.scm +60 -0
  122. siada/queries/tree-sitter-languages/scala-tags.scm +65 -0
  123. siada/queries/tree-sitter-languages/typescript-tags.scm +41 -0
  124. siada/services/__init__.py +30 -0
  125. siada/services/at_file_recommendation_design_document.md +1213 -0
  126. siada/services/code_context_manager.py +136 -0
  127. siada/services/enhanced_fix_result_check.py +546 -0
  128. siada/services/execution_trace_collector.py +207 -0
  129. siada/services/file_recommendation/__init__.py +136 -0
  130. siada/services/file_recommendation/core/__init__.py +17 -0
  131. siada/services/file_recommendation/core/completion_engine.py +351 -0
  132. siada/services/file_recommendation/core/config.py +62 -0
  133. siada/services/file_recommendation/core/file_discovery.py +353 -0
  134. siada/services/file_recommendation/core/suggestion.py +110 -0
  135. siada/services/file_recommendation/utils/__init__.py +22 -0
  136. siada/services/file_recommendation/utils/path_utils.py +138 -0
  137. siada/services/file_recommendation/utils/text_utils.py +253 -0
  138. siada/services/fix_result_check.py +377 -0
  139. siada/services/handle_at_command/README.md +247 -0
  140. siada/services/handle_at_command/__init__.py +115 -0
  141. siada/services/handle_at_command/exceptions.py +46 -0
  142. siada/services/handle_at_command/models.py +92 -0
  143. siada/services/handle_at_command/parser.py +189 -0
  144. siada/services/handle_at_command/processor.py +321 -0
  145. siada/services/handle_at_command/resolver.py +318 -0
  146. siada/services/handle_at_command/utils.py +345 -0
  147. siada/services/model_info_service.py +103 -0
  148. siada/services/siada_runner.py +170 -0
  149. siada/session/__init__.py +29 -0
  150. siada/session/session_manager.py +66 -0
  151. siada/session/session_models.py +43 -0
  152. siada/support/__init__.py +0 -0
  153. siada/support/completer.py +204 -0
  154. siada/support/editor.py +146 -0
  155. siada/support/envprocessor.py +54 -0
  156. siada/support/repo.py +51 -0
  157. siada/support/slash_commands.py +410 -0
  158. siada/support/spinner.py +320 -0
  159. siada/tools/__init__.py +0 -0
  160. siada/tools/ast/README.md +345 -0
  161. siada/tools/ast/ast_tool.py +341 -0
  162. siada/tools/ast/models.py +11 -0
  163. siada/tools/coder/__init__.py +0 -0
  164. siada/tools/coder/ask_followup_question.py +70 -0
  165. siada/tools/coder/cmd_runner.py +132 -0
  166. siada/tools/coder/file_operator.py +284 -0
  167. siada/tools/coder/file_search/README.md +223 -0
  168. siada/tools/coder/file_search/__init__.py +10 -0
  169. siada/tools/coder/file_search/bin/rg-linux-arm64 +0 -0
  170. siada/tools/coder/file_search/bin/rg-linux-x64 +0 -0
  171. siada/tools/coder/file_search/bin/rg-macos-arm64 +0 -0
  172. siada/tools/coder/file_search/bin/rg-macos-x64 +0 -0
  173. siada/tools/coder/file_search/bin/rg.exe +0 -0
  174. siada/tools/coder/file_search/search.py +437 -0
  175. siada/tools/coder/file_search/setup_package.py +150 -0
  176. siada/tools/coder/file_search/test_search.py +142 -0
  177. siada/tools/coder/files.py +147 -0
  178. siada/tools/coder/fix_attempt_completion.py +58 -0
  179. siada/tools/coder/issue_review_completion.py +29 -0
  180. siada/tools/coder/observation/__init__.py +0 -0
  181. siada/tools/coder/observation/error.py +22 -0
  182. siada/tools/coder/observation/file_observation.py +216 -0
  183. siada/tools/coder/observation/observation.py +71 -0
  184. siada/tools/coder/repo_map/__init__.py +157 -0
  185. siada/tools/coder/repo_map/dump.py +29 -0
  186. siada/tools/coder/repo_map/io.py +226 -0
  187. siada/tools/coder/repo_map/repo_map.py +881 -0
  188. siada/tools/coder/repo_map/special.py +203 -0
  189. siada/tools/coder/repo_map/token_counter.py +154 -0
  190. siada/tools/coder/repo_map/waiting.py +221 -0
  191. siada/tools/coder/reproduce_completion.py +39 -0
  192. siada/tools/coder/run_cmd.py +60 -0
  193. siada/tools/coder/test_completion.py +25 -0
  194. siada/tools/coder/tool_docs.py +44 -0
  195. siada/tools/compression_tool.py +200 -0
  196. siada/tools/read_many_files/README.md +220 -0
  197. siada/tools/read_many_files/__init__.py +25 -0
  198. siada/tools/read_many_files/file_processor.py +486 -0
  199. siada/tools/read_many_files/filters.py +326 -0
  200. siada/tools/read_many_files/formatters.py +204 -0
  201. siada/tools/read_many_files/models.py +189 -0
  202. siada/tools/read_many_files_tool.py +233 -0
  203. siada/tools/tool_call_format/__init__.py +55 -0
  204. siada/tools/tool_call_format/file_to_language.py +231 -0
  205. siada/tools/tool_call_format/formatter_factory.py +80 -0
  206. siada/tools/tool_call_format/formatters.py +282 -0
  207. siada/tools/tool_call_format/tool_call_formatter.py +54 -0
  208. siada/tools/web/__init__.py +0 -0
  209. siada/tools/web/web_crawl.py +208 -0
  210. siada/utils.py +194 -0
  211. siada_cli-0.0.1.dist-info/LICENSE +201 -0
  212. siada_cli-0.0.1.dist-info/METADATA +457 -0
  213. siada_cli-0.0.1.dist-info/RECORD +215 -0
  214. siada_cli-0.0.1.dist-info/WHEEL +4 -0
  215. siada_cli-0.0.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,320 @@
1
+ #!/usr/bin/env python
2
+
3
+ """
4
+ Thread-based, killable spinner utility with beautiful animations and colors.
5
+
6
+ Features:
7
+ - Unicode braille patterns for smooth animation
8
+ - Color support with automatic terminal detection
9
+ - Graceful fallback to ASCII for limited terminals
10
+ - Thread-safe operation
11
+
12
+ Use it like:
13
+
14
+ from siada.support.spinner import WaitingSpinner
15
+
16
+ spinner = WaitingSpinner("Waiting for LLM")
17
+ spinner.start()
18
+ ... # long task
19
+ spinner.stop()
20
+
21
+ Or as a context manager:
22
+
23
+ with WaitingSpinner("Processing...") as spinner:
24
+ # long task
25
+ pass
26
+ """
27
+
28
+ import os
29
+ import sys
30
+ import threading
31
+ import time
32
+
33
+ from rich.console import Console
34
+ from rich.text import Text
35
+
36
+
37
+ class Spinner:
38
+ """
39
+ Modern, colorful spinner with smooth unicode animations.
40
+
41
+ Features:
42
+ - Uses unicode braille patterns for smooth, professional animation
43
+ - Automatic color detection and beautiful color cycling
44
+ - Graceful fallback to ASCII for limited terminals
45
+ - Optimized rendering with Rich console integration
46
+ """
47
+
48
+ last_frame_idx = 0 # Class variable to store the last frame index
49
+
50
+ def __init__(self, text: str, text_color: str = "bright_white"):
51
+ self.text = text
52
+ self.text_color = text_color
53
+ self.start_time = time.time()
54
+ self.last_update = 0.0
55
+ self.visible = False
56
+ self.is_tty = sys.stdout.isatty()
57
+ self.console = Console()
58
+ self.use_colors = self._supports_colors()
59
+
60
+ # Modern spinner patterns with better visual appeal
61
+ if self._supports_unicode() and self.use_colors:
62
+ # Beautiful unicode spinner with colors
63
+ self.frames = [
64
+ "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"
65
+ ]
66
+ self.colors = ["cyan", "bright_cyan", "blue", "bright_blue", "magenta", "bright_magenta"]
67
+ self.scan_char = "⠋"
68
+ elif self._supports_unicode():
69
+ # Unicode without colors
70
+ self.frames = [
71
+ "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"
72
+ ]
73
+ self.colors = None
74
+ self.scan_char = "⠋"
75
+ else:
76
+ # Fallback to ASCII with improved pattern
77
+ self.frames = [
78
+ "|", "/", "-", "\\", "|", "/", "-", "\\"
79
+ ]
80
+ self.colors = None
81
+ self.scan_char = "|"
82
+
83
+ self.frame_idx = Spinner.last_frame_idx # Initialize from class variable
84
+ self.animation_len = 1 # Single character spinner
85
+ self.last_display_len = 0 # Length of the last spinner line (frame + text)
86
+
87
+ def _supports_unicode(self) -> bool:
88
+ """Check if terminal supports unicode without side effects."""
89
+ if not self.is_tty:
90
+ return False
91
+ try:
92
+ # Test encoding capability without actually writing to stdout
93
+ test_char = "⠋"
94
+ test_char.encode(sys.stdout.encoding or 'utf-8')
95
+ return True
96
+ except (UnicodeEncodeError, AttributeError, LookupError):
97
+ return False
98
+ except Exception:
99
+ return False
100
+
101
+ def _supports_colors(self) -> bool:
102
+ """Check if terminal supports colors"""
103
+ if not self.is_tty:
104
+ return False
105
+ # Check environment variables that indicate color support
106
+ term = os.environ.get('TERM', '').lower()
107
+ colorterm = os.environ.get('COLORTERM', '').lower()
108
+ return (
109
+ 'color' in term or
110
+ term in ('xterm', 'xterm-256color', 'screen', 'tmux') or
111
+ colorterm in ('truecolor', '24bit') or
112
+ hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
113
+ )
114
+
115
+ def _next_frame(self) -> str:
116
+ """Get the next frame without applying colors (colors applied in step method)."""
117
+ frame = self.frames[self.frame_idx]
118
+ self.frame_idx = (self.frame_idx + 1) % len(self.frames)
119
+ Spinner.last_frame_idx = self.frame_idx # Update class variable
120
+ return frame
121
+
122
+ def _get_current_color(self) -> str:
123
+ """Get the current color for the spinner frame."""
124
+ if self.use_colors and self.colors:
125
+ return self.colors[self.frame_idx % len(self.colors)]
126
+ return "white"
127
+
128
+ def set_text_color(self, color: str):
129
+ """Set the color for the spinner text."""
130
+ self.text_color = color
131
+
132
+ def set_text(self, text: str, color: str = None):
133
+ """Set the spinner text and optionally change its color."""
134
+ self.text = text
135
+ if color is not None:
136
+ self.text_color = color
137
+
138
+ def step(self, text: str = None) -> None:
139
+ """Update the spinner animation and optionally change the text."""
140
+ if text is not None:
141
+ self.text = text
142
+
143
+ if not self.is_tty:
144
+ return
145
+
146
+ try:
147
+ now = time.time()
148
+ if not self.visible and now - self.start_time >= 0.5:
149
+ self.visible = True
150
+ self.last_update = 0.0
151
+ if self.is_tty:
152
+ self.console.show_cursor(False)
153
+
154
+ if not self.visible or now - self.last_update < 0.1:
155
+ return
156
+
157
+ self.last_update = now
158
+ frame_str = self._next_frame()
159
+ except Exception:
160
+ # If anything goes wrong, just skip this frame
161
+ return
162
+
163
+ # Create the spinner line with consistent formatting
164
+ if self.use_colors and self.colors:
165
+ # For colored output, use rich text formatting
166
+ current_color = self._get_current_color()
167
+ text_content = Text()
168
+ text_content.append(frame_str, style=f"bold {current_color}")
169
+ text_content.append(f" {self.text}", style=self.text_color)
170
+
171
+ # Clear the line and print with rich
172
+ sys.stdout.write("\r")
173
+ with self.console.capture() as capture:
174
+ self.console.print(text_content, end="")
175
+ output = capture.get()
176
+ sys.stdout.write(output)
177
+ self.last_display_len = len(frame_str) + 1 + len(self.text) # Approximate length
178
+ else:
179
+ # Simple output for terminals without color support
180
+ line_to_display = f"{frame_str} {self.text}"
181
+
182
+ # Determine the maximum width for the spinner line
183
+ max_spinner_width = self.console.width - 2 if self.console.width > 2 else 0
184
+ if max_spinner_width > 0 and len(line_to_display) > max_spinner_width:
185
+ line_to_display = line_to_display[:max_spinner_width]
186
+
187
+ # Calculate padding to clear any remnants from a longer previous line
188
+ padding_to_clear = " " * max(0, self.last_display_len - len(line_to_display))
189
+
190
+ # Write the spinner frame and text
191
+ sys.stdout.write(f"\r{line_to_display}{padding_to_clear}")
192
+ self.last_display_len = len(line_to_display)
193
+
194
+ sys.stdout.flush()
195
+
196
+ def end(self) -> None:
197
+ """Stop the spinner and clean up the display."""
198
+ try:
199
+ if self.visible and self.is_tty:
200
+ # Clear the current line more reliably
201
+ sys.stdout.write("\r\033[K") # \033[K clears from cursor to end of line
202
+ sys.stdout.flush()
203
+ self.console.show_cursor(True)
204
+ except Exception:
205
+ # If cleanup fails, just continue - better than crashing
206
+ pass
207
+ finally:
208
+ self.visible = False
209
+
210
+
211
+ class WaitingSpinner:
212
+ """Background spinner that can be started/stopped safely and restarted."""
213
+
214
+ def __init__(self, text: str = "Waiting for LLM", delay: float = 0.15, text_color: str = "bright_cyan"):
215
+ self.text = text
216
+ self.text_color = text_color
217
+ self.delay = delay
218
+ self.spinner = None
219
+ self._stop_event = None
220
+ self._thread = None
221
+
222
+ def _spin(self):
223
+ """Internal spinning loop."""
224
+ if self.spinner is None:
225
+ return
226
+ while not self._stop_event.is_set():
227
+ self.spinner.step()
228
+ time.sleep(self.delay)
229
+ self.spinner.end()
230
+
231
+ def start(self):
232
+ """Start the spinner in a background thread."""
233
+ if self._thread is not None and self._thread.is_alive():
234
+ return # Already running
235
+
236
+ # Create fresh instances for restart capability
237
+ self.spinner = Spinner(self.text, self.text_color)
238
+ self._stop_event = threading.Event()
239
+ self._thread = threading.Thread(target=self._spin, daemon=True)
240
+ self._thread.start()
241
+
242
+ def stop(self):
243
+ """Request the spinner to stop and wait briefly for the thread to exit."""
244
+ if self._stop_event is not None:
245
+ self._stop_event.set()
246
+ if self._thread is not None and self._thread.is_alive():
247
+ self._thread.join(timeout=self.delay * 2) # Give more time for cleanup
248
+ if self.spinner is not None:
249
+ self.spinner.end()
250
+
251
+ def update_text(self, text: str, color: str = None):
252
+ """Update the spinner text dynamically and optionally change its color."""
253
+ self.text = text
254
+ if color is not None:
255
+ self.text_color = color
256
+ if self.spinner is not None:
257
+ if color is not None:
258
+ self.spinner.set_text(text, color)
259
+ else:
260
+ self.spinner.text = text
261
+
262
+ def set_text_color(self, color: str):
263
+ """Set the color for the spinner text."""
264
+ self.text_color = color
265
+ if self.spinner is not None:
266
+ self.spinner.set_text_color(color)
267
+
268
+ # Allow use as a context-manager
269
+ def __enter__(self):
270
+ self.start()
271
+ return self
272
+
273
+ def __exit__(self, exc_type, exc_val, exc_tb):
274
+ self.stop()
275
+
276
+
277
+ def main():
278
+ """Demo the improved spinner with colors and unicode."""
279
+ print("🎨 Testing the colorful spinner...")
280
+ print("Press Ctrl+C to stop")
281
+
282
+ # Test the basic Spinner with different text colors
283
+ print("\n🔸 Testing basic Spinner with color changes...")
284
+ spinner = Spinner("Starting with white text...", "bright_white")
285
+ try:
286
+ for i in range(100):
287
+ time.sleep(0.1)
288
+ if i == 20:
289
+ spinner.set_text("Now in green! 🟢", "bright_green")
290
+ elif i == 40:
291
+ spinner.set_text("Switching to red! 🔴", "bright_red")
292
+ elif i == 60:
293
+ spinner.set_text("Beautiful blue! 🔵", "bright_blue")
294
+ elif i == 80:
295
+ spinner.set_text("Magnificent magenta! 🟣", "bright_magenta")
296
+ else:
297
+ spinner.step()
298
+ spinner.end()
299
+ print("✅ Color-changing spinner test completed!")
300
+
301
+ # Test the WaitingSpinner with color changes
302
+ print("\n🔸 Testing WaitingSpinner with dynamic colors...")
303
+ with WaitingSpinner("Starting in cyan...", text_color="bright_cyan") as waiting_spinner:
304
+ time.sleep(1)
305
+ waiting_spinner.update_text("Now in yellow! ⚡", "bright_yellow")
306
+ time.sleep(1)
307
+ waiting_spinner.set_text_color("bright_red")
308
+ waiting_spinner.update_text("Finishing in red! 🚀")
309
+ time.sleep(1)
310
+
311
+ print("✅ All colorful tests completed successfully! 🌈")
312
+
313
+ except KeyboardInterrupt:
314
+ print("\n❌ Interrupted by user.")
315
+ finally:
316
+ spinner.end()
317
+
318
+
319
+ if __name__ == "__main__":
320
+ main()
File without changes
@@ -0,0 +1,345 @@
1
+ # AST Code Definition Extraction Tool
2
+
3
+ This module provides code definition extraction functionality based on tree-sitter and pygments, primarily used for analyzing source code files and extracting function, class, method, and other definition information.
4
+
5
+ ## Main Features
6
+
7
+ ### `_list_code_definition_names(fname, rel_fname=None)`
8
+
9
+ Parses a source code file and returns a summary of its code definitions.
10
+
11
+ #### Parameters
12
+ - `fname` (str): Absolute path to the source file
13
+ - `rel_fname` (str, optional): Relative path to the source file, defaults to filename
14
+
15
+ #### Returns
16
+ - `str`: Formatted string containing file structure and code definitions
17
+
18
+ ## Parsing Principles
19
+
20
+ ### 1. Dual Parsing Strategy
21
+ - **Primary Parser**: Uses tree-sitter for syntax tree parsing, providing precise code structure analysis
22
+ - **Fallback Parser**: Uses pygments for lexical analysis as a backup for reference extraction
23
+
24
+ ### 2. Parsing Workflow
25
+ 1. **Language Detection**: Identifies programming language based on file extension
26
+ 2. **Syntax Parsing**: Uses tree-sitter to build Abstract Syntax Tree (AST)
27
+ 3. **Query Execution**: Runs predefined query patterns to extract definitions and references
28
+ 4. **Fallback Processing**: Uses pygments to supplement reference information if only definitions are found
29
+ 5. **Format Output**: Uses TreeContext to generate code tree structure with context
30
+
31
+ ### 3. Core Components
32
+ - **Tag Model**: Data structure representing code identifiers
33
+ - **TreeContext**: Provides code context and formatting functionality
34
+ - **Query Files**: .scm files stored in `siada/queries/` directory, defining parsing rules for each language
35
+
36
+ ## Supported Programming Languages
37
+
38
+ Based on tree-sitter language support, including but not limited to:
39
+
40
+ ### Fully Supported Languages
41
+ - **Python** (.py) - functions, classes, methods, decorators, async functions, etc.
42
+ - **JavaScript** (.js) - functions, classes, arrow functions, object methods, etc.
43
+ - **TypeScript** (.ts) - type definitions, interfaces, classes, functions, etc.
44
+ - **Java** (.java) - classes, methods, interfaces, enums, etc.
45
+ - **C/C++** (.c, .cpp, .h, .hpp) - functions, structs, classes, etc.
46
+ - **Go** (.go) - functions, structs, methods, interfaces, etc.
47
+ - **Rust** (.rs) - functions, structs, traits, impl, etc.
48
+ - **Ruby** (.rb) - classes, methods, modules, etc.
49
+
50
+ ### Partially Supported Languages
51
+ - **C#** (.cs) - classes, methods, properties, etc.
52
+ - **PHP** (.php) - classes, functions, methods, etc.
53
+ - **Scala** (.scala) - classes, objects, traits, methods, etc.
54
+ - **Kotlin** (.kt) - classes, functions, objects, etc.
55
+
56
+ ### Query File Locations
57
+ - `siada/queries/tree-sitter-language-pack/` - Primary query files
58
+ - `siada/queries/tree-sitter-languages/` - Fallback query files
59
+
60
+ ## Output Formats
61
+
62
+ ### 1. Standard Format (when definitions exist)
63
+ ```
64
+ File: <filename>
65
+ Definitions: <definition_count>, References: <reference_count>
66
+
67
+ <code_tree_structure>
68
+ ```
69
+
70
+ ### 2. Simplified Format (fallback mode)
71
+ ```
72
+ File: <filename>
73
+ Definitions: <definition_count>, References: <reference_count>
74
+
75
+ Definitions found:
76
+ - <definition_name> (line <line_number>)
77
+ - <definition_name> (line <line_number>)
78
+ ...
79
+ ```
80
+
81
+ ### 3. Error Format (no definitions or errors)
82
+ ```
83
+ No code definitions found in <filename>
84
+ ```
85
+
86
+ ## Output Examples
87
+
88
+ ### Python File Example
89
+
90
+ **Input File** (`calculator.py`):
91
+ ```python
92
+ """A simple calculator module with multiple classes and functions."""
93
+
94
+ class Calculator:
95
+ """Basic calculator with arithmetic operations."""
96
+
97
+ def __init__(self):
98
+ self.history = []
99
+
100
+ def add(self, a, b):
101
+ result = a + b
102
+ self.history.append(f"{a} + {b} = {result}")
103
+ return result
104
+
105
+ def multiply(self, a, b):
106
+ result = a * b
107
+ self.history.append(f"{a} * {b} = {result}")
108
+ return result
109
+
110
+ class ScientificCalculator(Calculator):
111
+ """Extended calculator with scientific functions."""
112
+
113
+ def power(self, base, exponent):
114
+ result = base ** exponent
115
+ self.history.append(f"{base} ^ {exponent} = {result}")
116
+ return result
117
+
118
+ def create_calculator(scientific=False):
119
+ """Factory function to create calculator instances."""
120
+ if scientific:
121
+ return ScientificCalculator()
122
+ return Calculator()
123
+
124
+ # Global configuration
125
+ DEFAULT_PRECISION = 2
126
+ ```
127
+
128
+ **Parsed Output**:
129
+ ```
130
+ File: calculator.py
131
+ Definitions: 6, References: 15
132
+
133
+ ⋮
134
+ │class Calculator:
135
+ │ """Basic calculator with arithmetic operations."""
136
+ │
137
+ │ def __init__(self):
138
+ ⋮
139
+ │ def add(self, a, b):
140
+ ⋮
141
+ │ def multiply(self, a, b):
142
+ ⋮
143
+ │class ScientificCalculator(Calculator):
144
+ │ """Extended calculator with scientific functions."""
145
+ │
146
+ │ def power(self, base, exponent):
147
+ ⋮
148
+ │def create_calculator(scientific=False):
149
+ ⋮
150
+ ```
151
+
152
+ **Key Differences from Source**:
153
+ - Shows only definition signatures, omitting implementation details
154
+ - Displays statistical summary (6 definitions, 15 references)
155
+ - Uses `⋮` to indicate omitted code sections
156
+ - Focuses on structural overview rather than complete code
157
+
158
+ ### JavaScript File Example
159
+
160
+ **Input File** (`user-manager.js`):
161
+ ```javascript
162
+ /**
163
+ * User management system with authentication
164
+ */
165
+
166
+ class User {
167
+ constructor(username, email) {
168
+ this.username = username;
169
+ this.email = email;
170
+ this.isActive = true;
171
+ }
172
+
173
+ activate() {
174
+ this.isActive = true;
175
+ console.log(`User ${this.username} activated`);
176
+ }
177
+
178
+ deactivate() {
179
+ this.isActive = false;
180
+ console.log(`User ${this.username} deactivated`);
181
+ }
182
+ }
183
+
184
+ class UserManager {
185
+ constructor() {
186
+ this.users = new Map();
187
+ }
188
+
189
+ addUser(username, email) {
190
+ const user = new User(username, email);
191
+ this.users.set(username, user);
192
+ return user;
193
+ }
194
+
195
+ static getInstance() {
196
+ if (!UserManager.instance) {
197
+ UserManager.instance = new UserManager();
198
+ }
199
+ return UserManager.instance;
200
+ }
201
+ }
202
+
203
+ const authService = {
204
+ login: function(username, password) {
205
+ // Authentication logic here
206
+ return true;
207
+ },
208
+
209
+ logout: (username) => {
210
+ // Logout logic here
211
+ console.log(`${username} logged out`);
212
+ }
213
+ };
214
+
215
+ async function initializeSystem() {
216
+ const manager = UserManager.getInstance();
217
+ return manager;
218
+ }
219
+ ```
220
+
221
+ **Parsed Output**:
222
+ ```
223
+ File: user-manager.js
224
+ Definitions: 9, References: 8
225
+
226
+ ⋮
227
+ │class User {
228
+ │ constructor(username, email) {
229
+ │ this.username = username;
230
+ │ this.email = email;
231
+ │ this.isActive = true;
232
+ │ }
233
+ │
234
+ │ activate() {
235
+ ⋮
236
+ │ deactivate() {
237
+ ⋮
238
+ │class UserManager {
239
+ │ constructor() {
240
+ │ this.users = new Map();
241
+ │ }
242
+ │
243
+ │ addUser(username, email) {
244
+ ⋮
245
+ │ static getInstance() {
246
+ ⋮
247
+ │const authService = {
248
+ │ login: function(username, password) {
249
+ ⋮
250
+ │ logout: (username) => {
251
+ ⋮
252
+ │async function initializeSystem() {
253
+ ⋮
254
+ ```
255
+
256
+ **Key Differences from Source**:
257
+ - Extracts 9 definitions (classes, methods, functions, object properties)
258
+ - Counts 8 references to other identifiers
259
+ - Omits implementation details and comments
260
+ - Shows structural hierarchy and method signatures
261
+
262
+ ### Empty or Unsupported File Example
263
+
264
+ **Output**:
265
+ ```
266
+ No code definitions found in empty_file.py
267
+ ```
268
+
269
+ ## Usage Examples
270
+
271
+ ### Basic Usage
272
+ ```python
273
+ from siada.tools.ast.ast_tool import _list_code_definition_names
274
+
275
+ # Analyze Python file
276
+ result = _list_code_definition_names("/path/to/file.py")
277
+ print(result)
278
+
279
+ # Specify relative path
280
+ result = _list_code_definition_names("/absolute/path/to/file.py", "src/file.py")
281
+ print(result)
282
+ ```
283
+
284
+ ### Batch Processing
285
+ ```python
286
+ import os
287
+ from pathlib import Path
288
+
289
+ def analyze_project(project_dir):
290
+ """Analyze all Python files in a project"""
291
+ for py_file in Path(project_dir).rglob("*.py"):
292
+ rel_path = py_file.relative_to(project_dir)
293
+ result = _list_code_definition_names(str(py_file), str(rel_path))
294
+ print(f"\n{'='*50}")
295
+ print(result)
296
+
297
+ # Usage example
298
+ analyze_project("/path/to/your/project")
299
+ ```
300
+
301
+ ### Error Handling
302
+ ```python
303
+ def safe_analyze(file_path):
304
+ """Safely analyze file with error handling"""
305
+ try:
306
+ result = _list_code_definition_names(file_path)
307
+ if "No code definitions found" in result:
308
+ print(f"No definitions found in {file_path}")
309
+ else:
310
+ print(result)
311
+ except Exception as e:
312
+ print(f"Error analyzing {file_path}: {e}")
313
+ ```
314
+
315
+ ## Technical Details
316
+
317
+ ### Dependencies
318
+ - `grep-ast`: Provides TreeContext and language identification functionality
319
+ - `pygments`: Provides lexical analysis fallback functionality
320
+ - `tree-sitter`: Underlying syntax parsing engine
321
+
322
+ ### Performance Characteristics
323
+ - **Memory Efficiency**: Uses generator pattern for processing large files
324
+ - **Error Tolerance**: Syntax errors don't completely prevent parsing
325
+ - **Cache Optimization**: TreeContext provides context caching
326
+ - **Line Length Limiting**: Automatically truncates overly long lines to prevent excessive output
327
+
328
+ ### Limitations and Considerations
329
+ 1. **File Encoding**: Only supports UTF-8 encoded files
330
+ 2. **File Size**: May have performance impact on very large files
331
+ 3. **Language Support**: Depends on availability of tree-sitter query files
332
+ 4. **Accuracy**: Complex macro definitions or dynamic code may not be accurately identified
333
+
334
+ ## Related Modules
335
+
336
+ - `models.py`: Defines Tag data model
337
+ - `../../../queries/`: Stores tree-sitter query files for various languages
338
+ - `../../../tests/tools/ast/`: Complete test suite
339
+
340
+ ## Changelog
341
+
342
+ - Support for multiple programming languages code definition extraction
343
+ - Implementation of dual parsing strategy for improved accuracy
344
+ - Added error handling and fallback mechanisms
345
+ - Optimized output format and performance