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.
- Agent/__init__.py +0 -0
- Agent/agent.py +891 -0
- Agent/chat_history_db.py +1500 -0
- Agent/command.py +49 -0
- Agent/config.py +46 -0
- Agent/effort_levels.py +33 -0
- Agent/git_manager.py +727 -0
- Agent/tools.py +35 -0
- Commands/__init__.py +18 -0
- Commands/effort.py +42 -0
- Commands/global_todo.py +23 -0
- Commands/help.py +22 -0
- Commands/reasoning.py +24 -0
- Commands/redo.py +11 -0
- Commands/reindex.py +27 -0
- Commands/shell.py +28 -0
- Commands/stream.py +24 -0
- Commands/undo.py +13 -0
- Commands/unlimited_effort.py +8 -0
- Commands/window_size.py +29 -0
- RAG/__init__.py +0 -0
- RAG/document.py +119 -0
- RAG/find.py +408 -0
- RAG/graph.py +231 -0
- Tools/GetFileCodeStructure.py +43 -0
- Tools/GetSymbolSourceCode.py +27 -0
- Tools/__init__.py +39 -0
- Tools/ask_user.py +102 -0
- Tools/dispatch_subagent.py +215 -0
- Tools/document.py +35 -0
- Tools/edit_symbol.py +250 -0
- Tools/fuzzy_search.py +119 -0
- Tools/list_dir.py +51 -0
- Tools/read.py +49 -0
- Tools/read_image.py +75 -0
- Tools/remove.py +75 -0
- Tools/replace.py +305 -0
- Tools/search.py +41 -0
- Tools/shell.py +149 -0
- Tools/shell_kill.py +87 -0
- Tools/temp_background_service.py +113 -0
- Tools/todo_list.py +481 -0
- Tools/utils.py +116 -0
- Tools/view_changes.py +179 -0
- Tools/walk_call_tree.py +30 -0
- Tools/web_fetch.py +175 -0
- Tools/web_search.py +69 -0
- Tools/write.py +48 -0
- cli.py +111 -0
- config/__init__.py +0 -0
- config/coder_system_prompt.md +119 -0
- config/roles.json +43 -0
- config/tools.json +709 -0
- indexing/__init__.py +0 -0
- indexing/cli.py +128 -0
- indexing/code_index_sdk.py +832 -0
- indexing/code_indexer.py +1763 -0
- indexing/db_schema.py +396 -0
- indexing/export_to_json.py +346 -0
- indexing/extractors.py +189 -0
- indexing/file_utils.py +97 -0
- indexing/frontend/__init__.py +0 -0
- indexing/frontend/css_extractor.py +195 -0
- indexing/frontend/css_parser.py +387 -0
- indexing/frontend/css_selector_utils.py +226 -0
- indexing/frontend/edit_safety.py +573 -0
- indexing/frontend/graph.py +838 -0
- indexing/frontend/html_extractor.py +496 -0
- indexing/frontend/html_parser.py +314 -0
- indexing/frontend/jsx_extractor.py +1204 -0
- indexing/frontend/location_lookup.py +247 -0
- indexing/frontend/resolver.py +485 -0
- indexing/frontend/runtime_resolver.py +862 -0
- indexing/frontend/semantic_output.py +705 -0
- indexing/frontend/source_location.py +69 -0
- indexing/frontend_config.py +72 -0
- indexing/frontend_models.py +347 -0
- indexing/language_config.py +360 -0
- indexing/models.py +284 -0
- indexing/node_utils.py +1112 -0
- indexing/parse_worker.py +1082 -0
- indexing/queries.py +1542 -0
- indexing/sdk_examples.py +426 -0
- interactive.py +248 -0
- raggie.py +673 -0
- raggiecode-0.2.1.dist-info/METADATA +944 -0
- raggiecode-0.2.1.dist-info/RECORD +93 -0
- raggiecode-0.2.1.dist-info/WHEEL +5 -0
- raggiecode-0.2.1.dist-info/entry_points.txt +2 -0
- raggiecode-0.2.1.dist-info/top_level.txt +10 -0
- skills/__init__.py +3 -0
- skills/manager.py +114 -0
- 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
|
+
]
|