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,226 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Lightweight CSS selector matching for runtime element resolution.
4
+
5
+ This is NOT a full CSS engine. It handles the common selector types that
6
+ appear in real-world stylesheets:
7
+
8
+ - Type selectors: ``div``, ``button``, ``span``
9
+ - Class selectors: ``.btn``, ``.container.primary``
10
+ - ID selectors: ``#submit-btn``
11
+ - Compound selectors: ``div.btn``, ``button#save.active``
12
+ - Descendant combinators: ``.parent .child``
13
+ - Child combinators: ``.parent > .child``
14
+
15
+ Pseudo-classes, pseudo-elements, attribute selectors, and sibling
16
+ combinators are not supported and will cause the matcher to return
17
+ ``False`` (safe fallback — the caller simply gets no match from this
18
+ strategy).
19
+ """
20
+
21
+ import re
22
+ from typing import List, Optional, Tuple
23
+
24
+
25
+ def _parse_compound_selector(sel: str) -> Optional[dict]:
26
+ """Parse a single compound selector (no combinators).
27
+
28
+ Returns a dict with keys: ``tag`` (str|None), ``id`` (str|None),
29
+ ``classes`` (list[str]), or ``None`` if the selector is unsupported.
30
+ """
31
+ sel = sel.strip()
32
+ if not sel:
33
+ return None
34
+
35
+ tag = None
36
+ elem_id = None
37
+ classes: List[str] = []
38
+
39
+ # Tokenize: tag at start, then .class / #id
40
+ pos = 0
41
+
42
+ # Optional tag at the beginning
43
+ m = re.match(r'^[a-zA-Z][a-zA-Z0-9_-]*', sel)
44
+ if m:
45
+ tag = m.group(0).lower()
46
+ pos = m.end()
47
+
48
+ # Parse .class and #id tokens
49
+ while pos < len(sel):
50
+ if sel[pos] == '.':
51
+ m = re.match(r'\.([a-zA-Z_][a-zA-Z0-9_-]*)', sel[pos:])
52
+ if not m:
53
+ return None # malformed
54
+ classes.append(m.group(1))
55
+ pos += m.end()
56
+ elif sel[pos] == '#':
57
+ m = re.match(r'#([a-zA-Z_][a-zA-Z0-9_-]*)', sel[pos:])
58
+ if not m:
59
+ return None
60
+ elem_id = m.group(1)
61
+ pos += m.end()
62
+ elif sel[pos] == '*':
63
+ # Universal selector — matches any tag
64
+ tag = '*'
65
+ pos += 1
66
+ else:
67
+ # Unsupported syntax (pseudo, attribute, etc.)
68
+ return None
69
+
70
+ return {"tag": tag, "id": elem_id, "classes": classes}
71
+
72
+
73
+ def _split_by_combinator(selector: str) -> Optional[List[Tuple[str, str]]]:
74
+ """Split a selector into compound parts with combinators.
75
+
76
+ Returns a list of (combinator, compound) pairs. The first element
77
+ has combinator ``""`` (empty string). Returns ``None`` if the
78
+ selector contains unsupported combinators.
79
+ """
80
+ # Normalize whitespace
81
+ selector = selector.strip()
82
+ if not selector:
83
+ return None
84
+
85
+ # Split on > or whitespace, keeping the combinator
86
+ # We tokenize: compound, then optional combinator (> or space), then compound, ...
87
+ parts: List[Tuple[str, str]] = []
88
+ current = ""
89
+ i = 0
90
+ while i < len(selector):
91
+ ch = selector[i]
92
+ if ch == '>':
93
+ if current.strip():
94
+ parts.append(("", current.strip()))
95
+ current = ""
96
+ parts.append((">", ""))
97
+ i += 1
98
+ elif ch == '~' or ch == '+':
99
+ # Sibling combinators — unsupported
100
+ return None
101
+ elif ch.isspace():
102
+ if current.strip():
103
+ parts.append(("", current.strip()))
104
+ current = ""
105
+ # Skip whitespace, but mark a descendant combinator unless
106
+ # the next non-space char is '>'
107
+ j = i
108
+ while j < len(selector) and selector[j].isspace():
109
+ j += 1
110
+ if j < len(selector) and selector[j] == '>':
111
+ # The > will be handled in the next iteration
112
+ i = j
113
+ else:
114
+ # Descendant combinator (whitespace)
115
+ if parts and parts[-1][0] != ">":
116
+ parts.append((" ", ""))
117
+ i = j
118
+ else:
119
+ current += ch
120
+ i += 1
121
+
122
+ if current.strip():
123
+ parts.append(("", current.strip()))
124
+
125
+ # Rebuild into (combinator, compound) pairs
126
+ result: List[Tuple[str, str]] = []
127
+ pending_combinator = ""
128
+ for comb, compound in parts:
129
+ if comb == ">" or comb == " ":
130
+ pending_combinator = comb
131
+ elif compound:
132
+ result.append((pending_combinator, compound))
133
+ pending_combinator = ""
134
+
135
+ if not result:
136
+ return None
137
+
138
+ # First entry should have empty combinator
139
+ result[0] = ("", result[0][1])
140
+ return result
141
+
142
+
143
+ def _compound_matches(compound: dict, tag: str, classes: List[str],
144
+ elem_id: Optional[str]) -> bool:
145
+ """Check if a parsed compound selector matches an element."""
146
+ # Tag check
147
+ if compound["tag"] is not None and compound["tag"] != "*":
148
+ if tag.lower() != compound["tag"]:
149
+ return False
150
+
151
+ # ID check
152
+ if compound["id"] is not None:
153
+ if elem_id != compound["id"]:
154
+ return False
155
+
156
+ # Class check — all classes in the selector must be present on the element
157
+ if compound["classes"]:
158
+ elem_class_set = set(classes)
159
+ for c in compound["classes"]:
160
+ if c not in elem_class_set:
161
+ return False
162
+
163
+ return True
164
+
165
+
166
+ def selector_matches_element(selector: str, tag: str, classes: List[str],
167
+ elem_id: Optional[str] = None,
168
+ attributes: Optional[dict] = None) -> bool:
169
+ """Check if a CSS selector matches an element.
170
+
171
+ Args:
172
+ selector: CSS selector text (e.g. ``.btn``, ``div#main``, ``.parent > .child``).
173
+ tag: Element tag name.
174
+ classes: List of class names on the element.
175
+ elem_id: Element's id attribute value, if any.
176
+ attributes: Element's attributes dict (unused currently, reserved for future).
177
+
178
+ Returns:
179
+ True if the selector matches the element, False otherwise.
180
+ Unsupported selector syntax always returns False.
181
+ """
182
+ parts = _split_by_combinator(selector)
183
+ if parts is None:
184
+ return False
185
+
186
+ # Parse all compound selectors
187
+ parsed = []
188
+ for comb, compound_text in parts:
189
+ p = _parse_compound_selector(compound_text)
190
+ if p is None:
191
+ return False
192
+ parsed.append((comb, p))
193
+
194
+ if not parsed:
195
+ return False
196
+
197
+ # Single compound selector — direct match
198
+ if len(parsed) == 1:
199
+ return _compound_matches(parsed[0][1], tag, classes, elem_id)
200
+
201
+ # Multi-part selector with combinators — we only check the final compound
202
+ # against the element (we don't have the full DOM tree here).
203
+ # For descendant/child combinators, we check if the last compound matches.
204
+ # Full ancestry matching is done at the caller level where DOM ancestry is available.
205
+ last_compound = parsed[-1][1]
206
+ return _compound_matches(last_compound, tag, classes, elem_id)
207
+
208
+
209
+ def selectors_matching_element(selectors: List[str], tag: str,
210
+ classes: List[str],
211
+ elem_id: Optional[str] = None) -> List[str]:
212
+ """Return only the selectors that match the given element.
213
+
214
+ Args:
215
+ selectors: List of CSS selector strings.
216
+ tag: Element tag name.
217
+ classes: List of class names on the element.
218
+ elem_id: Element's id attribute value, if any.
219
+
220
+ Returns:
221
+ List of matching selector strings (subset of input).
222
+ """
223
+ return [
224
+ s for s in selectors
225
+ if selector_matches_element(s, tag, classes, elem_id)
226
+ ]