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,69 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Source location utilities for frontend extractors.
4
+ Converts tree-sitter byte offsets to 1-indexed line/column positions.
5
+ """
6
+
7
+ from typing import Dict, Optional
8
+
9
+
10
+ class SourceLocation:
11
+ """Represents a source range with 1-indexed line/column positions."""
12
+
13
+ __slots__ = ("start_line", "start_column", "end_line", "end_column", "start_byte", "end_byte")
14
+
15
+ def __init__(self, start_line, start_column, end_line, end_column, start_byte=None, end_byte=None):
16
+ self.start_line = start_line
17
+ self.start_column = start_column
18
+ self.end_line = end_line
19
+ self.end_column = end_column
20
+ self.start_byte = start_byte
21
+ self.end_byte = end_byte
22
+
23
+ def to_dict(self) -> Dict:
24
+ d = {
25
+ "start_line": self.start_line,
26
+ "start_column": self.start_column,
27
+ "end_line": self.end_line,
28
+ "end_column": self.end_column,
29
+ }
30
+ if self.start_byte is not None:
31
+ d["start_byte"] = self.start_byte
32
+ if self.end_byte is not None:
33
+ d["end_byte"] = self.end_byte
34
+ return d
35
+
36
+ def __repr__(self):
37
+ return f"SourceLocation({self.start_line}:{self.start_column}-{self.end_line}:{self.end_column})"
38
+
39
+
40
+ def node_to_location(node) -> SourceLocation:
41
+ """Convert a tree-sitter node to a SourceLocation with 1-indexed lines."""
42
+ start_line, start_col = node.start_point
43
+ end_line, end_col = node.end_point
44
+ return SourceLocation(
45
+ start_line=start_line + 1,
46
+ start_column=start_col,
47
+ end_line=end_line + 1,
48
+ end_column=end_col,
49
+ start_byte=node.start_byte,
50
+ end_byte=node.end_byte,
51
+ )
52
+
53
+
54
+ def byte_to_line_col(byte_offset: int, source_bytes: bytes) -> tuple:
55
+ """Convert a byte offset to (line, column) with 1-indexed line."""
56
+ line = 1
57
+ col = 0
58
+ for i in range(min(byte_offset, len(source_bytes))):
59
+ if source_bytes[i] == 0x0A: # newline
60
+ line += 1
61
+ col = 0
62
+ else:
63
+ col += 1
64
+ return (line, col)
65
+
66
+
67
+ def extract_range(source_bytes: bytes, start_byte: int, end_byte: int) -> str:
68
+ """Extract exact source text from byte range, handling UTF-8."""
69
+ return source_bytes[start_byte:end_byte].decode("utf-8", errors="replace")
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Frontend indexing configuration.
4
+ Loads defaults and optional overrides from .raggie/frontend_config.json.
5
+ """
6
+
7
+ import json
8
+ from pathlib import Path
9
+ from typing import List, Optional
10
+
11
+
12
+ # Default configuration
13
+ DEFAULT_CONFIG = {
14
+ "enabled_languages": ["html", "css", "javascript", "tsx"],
15
+ "generated_dir_exclusions": ["dist", "build", "node_modules", ".next", ".nuxt", "out"],
16
+ "parse_inline_scripts": True,
17
+ "parse_inline_styles": True,
18
+ "include_text_nodes": False,
19
+ "css_module_resolution": True,
20
+ "framework_detection_overrides": {},
21
+ "generated_css_threshold": 100_000,
22
+ "max_frontend_file_size": 500_000,
23
+ }
24
+
25
+
26
+ class FrontendConfig:
27
+ """Configuration for frontend indexing behavior."""
28
+
29
+ def __init__(self, config_dict: Optional[dict] = None):
30
+ merged = dict(DEFAULT_CONFIG)
31
+ if config_dict:
32
+ merged.update(config_dict)
33
+ self.enabled_languages: List[str] = merged["enabled_languages"]
34
+ self.generated_dir_exclusions: List[str] = merged["generated_dir_exclusions"]
35
+ self.parse_inline_scripts: bool = merged["parse_inline_scripts"]
36
+ self.parse_inline_styles: bool = merged["parse_inline_styles"]
37
+ self.include_text_nodes: bool = merged["include_text_nodes"]
38
+ self.css_module_resolution: bool = merged["css_module_resolution"]
39
+ self.framework_detection_overrides: dict = merged["framework_detection_overrides"]
40
+ self.generated_css_threshold: int = merged["generated_css_threshold"]
41
+ self.max_frontend_file_size: int = merged["max_frontend_file_size"]
42
+
43
+ def is_language_enabled(self, language: str) -> bool:
44
+ return language in self.enabled_languages
45
+
46
+ def is_dir_excluded(self, dir_name: str) -> bool:
47
+ return dir_name in self.generated_dir_exclusions
48
+
49
+
50
+ def load_frontend_config(root_dir) -> FrontendConfig:
51
+ """Load frontend config from .raggie/frontend_config.json, or fall back to defaults.
52
+
53
+ Args:
54
+ root_dir: Project root directory path.
55
+
56
+ Returns:
57
+ FrontendConfig instance.
58
+ """
59
+ root_path = Path(root_dir)
60
+ config_path = root_path / ".raggie" / "frontend_config.json"
61
+
62
+ if config_path.exists():
63
+ try:
64
+ with open(config_path, "r", encoding="utf-8") as f:
65
+ config_dict = json.load(f)
66
+ return FrontendConfig(config_dict)
67
+ except json.JSONDecodeError as e:
68
+ print(f"Warning: Invalid JSON in {config_path}: {e}")
69
+ print("Falling back to default frontend config.")
70
+ return FrontendConfig()
71
+
72
+ return FrontendConfig()
@@ -0,0 +1,347 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Data models for frontend semantic entities.
4
+ Dataclasses representing frontend entities stored in the SQLite index.
5
+ """
6
+
7
+ import json
8
+ import sqlite3
9
+ from typing import List, Dict, Optional
10
+ from dataclasses import dataclass
11
+
12
+ from .models import Location
13
+
14
+
15
+ @dataclass
16
+ class FrontendComponent:
17
+ """Recognized UI component (React function/arrow/class/forwardRef/memo)."""
18
+ id: int
19
+ file_id: int
20
+ name: str
21
+ framework: str = "react"
22
+ source_range: Optional[Location] = None
23
+ is_exported: bool = False
24
+ impl_function_id: Optional[int] = None
25
+ impl_class_id: Optional[int] = None
26
+
27
+ @classmethod
28
+ def from_row(cls, row: sqlite3.Row) -> "FrontendComponent":
29
+ sr = None
30
+ if row["source_range"]:
31
+ sr = Location.from_dict(json.loads(row["source_range"]))
32
+ return cls(
33
+ id=row["id"],
34
+ file_id=row["file_id"],
35
+ name=row["name"],
36
+ framework=row["framework"],
37
+ source_range=sr,
38
+ is_exported=bool(row["is_exported"]),
39
+ impl_function_id=row["impl_function_id"],
40
+ impl_class_id=row["impl_class_id"],
41
+ )
42
+
43
+
44
+ @dataclass
45
+ class MarkupElement:
46
+ """Element in markup tree (HTML, JSX, fragment, template, expression, text)."""
47
+ id: int
48
+ file_id: int
49
+ tag_name: str
50
+ element_type: str
51
+ component_id: Optional[int] = None
52
+ parent_element_id: Optional[int] = None
53
+ source_range: Optional[Location] = None
54
+ element_id_attr: Optional[str] = None
55
+ static_classes: Optional[List[str]] = None
56
+ attributes: Optional[Dict] = None
57
+ is_conditional: bool = False
58
+ is_repeated: bool = False
59
+ conditional_expr: Optional[str] = None
60
+ repeated_expr: Optional[str] = None
61
+
62
+ @classmethod
63
+ def from_row(cls, row: sqlite3.Row) -> "MarkupElement":
64
+ sr = None
65
+ if row["source_range"]:
66
+ sr = Location.from_dict(json.loads(row["source_range"]))
67
+ classes = None
68
+ if row["static_classes"]:
69
+ classes = json.loads(row["static_classes"])
70
+ attrs = None
71
+ if row["attributes"]:
72
+ attrs = json.loads(row["attributes"])
73
+ return cls(
74
+ id=row["id"],
75
+ file_id=row["file_id"],
76
+ tag_name=row["tag_name"],
77
+ element_type=row["element_type"],
78
+ component_id=row["component_id"],
79
+ parent_element_id=row["parent_element_id"],
80
+ source_range=sr,
81
+ element_id_attr=row["element_id_attr"],
82
+ static_classes=classes,
83
+ attributes=attrs,
84
+ is_conditional=bool(row["is_conditional"]),
85
+ is_repeated=bool(row["is_repeated"]),
86
+ conditional_expr=row["conditional_expr"],
87
+ repeated_expr=row["repeated_expr"],
88
+ )
89
+
90
+
91
+ @dataclass
92
+ class StyleSelector:
93
+ """CSS selector definition."""
94
+ id: int
95
+ file_id: int
96
+ selector_text: str
97
+ selector_type: str
98
+ normalized_selector: Optional[str] = None
99
+ source_range: Optional[Location] = None
100
+ component_id: Optional[int] = None
101
+ is_scoped: bool = False
102
+
103
+ @classmethod
104
+ def from_row(cls, row: sqlite3.Row) -> "StyleSelector":
105
+ sr = None
106
+ if row["source_range"]:
107
+ sr = Location.from_dict(json.loads(row["source_range"]))
108
+ return cls(
109
+ id=row["id"],
110
+ file_id=row["file_id"],
111
+ selector_text=row["selector_text"],
112
+ selector_type=row["selector_type"],
113
+ normalized_selector=row["normalized_selector"],
114
+ source_range=sr,
115
+ component_id=row["component_id"],
116
+ is_scoped=bool(row["is_scoped"]),
117
+ )
118
+
119
+
120
+ @dataclass
121
+ class StyleCustomProperty:
122
+ """CSS custom property definition (--name: value)."""
123
+ id: int
124
+ file_id: int
125
+ name: str
126
+ value: Optional[str] = None
127
+ source_range: Optional[Location] = None
128
+ scope_selector: Optional[str] = None
129
+
130
+ @classmethod
131
+ def from_row(cls, row: sqlite3.Row) -> "StyleCustomProperty":
132
+ sr = None
133
+ if row["source_range"]:
134
+ sr = Location.from_dict(json.loads(row["source_range"]))
135
+ return cls(
136
+ id=row["id"],
137
+ file_id=row["file_id"],
138
+ name=row["name"],
139
+ value=row["value"],
140
+ source_range=sr,
141
+ scope_selector=row["scope_selector"],
142
+ )
143
+
144
+
145
+ @dataclass
146
+ class StyleCustomPropertyUsage:
147
+ """CSS custom property usage (var(--name))."""
148
+ id: int
149
+ file_id: int
150
+ property_name: str
151
+ source_range: Optional[Location] = None
152
+ selector_id: Optional[int] = None
153
+ resolved_property_id: Optional[int] = None
154
+
155
+ @classmethod
156
+ def from_row(cls, row: sqlite3.Row) -> "StyleCustomPropertyUsage":
157
+ sr = None
158
+ if row["source_range"]:
159
+ sr = Location.from_dict(json.loads(row["source_range"]))
160
+ return cls(
161
+ id=row["id"],
162
+ file_id=row["file_id"],
163
+ property_name=row["property_name"],
164
+ source_range=sr,
165
+ selector_id=row["selector_id"],
166
+ resolved_property_id=row["resolved_property_id"],
167
+ )
168
+
169
+
170
+ @dataclass
171
+ class StyleKeyframe:
172
+ """Keyframe definition (@keyframes name)."""
173
+ id: int
174
+ file_id: int
175
+ name: str
176
+ source_range: Optional[Location] = None
177
+
178
+ @classmethod
179
+ def from_row(cls, row: sqlite3.Row) -> "StyleKeyframe":
180
+ sr = None
181
+ if row["source_range"]:
182
+ sr = Location.from_dict(json.loads(row["source_range"]))
183
+ return cls(
184
+ id=row["id"],
185
+ file_id=row["file_id"],
186
+ name=row["name"],
187
+ source_range=sr,
188
+ )
189
+
190
+
191
+ @dataclass
192
+ class StyleImport:
193
+ """CSS/stylesheet import (@import, <link rel="stylesheet">, CSS module import)."""
194
+ id: int
195
+ file_id: int
196
+ import_path: str
197
+ is_external: bool = False
198
+ resolved_file_id: Optional[int] = None
199
+ source_range: Optional[Location] = None
200
+
201
+ @classmethod
202
+ def from_row(cls, row: sqlite3.Row) -> "StyleImport":
203
+ sr = None
204
+ if row["source_range"]:
205
+ sr = Location.from_dict(json.loads(row["source_range"]))
206
+ return cls(
207
+ id=row["id"],
208
+ file_id=row["file_id"],
209
+ import_path=row["import_path"],
210
+ is_external=bool(row["is_external"]),
211
+ resolved_file_id=row["resolved_file_id"],
212
+ source_range=sr,
213
+ )
214
+
215
+
216
+ @dataclass
217
+ class FrontendEvent:
218
+ """Event handler binding (onclick, onClick, etc.)."""
219
+ id: int
220
+ file_id: int
221
+ event_name: str
222
+ handler_type: str
223
+ element_id: Optional[int] = None
224
+ handler_expression: Optional[str] = None
225
+ handler_symbol_id: Optional[int] = None
226
+ resolution_status: str = "unresolved"
227
+ source_range: Optional[Location] = None
228
+
229
+ @classmethod
230
+ def from_row(cls, row: sqlite3.Row) -> "FrontendEvent":
231
+ sr = None
232
+ if row["source_range"]:
233
+ sr = Location.from_dict(json.loads(row["source_range"]))
234
+ return cls(
235
+ id=row["id"],
236
+ file_id=row["file_id"],
237
+ event_name=row["event_name"],
238
+ handler_type=row["handler_type"],
239
+ element_id=row["element_id"],
240
+ handler_expression=row["handler_expression"],
241
+ handler_symbol_id=row["handler_symbol_id"],
242
+ resolution_status=row["resolution_status"],
243
+ source_range=sr,
244
+ )
245
+
246
+
247
+ @dataclass
248
+ class FrontendBinding:
249
+ """Property/state binding (disabled={x}, className={cn(...)}, {title}, etc.)."""
250
+ id: int
251
+ file_id: int
252
+ binding_type: str
253
+ element_id: Optional[int] = None
254
+ binding_name: Optional[str] = None
255
+ binding_expression: Optional[str] = None
256
+ resolution_status: str = "unresolved"
257
+ source_range: Optional[Location] = None
258
+
259
+ @classmethod
260
+ def from_row(cls, row: sqlite3.Row) -> "FrontendBinding":
261
+ sr = None
262
+ if row["source_range"]:
263
+ sr = Location.from_dict(json.loads(row["source_range"]))
264
+ return cls(
265
+ id=row["id"],
266
+ file_id=row["file_id"],
267
+ binding_type=row["binding_type"],
268
+ element_id=row["element_id"],
269
+ binding_name=row["binding_name"],
270
+ binding_expression=row["binding_expression"],
271
+ resolution_status=row["resolution_status"],
272
+ source_range=sr,
273
+ )
274
+
275
+
276
+ @dataclass
277
+ class RenderRelationship:
278
+ """Component render graph edge (parent renders child)."""
279
+ id: int
280
+ parent_component_id: int
281
+ render_type: str
282
+ child_component_id: Optional[int] = None
283
+ child_component_name: Optional[str] = None
284
+ child_element_id: Optional[int] = None
285
+ controlling_expr: Optional[str] = None
286
+
287
+ @classmethod
288
+ def from_row(cls, row: sqlite3.Row) -> "RenderRelationship":
289
+ return cls(
290
+ id=row["id"],
291
+ parent_component_id=row["parent_component_id"],
292
+ child_component_id=row["child_component_id"],
293
+ child_component_name=row["child_component_name"],
294
+ child_element_id=row["child_element_id"],
295
+ render_type=row["render_type"],
296
+ controlling_expr=row["controlling_expr"],
297
+ )
298
+
299
+
300
+ @dataclass
301
+ class FrontendDiagnostic:
302
+ """Extraction diagnostic for a frontend file."""
303
+ id: int
304
+ file_id: int
305
+ diagnostic_type: str
306
+ severity: str
307
+ message: Optional[str] = None
308
+ source_range: Optional[Location] = None
309
+
310
+ @classmethod
311
+ def from_row(cls, row: sqlite3.Row) -> "FrontendDiagnostic":
312
+ sr = None
313
+ if row["source_range"]:
314
+ sr = Location.from_dict(json.loads(row["source_range"]))
315
+ return cls(
316
+ id=row["id"],
317
+ file_id=row["file_id"],
318
+ diagnostic_type=row["diagnostic_type"],
319
+ severity=row["severity"],
320
+ message=row["message"],
321
+ source_range=sr,
322
+ )
323
+
324
+
325
+ @dataclass
326
+ class StyleSelectorMatch:
327
+ """Pre-computed selector→element match for blast radius analysis."""
328
+ id: int
329
+ selector_id: int
330
+ element_id: int
331
+ match_type: str
332
+ confidence: str = "high"
333
+ source_range: Optional[Location] = None
334
+
335
+ @classmethod
336
+ def from_row(cls, row: sqlite3.Row) -> "StyleSelectorMatch":
337
+ sr = None
338
+ if row["source_range"]:
339
+ sr = Location.from_dict(json.loads(row["source_range"]))
340
+ return cls(
341
+ id=row["id"],
342
+ selector_id=row["selector_id"],
343
+ element_id=row["element_id"],
344
+ match_type=row["match_type"],
345
+ confidence=row["confidence"],
346
+ source_range=sr,
347
+ )