raggiecode 0.2.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 (93) hide show
  1. Agent/__init__.py +0 -0
  2. Agent/agent.py +891 -0
  3. Agent/chat_history_db.py +1500 -0
  4. Agent/command.py +49 -0
  5. Agent/config.py +46 -0
  6. Agent/effort_levels.py +33 -0
  7. Agent/git_manager.py +727 -0
  8. Agent/tools.py +35 -0
  9. Commands/__init__.py +18 -0
  10. Commands/effort.py +42 -0
  11. Commands/global_todo.py +23 -0
  12. Commands/help.py +22 -0
  13. Commands/reasoning.py +24 -0
  14. Commands/redo.py +11 -0
  15. Commands/reindex.py +27 -0
  16. Commands/shell.py +28 -0
  17. Commands/stream.py +24 -0
  18. Commands/undo.py +13 -0
  19. Commands/unlimited_effort.py +8 -0
  20. Commands/window_size.py +29 -0
  21. RAG/__init__.py +0 -0
  22. RAG/document.py +119 -0
  23. RAG/find.py +408 -0
  24. RAG/graph.py +231 -0
  25. Tools/GetFileCodeStructure.py +43 -0
  26. Tools/GetSymbolSourceCode.py +27 -0
  27. Tools/__init__.py +39 -0
  28. Tools/ask_user.py +102 -0
  29. Tools/dispatch_subagent.py +215 -0
  30. Tools/document.py +35 -0
  31. Tools/edit_symbol.py +250 -0
  32. Tools/fuzzy_search.py +119 -0
  33. Tools/list_dir.py +51 -0
  34. Tools/read.py +49 -0
  35. Tools/read_image.py +75 -0
  36. Tools/remove.py +75 -0
  37. Tools/replace.py +305 -0
  38. Tools/search.py +41 -0
  39. Tools/shell.py +149 -0
  40. Tools/shell_kill.py +87 -0
  41. Tools/temp_background_service.py +113 -0
  42. Tools/todo_list.py +481 -0
  43. Tools/utils.py +116 -0
  44. Tools/view_changes.py +179 -0
  45. Tools/walk_call_tree.py +30 -0
  46. Tools/web_fetch.py +175 -0
  47. Tools/web_search.py +69 -0
  48. Tools/write.py +48 -0
  49. cli.py +111 -0
  50. config/__init__.py +0 -0
  51. config/coder_system_prompt.md +119 -0
  52. config/roles.json +43 -0
  53. config/tools.json +709 -0
  54. indexing/__init__.py +0 -0
  55. indexing/cli.py +128 -0
  56. indexing/code_index_sdk.py +832 -0
  57. indexing/code_indexer.py +1763 -0
  58. indexing/db_schema.py +396 -0
  59. indexing/export_to_json.py +346 -0
  60. indexing/extractors.py +189 -0
  61. indexing/file_utils.py +97 -0
  62. indexing/frontend/__init__.py +0 -0
  63. indexing/frontend/css_extractor.py +195 -0
  64. indexing/frontend/css_parser.py +387 -0
  65. indexing/frontend/css_selector_utils.py +226 -0
  66. indexing/frontend/edit_safety.py +573 -0
  67. indexing/frontend/graph.py +838 -0
  68. indexing/frontend/html_extractor.py +496 -0
  69. indexing/frontend/html_parser.py +314 -0
  70. indexing/frontend/jsx_extractor.py +1204 -0
  71. indexing/frontend/location_lookup.py +247 -0
  72. indexing/frontend/resolver.py +485 -0
  73. indexing/frontend/runtime_resolver.py +862 -0
  74. indexing/frontend/semantic_output.py +705 -0
  75. indexing/frontend/source_location.py +69 -0
  76. indexing/frontend_config.py +72 -0
  77. indexing/frontend_models.py +347 -0
  78. indexing/language_config.py +360 -0
  79. indexing/models.py +284 -0
  80. indexing/node_utils.py +1112 -0
  81. indexing/parse_worker.py +1082 -0
  82. indexing/queries.py +1542 -0
  83. indexing/sdk_examples.py +426 -0
  84. interactive.py +248 -0
  85. raggie.py +673 -0
  86. raggiecode-0.2.1.dist-info/METADATA +944 -0
  87. raggiecode-0.2.1.dist-info/RECORD +93 -0
  88. raggiecode-0.2.1.dist-info/WHEEL +5 -0
  89. raggiecode-0.2.1.dist-info/entry_points.txt +2 -0
  90. raggiecode-0.2.1.dist-info/top_level.txt +10 -0
  91. skills/__init__.py +3 -0
  92. skills/manager.py +114 -0
  93. skills/tool.py +121 -0
@@ -0,0 +1,314 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ HTML parser using tree-sitter.
4
+ Parses HTML source and builds a document tree of elements.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from typing import List, Dict, Optional
9
+
10
+ from indexing.language_config import LANGUAGE_CONFIG
11
+ from indexing.node_utils import create_parser
12
+ from indexing.frontend.source_location import SourceLocation, node_to_location, extract_range
13
+
14
+
15
+ @dataclass
16
+ class ParsedAttribute:
17
+ name: str
18
+ value: Optional[str]
19
+ location: SourceLocation
20
+
21
+
22
+ @dataclass
23
+ class ParsedElement:
24
+ tag_name: str
25
+ element_type: str # 'element', 'script_element', 'style_element'
26
+ location: SourceLocation
27
+ start_tag_location: SourceLocation
28
+ attributes: List[ParsedAttribute] = field(default_factory=list)
29
+ children: List["ParsedElement"] = field(default_factory=list)
30
+ element_id_attr: Optional[str] = None
31
+ static_classes: List[str] = field(default_factory=list)
32
+ attributes_dict: Dict[str, str] = field(default_factory=dict)
33
+ raw_text: Optional[str] = None # for script/style content
34
+ has_end_tag: bool = True
35
+ parent: Optional["ParsedElement"] = None
36
+ depth: int = 0
37
+
38
+
39
+ @dataclass
40
+ class HTMLDocument:
41
+ elements: List[ParsedElement] = field(default_factory=list)
42
+ scripts: List[ParsedElement] = field(default_factory=list)
43
+ styles: List[ParsedElement] = field(default_factory=list)
44
+ errors: List[Dict] = field(default_factory=list)
45
+ source_bytes: bytes = b""
46
+
47
+
48
+ # Tags that are always void (no end tag expected)
49
+ VOID_TAGS = {"area", "base", "br", "col", "embed", "hr", "img", "input",
50
+ "link", "meta", "param", "source", "track", "wbr"}
51
+
52
+
53
+ _html_parser = None
54
+
55
+ def _get_parser():
56
+ """Get or create the HTML parser (cached)."""
57
+ global _html_parser
58
+ if _html_parser is None:
59
+ lang_module = LANGUAGE_CONFIG.get("html", {}).get("language_module")
60
+ if lang_module is None:
61
+ return None
62
+ _html_parser = create_parser(lang_module)
63
+ return _html_parser
64
+
65
+
66
+ def _extract_attributes(start_tag_node, source_bytes) -> List[ParsedAttribute]:
67
+ """Extract attributes from a start_tag node."""
68
+ attrs = []
69
+ for i in range(start_tag_node.child_count):
70
+ child = start_tag_node.child(i)
71
+ if child.type == "attribute":
72
+ name = None
73
+ value = None
74
+ for j in range(child.child_count):
75
+ ac = child.child(j)
76
+ if ac.type == "attribute_name":
77
+ name = extract_range(source_bytes, ac.start_byte, ac.end_byte)
78
+ elif ac.type == "quoted_attribute_value":
79
+ raw = extract_range(source_bytes, ac.start_byte, ac.end_byte)
80
+ if len(raw) >= 2 and raw[0] in ('"', "'") and raw[-1] == raw[0]:
81
+ value = raw[1:-1]
82
+ else:
83
+ value = raw
84
+ elif ac.type == "attribute_value":
85
+ value = extract_range(source_bytes, ac.start_byte, ac.end_byte)
86
+ if name:
87
+ attrs.append(ParsedAttribute(
88
+ name=name,
89
+ value=value,
90
+ location=node_to_location(child),
91
+ ))
92
+ return attrs
93
+
94
+
95
+ def _parse_element(node, source_bytes, parent=None, depth=0) -> Optional[ParsedElement]:
96
+ """Parse a tree-sitter element node into a ParsedElement.
97
+
98
+ Iterative implementation using explicit stack to avoid recursion.
99
+ """
100
+ if node.type not in ("element", "script_element", "style_element"):
101
+ return None
102
+
103
+ # Stack entries: (ts_node, parent_elem, depth, children_list)
104
+ # Returns the parsed element for each stack entry.
105
+ root_elem = [None]
106
+ stack = [(node, parent, depth, None)]
107
+
108
+ while stack:
109
+ ts_node, parent_elem, d, children_list = stack.pop()
110
+
111
+ start_tag = None
112
+ end_tag = None
113
+ raw_text = None
114
+ child_ts_nodes = []
115
+
116
+ for i in range(ts_node.child_count):
117
+ child = ts_node.child(i)
118
+ if child.type == "start_tag":
119
+ start_tag = child
120
+ elif child.type == "end_tag":
121
+ end_tag = child
122
+ elif child.type == "raw_text":
123
+ raw_text = extract_range(source_bytes, child.start_byte, child.end_byte)
124
+ elif child.type in ("element", "script_element", "style_element"):
125
+ child_ts_nodes.append(child)
126
+
127
+ if start_tag is None:
128
+ continue
129
+
130
+ tag_name = ""
131
+ for i in range(start_tag.child_count):
132
+ c = start_tag.child(i)
133
+ if c.type == "tag_name":
134
+ tag_name = extract_range(source_bytes, c.start_byte, c.end_byte)
135
+ break
136
+
137
+ parsed_attrs = _extract_attributes(start_tag, source_bytes)
138
+ attrs_dict = {}
139
+ element_id = None
140
+ classes = []
141
+ for attr in parsed_attrs:
142
+ attrs_dict[attr.name] = attr.value if attr.value is not None else ""
143
+ if attr.name == "id":
144
+ element_id = attr.value
145
+ elif attr.name == "class":
146
+ if attr.value:
147
+ classes = attr.value.split()
148
+
149
+ elem = ParsedElement(
150
+ tag_name=tag_name,
151
+ element_type=ts_node.type,
152
+ location=node_to_location(ts_node),
153
+ start_tag_location=node_to_location(start_tag),
154
+ attributes=parsed_attrs,
155
+ attributes_dict=attrs_dict,
156
+ element_id_attr=element_id,
157
+ static_classes=classes,
158
+ raw_text=raw_text,
159
+ has_end_tag=end_tag is not None,
160
+ parent=parent_elem,
161
+ depth=d,
162
+ )
163
+
164
+ if children_list is not None:
165
+ # This was a child being processed — add it to parent's children
166
+ children_list.append(elem)
167
+
168
+ if root_elem[0] is None and ts_node == node:
169
+ root_elem[0] = elem
170
+
171
+ # Push child TS nodes onto the stack for processing
172
+ # We need a children list to collect parsed children
173
+ elem_children = []
174
+ elem.children = elem_children # Will be filled as children are processed
175
+
176
+ for child_ts in reversed(child_ts_nodes):
177
+ stack.append((child_ts, elem, d + 1, elem_children))
178
+
179
+ return root_elem[0]
180
+
181
+
182
+ def _collect_errors(node, source_bytes, errors: list):
183
+ """Collect parse errors from the tree (iterative)."""
184
+ if not node.has_error:
185
+ if node.type == "ERROR":
186
+ text = extract_range(source_bytes, node.start_byte, node.end_byte)[:80]
187
+ errors.append({
188
+ "type": "parse_error",
189
+ "location": node_to_location(node).to_dict(),
190
+ "text": text,
191
+ })
192
+ return
193
+
194
+ stack = [node]
195
+ while stack:
196
+ n = stack.pop()
197
+ if n.type == "ERROR":
198
+ text = extract_range(source_bytes, n.start_byte, n.end_byte)[:80]
199
+ errors.append({
200
+ "type": "parse_error",
201
+ "location": node_to_location(n).to_dict(),
202
+ "text": text,
203
+ })
204
+ if n.has_error:
205
+ for i in range(n.child_count):
206
+ stack.append(n.child(i))
207
+
208
+
209
+ def _collect_from_error(error_node, source_bytes, doc: HTMLDocument):
210
+ """Iteratively collect elements, scripts, and styles from an ERROR node."""
211
+ stack = [error_node]
212
+ while stack:
213
+ n = stack.pop()
214
+ error_children = []
215
+ for i in range(n.child_count):
216
+ child = n.child(i)
217
+ if child.type in ("element", "script_element", "style_element"):
218
+ elem = _parse_element(child, source_bytes)
219
+ if elem:
220
+ if elem.element_type == "script_element":
221
+ doc.scripts.append(elem)
222
+ elif elem.element_type == "style_element":
223
+ doc.styles.append(elem)
224
+ else:
225
+ doc.elements.append(elem)
226
+ elif child.type == "ERROR":
227
+ error_children.append(child)
228
+ # Push error children in reverse so earlier ones are processed first
229
+ for child in reversed(error_children):
230
+ stack.append(child)
231
+
232
+
233
+ def _flatten_elements(elem: ParsedElement, result: list):
234
+ """Flatten element tree into a list (depth-first, iterative)."""
235
+ stack = [elem]
236
+ while stack:
237
+ e = stack.pop()
238
+ result.append(e)
239
+ # Push children in reverse so leftmost is processed first
240
+ for i in range(len(e.children) - 1, -1, -1):
241
+ stack.append(e.children[i])
242
+
243
+
244
+ def parse_html(source_bytes: bytes) -> HTMLDocument:
245
+ """Parse HTML source bytes and return an HTMLDocument.
246
+
247
+ Args:
248
+ source_bytes: Raw HTML file content as bytes.
249
+
250
+ Returns:
251
+ HTMLDocument with parsed elements, scripts, styles, and errors.
252
+ """
253
+ parser = _get_parser()
254
+ if parser is None:
255
+ return HTMLDocument(source_bytes=source_bytes, errors=[{
256
+ "type": "missing_parser",
257
+ "message": "HTML tree-sitter grammar not available",
258
+ }])
259
+
260
+ tree = parser.parse(source_bytes)
261
+ root = tree.root_node
262
+
263
+ doc = HTMLDocument(source_bytes=source_bytes)
264
+
265
+ # Collect parse errors
266
+ if root.has_error:
267
+ _collect_errors(root, source_bytes, doc.errors)
268
+
269
+ # Walk top-level nodes (including ERROR nodes for malformed HTML recovery)
270
+ for i in range(root.child_count):
271
+ child = root.child(i)
272
+ if child.type in ("element", "script_element", "style_element"):
273
+ elem = _parse_element(child, source_bytes)
274
+ if elem:
275
+ if elem.element_type == "script_element":
276
+ doc.scripts.append(elem)
277
+ elif elem.element_type == "style_element":
278
+ doc.styles.append(elem)
279
+ else:
280
+ doc.elements.append(elem)
281
+ elif child.type == "doctype":
282
+ pass # Skip doctype
283
+ elif child.type == "ERROR":
284
+ # Malformed HTML: recurse into ERROR node to find parseable elements
285
+ _collect_from_error(child, source_bytes, doc)
286
+
287
+ # Also collect nested scripts and styles from within elements
288
+ all_elements = []
289
+ for elem in doc.elements:
290
+ _flatten_elements(elem, all_elements)
291
+
292
+ for elem in all_elements:
293
+ for child in elem.children:
294
+ if child.element_type == "script_element" and child not in doc.scripts:
295
+ doc.scripts.append(child)
296
+ elif child.element_type == "style_element" and child not in doc.styles:
297
+ doc.styles.append(child)
298
+
299
+ return doc
300
+
301
+
302
+ def get_all_elements(doc: HTMLDocument) -> List[ParsedElement]:
303
+ """Get all elements (including scripts and styles) as a flat list."""
304
+ result = []
305
+ for elem in doc.elements:
306
+ _flatten_elements(elem, result)
307
+ # Scripts and styles that are top-level (not nested in elements)
308
+ for elem in doc.scripts:
309
+ if elem.parent is None:
310
+ result.append(elem)
311
+ for elem in doc.styles:
312
+ if elem.parent is None:
313
+ result.append(elem)
314
+ return result