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,346 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Export SQLite code index to JSON format.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import sqlite3
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def export_to_json(db_path, output_file):
|
|
12
|
+
"""Export SQLite database to JSON format."""
|
|
13
|
+
print(f"Reading database from {db_path}...")
|
|
14
|
+
|
|
15
|
+
conn = sqlite3.connect(db_path)
|
|
16
|
+
conn.row_factory = sqlite3.Row
|
|
17
|
+
|
|
18
|
+
# Initialize JSON structure
|
|
19
|
+
json_index = {
|
|
20
|
+
"files": {},
|
|
21
|
+
"total_functions": 0,
|
|
22
|
+
"total_classes": 0,
|
|
23
|
+
"total_variables": 0,
|
|
24
|
+
"total_methods": 0,
|
|
25
|
+
"total_type_defs": 0,
|
|
26
|
+
"total_structs": 0,
|
|
27
|
+
"total_interfaces": 0
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
cursor = conn.cursor()
|
|
31
|
+
|
|
32
|
+
# Get all files
|
|
33
|
+
cursor.execute("SELECT * FROM files ORDER BY id")
|
|
34
|
+
files = cursor.fetchall()
|
|
35
|
+
|
|
36
|
+
print(f"Exporting {len(files)} files...")
|
|
37
|
+
|
|
38
|
+
for file_row in files:
|
|
39
|
+
file_id = file_row['id']
|
|
40
|
+
relative_path = file_row['path']
|
|
41
|
+
|
|
42
|
+
file_info = {
|
|
43
|
+
"path": relative_path,
|
|
44
|
+
"absolute_path": file_row['absolute_path'],
|
|
45
|
+
"language": file_row['language'],
|
|
46
|
+
"functions": [],
|
|
47
|
+
"classes": [],
|
|
48
|
+
"variables": [],
|
|
49
|
+
"type_aliases": [],
|
|
50
|
+
"structs": [],
|
|
51
|
+
"interfaces": []
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Get top-level functions (no parent)
|
|
55
|
+
cursor.execute(
|
|
56
|
+
"""SELECT * FROM functions
|
|
57
|
+
WHERE file_id = ? AND parent_id IS NULL
|
|
58
|
+
ORDER BY id""",
|
|
59
|
+
(file_id,)
|
|
60
|
+
)
|
|
61
|
+
for func_row in cursor.fetchall():
|
|
62
|
+
func_info = {
|
|
63
|
+
"type": func_row['type'],
|
|
64
|
+
"name": func_row['name'],
|
|
65
|
+
"location": json.loads(func_row['location']),
|
|
66
|
+
"parameters": json.loads(func_row['parameters']),
|
|
67
|
+
"return_type": func_row['return_type'],
|
|
68
|
+
"docstring": func_row['docstring']
|
|
69
|
+
}
|
|
70
|
+
if func_row['receiver']:
|
|
71
|
+
func_info['receiver'] = func_row['receiver']
|
|
72
|
+
file_info["functions"].append(func_info)
|
|
73
|
+
json_index["total_functions"] += 1
|
|
74
|
+
|
|
75
|
+
# Get classes (top-level only)
|
|
76
|
+
cursor.execute(
|
|
77
|
+
"""SELECT * FROM classes
|
|
78
|
+
WHERE file_id = ? AND parent_id IS NULL
|
|
79
|
+
ORDER BY id""",
|
|
80
|
+
(file_id,)
|
|
81
|
+
)
|
|
82
|
+
classes_map = {} # Map class_id to class info for method lookup
|
|
83
|
+
|
|
84
|
+
for class_row in cursor.fetchall():
|
|
85
|
+
class_id = class_row['id']
|
|
86
|
+
class_info = {
|
|
87
|
+
"type": "class",
|
|
88
|
+
"name": class_row['name'],
|
|
89
|
+
"location": json.loads(class_row['location']),
|
|
90
|
+
"base_classes": json.loads(class_row['base_classes']),
|
|
91
|
+
"docstring": class_row['docstring'],
|
|
92
|
+
"methods": [],
|
|
93
|
+
"nested_classes": [],
|
|
94
|
+
"variables": []
|
|
95
|
+
}
|
|
96
|
+
classes_map[class_id] = class_info
|
|
97
|
+
file_info["classes"].append(class_info)
|
|
98
|
+
json_index["total_classes"] += 1
|
|
99
|
+
|
|
100
|
+
# Get nested classes
|
|
101
|
+
cursor.execute(
|
|
102
|
+
"""SELECT * FROM classes
|
|
103
|
+
WHERE file_id = ? AND parent_id IS NOT NULL
|
|
104
|
+
ORDER BY id""",
|
|
105
|
+
(file_id,)
|
|
106
|
+
)
|
|
107
|
+
for class_row in cursor.fetchall():
|
|
108
|
+
class_id = class_row['id']
|
|
109
|
+
parent_id = class_row['parent_id']
|
|
110
|
+
|
|
111
|
+
class_info = {
|
|
112
|
+
"type": "class",
|
|
113
|
+
"name": class_row['name'],
|
|
114
|
+
"location": json.loads(class_row['location']),
|
|
115
|
+
"base_classes": json.loads(class_row['base_classes']),
|
|
116
|
+
"docstring": class_row['docstring'],
|
|
117
|
+
"methods": [],
|
|
118
|
+
"nested_classes": [],
|
|
119
|
+
"variables": []
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Add to parent's nested_classes
|
|
123
|
+
if parent_id in classes_map:
|
|
124
|
+
classes_map[parent_id]["nested_classes"].append(class_info)
|
|
125
|
+
classes_map[class_id] = class_info
|
|
126
|
+
json_index["total_classes"] += 1
|
|
127
|
+
|
|
128
|
+
# Get methods (functions with parent)
|
|
129
|
+
cursor.execute(
|
|
130
|
+
"""SELECT * FROM functions
|
|
131
|
+
WHERE file_id = ? AND parent_id IS NOT NULL
|
|
132
|
+
ORDER BY id""",
|
|
133
|
+
(file_id,)
|
|
134
|
+
)
|
|
135
|
+
for func_row in cursor.fetchall():
|
|
136
|
+
parent_id = func_row['parent_id']
|
|
137
|
+
parent_type = func_row['parent_type']
|
|
138
|
+
|
|
139
|
+
method_info = {
|
|
140
|
+
"type": func_row['type'],
|
|
141
|
+
"name": func_row['name'],
|
|
142
|
+
"location": json.loads(func_row['location']),
|
|
143
|
+
"parameters": json.loads(func_row['parameters']),
|
|
144
|
+
"return_type": func_row['return_type'],
|
|
145
|
+
"docstring": func_row['docstring']
|
|
146
|
+
}
|
|
147
|
+
if func_row['receiver']:
|
|
148
|
+
method_info['receiver'] = func_row['receiver']
|
|
149
|
+
|
|
150
|
+
# Add to parent class's methods
|
|
151
|
+
if parent_type == 'class' and parent_id in classes_map:
|
|
152
|
+
classes_map[parent_id]["methods"].append(method_info)
|
|
153
|
+
json_index["total_methods"] += 1
|
|
154
|
+
|
|
155
|
+
# Get top-level variables (no parent)
|
|
156
|
+
cursor.execute(
|
|
157
|
+
"""SELECT * FROM variables
|
|
158
|
+
WHERE file_id = ? AND parent_id IS NULL
|
|
159
|
+
ORDER BY id""",
|
|
160
|
+
(file_id,)
|
|
161
|
+
)
|
|
162
|
+
for var_row in cursor.fetchall():
|
|
163
|
+
var_info = {
|
|
164
|
+
"type": var_row['type'],
|
|
165
|
+
"name": var_row['name'],
|
|
166
|
+
"location": json.loads(var_row['location'])
|
|
167
|
+
}
|
|
168
|
+
if var_row['field_type']:
|
|
169
|
+
var_info['field_type'] = var_row['field_type']
|
|
170
|
+
file_info["variables"].append(var_info)
|
|
171
|
+
json_index["total_variables"] += 1
|
|
172
|
+
|
|
173
|
+
# Get class attributes (variables with parent)
|
|
174
|
+
cursor.execute(
|
|
175
|
+
"""SELECT * FROM variables
|
|
176
|
+
WHERE file_id = ? AND parent_id IS NOT NULL
|
|
177
|
+
ORDER BY id""",
|
|
178
|
+
(file_id,)
|
|
179
|
+
)
|
|
180
|
+
for var_row in cursor.fetchall():
|
|
181
|
+
parent_id = var_row['parent_id']
|
|
182
|
+
parent_type = var_row['parent_type']
|
|
183
|
+
|
|
184
|
+
var_info = {
|
|
185
|
+
"type": var_row['type'],
|
|
186
|
+
"name": var_row['name'],
|
|
187
|
+
"location": json.loads(var_row['location'])
|
|
188
|
+
}
|
|
189
|
+
if var_row['field_type']:
|
|
190
|
+
var_info['field_type'] = var_row['field_type']
|
|
191
|
+
|
|
192
|
+
# Add to parent class's variables
|
|
193
|
+
if parent_type == 'class' and parent_id in classes_map:
|
|
194
|
+
classes_map[parent_id]["variables"].append(var_info)
|
|
195
|
+
json_index["total_variables"] += 1
|
|
196
|
+
|
|
197
|
+
# Get type aliases
|
|
198
|
+
cursor.execute(
|
|
199
|
+
"SELECT * FROM type_aliases WHERE file_id = ? ORDER BY id",
|
|
200
|
+
(file_id,)
|
|
201
|
+
)
|
|
202
|
+
for type_row in cursor.fetchall():
|
|
203
|
+
type_info = {
|
|
204
|
+
"type": "type_alias",
|
|
205
|
+
"name": type_row['name'],
|
|
206
|
+
"location": json.loads(type_row['location']),
|
|
207
|
+
"type_definition": type_row['type_definition']
|
|
208
|
+
}
|
|
209
|
+
file_info["type_aliases"].append(type_info)
|
|
210
|
+
json_index["total_type_defs"] += 1
|
|
211
|
+
|
|
212
|
+
# Get structs
|
|
213
|
+
cursor.execute(
|
|
214
|
+
"SELECT * FROM structs WHERE file_id = ? ORDER BY id",
|
|
215
|
+
(file_id,)
|
|
216
|
+
)
|
|
217
|
+
for struct_row in cursor.fetchall():
|
|
218
|
+
struct_info = {
|
|
219
|
+
"type": "struct",
|
|
220
|
+
"name": struct_row['name'],
|
|
221
|
+
"location": json.loads(struct_row['location']),
|
|
222
|
+
"methods": [],
|
|
223
|
+
"fields": []
|
|
224
|
+
}
|
|
225
|
+
file_info["structs"].append(struct_info)
|
|
226
|
+
json_index["total_structs"] += 1
|
|
227
|
+
|
|
228
|
+
# Get interfaces
|
|
229
|
+
cursor.execute(
|
|
230
|
+
"SELECT * FROM interfaces WHERE file_id = ? ORDER BY id",
|
|
231
|
+
(file_id,)
|
|
232
|
+
)
|
|
233
|
+
for interface_row in cursor.fetchall():
|
|
234
|
+
interface_info = {
|
|
235
|
+
"type": "interface",
|
|
236
|
+
"name": interface_row['name'],
|
|
237
|
+
"location": json.loads(interface_row['location']),
|
|
238
|
+
"methods": []
|
|
239
|
+
}
|
|
240
|
+
file_info["interfaces"].append(interface_info)
|
|
241
|
+
json_index["total_interfaces"] += 1
|
|
242
|
+
|
|
243
|
+
json_index["files"][relative_path] = file_info
|
|
244
|
+
|
|
245
|
+
# Export frontend tables
|
|
246
|
+
_export_frontend_tables(conn, json_index)
|
|
247
|
+
|
|
248
|
+
conn.close()
|
|
249
|
+
|
|
250
|
+
# Write to JSON file
|
|
251
|
+
print(f"Writing JSON to {output_file}...")
|
|
252
|
+
with open(output_file, 'w', encoding='utf-8') as f:
|
|
253
|
+
json.dump(json_index, f, indent=2)
|
|
254
|
+
|
|
255
|
+
print(f"\nExport complete!")
|
|
256
|
+
print(f"JSON saved to {output_file}")
|
|
257
|
+
|
|
258
|
+
# Print summary
|
|
259
|
+
print("\n--- Export Summary ---")
|
|
260
|
+
print(f"Total files: {len(json_index['files'])}")
|
|
261
|
+
print(f"Total functions: {json_index['total_functions']}")
|
|
262
|
+
print(f"Total methods: {json_index['total_methods']}")
|
|
263
|
+
print(f"Total classes: {json_index['total_classes']}")
|
|
264
|
+
print(f"Total structs: {json_index['total_structs']}")
|
|
265
|
+
print(f"Total interfaces: {json_index['total_interfaces']}")
|
|
266
|
+
print(f"Total variables: {json_index['total_variables']}")
|
|
267
|
+
print(f"Total type aliases: {json_index['total_type_defs']}")
|
|
268
|
+
|
|
269
|
+
# Frontend summary
|
|
270
|
+
frontend_keys = ["frontend_components", "markup_elements", "style_selectors",
|
|
271
|
+
"frontend_events", "frontend_bindings", "render_relationships",
|
|
272
|
+
"frontend_diagnostics"]
|
|
273
|
+
has_frontend = any(k in json_index and json_index[k] for k in frontend_keys)
|
|
274
|
+
if has_frontend:
|
|
275
|
+
print("\n--- Frontend Summary ---")
|
|
276
|
+
for k in frontend_keys:
|
|
277
|
+
if k in json_index:
|
|
278
|
+
print(f" {k}: {len(json_index[k])}")
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _export_frontend_tables(conn, json_index):
|
|
282
|
+
"""Export frontend semantic tables to the JSON index."""
|
|
283
|
+
cursor = conn.cursor()
|
|
284
|
+
|
|
285
|
+
frontend_tables = [
|
|
286
|
+
("frontend_components", "frontend_components"),
|
|
287
|
+
("markup_elements", "markup_elements"),
|
|
288
|
+
("style_selectors", "style_selectors"),
|
|
289
|
+
("style_custom_properties", "style_custom_properties"),
|
|
290
|
+
("style_custom_property_usages", "style_custom_property_usages"),
|
|
291
|
+
("style_keyframes", "style_keyframes"),
|
|
292
|
+
("style_imports", "style_imports"),
|
|
293
|
+
("style_selector_matches", "style_selector_matches"),
|
|
294
|
+
("frontend_events", "frontend_events"),
|
|
295
|
+
("frontend_bindings", "frontend_bindings"),
|
|
296
|
+
("render_relationships", "render_relationships"),
|
|
297
|
+
("frontend_diagnostics", "frontend_diagnostics"),
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
for table_name, key in frontend_tables:
|
|
301
|
+
try:
|
|
302
|
+
cursor.execute(f"SELECT * FROM {table_name} ORDER BY id")
|
|
303
|
+
rows = cursor.fetchall()
|
|
304
|
+
json_index[key] = []
|
|
305
|
+
for row in rows:
|
|
306
|
+
entry = {}
|
|
307
|
+
for col in row.keys():
|
|
308
|
+
val = row[col]
|
|
309
|
+
if val is not None and isinstance(val, str) and val.startswith('{'):
|
|
310
|
+
try:
|
|
311
|
+
val = json.loads(val)
|
|
312
|
+
except (json.JSONDecodeError, TypeError):
|
|
313
|
+
pass
|
|
314
|
+
entry[col] = val
|
|
315
|
+
json_index[key].append(entry)
|
|
316
|
+
except sqlite3.OperationalError:
|
|
317
|
+
pass
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def main():
|
|
321
|
+
"""Main entry point for CLI usage."""
|
|
322
|
+
import sys
|
|
323
|
+
|
|
324
|
+
if len(sys.argv) < 2:
|
|
325
|
+
print("Usage: python export_to_json.py <db_file> [output_json]")
|
|
326
|
+
print("Example: python export_to_json.py code_index.db code_index.json")
|
|
327
|
+
sys.exit(1)
|
|
328
|
+
|
|
329
|
+
db_path = sys.argv[1]
|
|
330
|
+
output_file = sys.argv[2] if len(sys.argv) > 2 else db_path.rsplit('.', 1)[0] + '.json'
|
|
331
|
+
|
|
332
|
+
if not Path(db_path).exists():
|
|
333
|
+
print(f"Error: Database file not found: {db_path}")
|
|
334
|
+
sys.exit(1)
|
|
335
|
+
|
|
336
|
+
try:
|
|
337
|
+
export_to_json(db_path, output_file)
|
|
338
|
+
except Exception as e:
|
|
339
|
+
print(f"Error during export: {e}")
|
|
340
|
+
import traceback
|
|
341
|
+
traceback.print_exc()
|
|
342
|
+
sys.exit(1)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
if __name__ == "__main__":
|
|
346
|
+
main()
|
indexing/extractors.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Node extraction functions for different language constructs.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from indexing.node_utils import (
|
|
6
|
+
get_node_location,
|
|
7
|
+
extract_name,
|
|
8
|
+
extract_node_text,
|
|
9
|
+
extract_parameters,
|
|
10
|
+
extract_return_type,
|
|
11
|
+
is_method,
|
|
12
|
+
extract_base_classes,
|
|
13
|
+
extract_variable_name,
|
|
14
|
+
extract_docstring,
|
|
15
|
+
extract_field_text,
|
|
16
|
+
extract_go_receiver,
|
|
17
|
+
extract_go_type_name,
|
|
18
|
+
count_branches
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def extract_function_info(node, source_code, language, class_node_type):
|
|
23
|
+
"""Extract information about a function definition."""
|
|
24
|
+
name = extract_name(node, source_code, language) or "unknown"
|
|
25
|
+
params = extract_parameters(node, source_code, language)
|
|
26
|
+
return_type = extract_return_type(node, source_code)
|
|
27
|
+
method_flag = is_method(node, language, class_node_type)
|
|
28
|
+
docstring = extract_docstring(node, source_code, language)
|
|
29
|
+
|
|
30
|
+
# Count branches in function body
|
|
31
|
+
branch_count = count_branches(node, language, source_code)
|
|
32
|
+
|
|
33
|
+
# Handle Go method receivers
|
|
34
|
+
receiver = None
|
|
35
|
+
if language == "go":
|
|
36
|
+
receiver = extract_go_receiver(node, source_code)
|
|
37
|
+
if receiver:
|
|
38
|
+
method_flag = True
|
|
39
|
+
|
|
40
|
+
result = {
|
|
41
|
+
"type": "method" if method_flag else "function",
|
|
42
|
+
"name": name,
|
|
43
|
+
"location": get_node_location(node),
|
|
44
|
+
"parameters": params,
|
|
45
|
+
"return_type": return_type,
|
|
46
|
+
"docstring": docstring,
|
|
47
|
+
"branch_count": branch_count
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if receiver:
|
|
51
|
+
result["receiver"] = receiver
|
|
52
|
+
|
|
53
|
+
return result
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def extract_class_info(node, source_code, language):
|
|
57
|
+
"""Extract information about a class definition."""
|
|
58
|
+
name = extract_name(node, source_code, language) or "unknown"
|
|
59
|
+
base_classes = extract_base_classes(node, source_code, language)
|
|
60
|
+
docstring = extract_docstring(node, source_code, language)
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
"type": "class",
|
|
64
|
+
"name": name,
|
|
65
|
+
"location": get_node_location(node),
|
|
66
|
+
"base_classes": base_classes,
|
|
67
|
+
"docstring": docstring,
|
|
68
|
+
"methods": [],
|
|
69
|
+
"nested_classes": [],
|
|
70
|
+
"variables": []
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def extract_variable_info(node, source_code, language):
|
|
75
|
+
"""Extract information about a variable assignment."""
|
|
76
|
+
name, is_attribute = extract_variable_name(node, source_code, language)
|
|
77
|
+
|
|
78
|
+
if not name:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
if is_attribute:
|
|
82
|
+
return {
|
|
83
|
+
"type": "attribute",
|
|
84
|
+
"name": name,
|
|
85
|
+
"location": get_node_location(node)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
"type": "variable",
|
|
90
|
+
"name": name,
|
|
91
|
+
"location": get_node_location(node)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def extract_type_alias_info(node, source_code, language=None):
|
|
96
|
+
"""Extract information about type alias definitions."""
|
|
97
|
+
name = extract_name(node, source_code, language) or "unknown"
|
|
98
|
+
type_def = extract_field_text(node, "type", source_code)
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
"type": "type_alias",
|
|
102
|
+
"name": name,
|
|
103
|
+
"location": get_node_location(node),
|
|
104
|
+
"type_definition": type_def
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def extract_macro_info(node, source_code, language):
|
|
109
|
+
"""Extract information about a macro definition (C preproc_def, Rust macro_definition)."""
|
|
110
|
+
name = extract_name(node, source_code, language) or "unknown"
|
|
111
|
+
|
|
112
|
+
# Extract parameters for function-like macros (C preproc_function_def)
|
|
113
|
+
params = []
|
|
114
|
+
params_node = node.child_by_field_name("parameters")
|
|
115
|
+
if params_node is None:
|
|
116
|
+
# C preproc_function_def uses preproc_params
|
|
117
|
+
for child in node.children:
|
|
118
|
+
if child.type == "preproc_params":
|
|
119
|
+
params_node = child
|
|
120
|
+
break
|
|
121
|
+
if params_node:
|
|
122
|
+
for child in params_node.children:
|
|
123
|
+
if child.type == "identifier":
|
|
124
|
+
params.append({"name": extract_node_text(child, source_code), "type": None})
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
"type": "macro",
|
|
128
|
+
"name": name,
|
|
129
|
+
"location": get_node_location(node),
|
|
130
|
+
"parameters": params,
|
|
131
|
+
"return_type": None,
|
|
132
|
+
"docstring": None,
|
|
133
|
+
"branch_count": 0,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def extract_struct_info(node, source_code, language):
|
|
138
|
+
"""Extract information about a struct definition (C, C++, etc.)."""
|
|
139
|
+
name = extract_name(node, source_code, language) or "unknown"
|
|
140
|
+
return {
|
|
141
|
+
"type": "struct",
|
|
142
|
+
"name": name,
|
|
143
|
+
"location": get_node_location(node),
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def extract_go_struct_info(node, source_code):
|
|
148
|
+
"""Extract information about a Go struct definition."""
|
|
149
|
+
name = extract_go_type_name(node, source_code) or "unknown"
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
"type": "struct",
|
|
153
|
+
"name": name,
|
|
154
|
+
"location": get_node_location(node),
|
|
155
|
+
"methods": [],
|
|
156
|
+
"fields": []
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def extract_interface_info(node, source_code, language):
|
|
161
|
+
"""Extract information about an interface/trait definition (Rust, etc.)."""
|
|
162
|
+
name = extract_name(node, source_code, language) or "unknown"
|
|
163
|
+
return {
|
|
164
|
+
"type": "interface",
|
|
165
|
+
"name": name,
|
|
166
|
+
"location": get_node_location(node),
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def extract_go_interface_info(node, source_code):
|
|
171
|
+
"""Extract information about a Go interface definition."""
|
|
172
|
+
name = extract_go_type_name(node, source_code) or "unknown"
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
"type": "interface",
|
|
176
|
+
"name": name,
|
|
177
|
+
"location": get_node_location(node),
|
|
178
|
+
"methods": []
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def extract_enum_info(node, source_code, language):
|
|
183
|
+
"""Extract information about an enum definition (Rust, etc.)."""
|
|
184
|
+
name = extract_name(node, source_code, language) or "unknown"
|
|
185
|
+
return {
|
|
186
|
+
"type": "enum",
|
|
187
|
+
"name": name,
|
|
188
|
+
"location": get_node_location(node),
|
|
189
|
+
}
|
indexing/file_utils.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File and directory utilities for the code indexer.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from indexing.language_config import get_language_for_extension, get_extensions_for_languages
|
|
8
|
+
from indexing.frontend_config import load_frontend_config
|
|
9
|
+
from pathspec import PathSpec
|
|
10
|
+
from pathspec.patterns import GitWildMatchPattern
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def detect_language(file_path):
|
|
14
|
+
"""Detect the language based on file extension."""
|
|
15
|
+
return get_language_for_extension(file_path.suffix)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def load_ignore_patterns(root_dir):
|
|
19
|
+
"""Load ignore patterns from .aiignore, falling back to .gitignore.
|
|
20
|
+
|
|
21
|
+
If .aiignore exists in the root directory, its patterns are used to
|
|
22
|
+
exclude files from indexing. If .aiignore does not exist, .gitignore
|
|
23
|
+
is used as a fallback.
|
|
24
|
+
"""
|
|
25
|
+
root_path = Path(root_dir)
|
|
26
|
+
aiignore_path = root_path / '.aiignore'
|
|
27
|
+
gitignore_path = root_path / '.gitignore'
|
|
28
|
+
|
|
29
|
+
ignore_path = None
|
|
30
|
+
if aiignore_path.exists():
|
|
31
|
+
ignore_path = aiignore_path
|
|
32
|
+
elif gitignore_path.exists():
|
|
33
|
+
ignore_path = gitignore_path
|
|
34
|
+
|
|
35
|
+
if ignore_path is None:
|
|
36
|
+
return PathSpec.from_lines(GitWildMatchPattern, [])
|
|
37
|
+
|
|
38
|
+
with open(ignore_path, 'r', encoding='utf-8') as f:
|
|
39
|
+
patterns = f.read().splitlines()
|
|
40
|
+
|
|
41
|
+
return PathSpec.from_lines(GitWildMatchPattern, patterns)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def collect_files_to_index(root_dir, languages, exclude_dirs=None):
|
|
45
|
+
"""Collect all files to index for given languages, respecting .aiignore (or .gitignore).
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
root_dir: Root directory to search.
|
|
49
|
+
languages: List of language names to include.
|
|
50
|
+
exclude_dirs: Optional list of additional directory names to exclude.
|
|
51
|
+
Generated directory exclusions from frontend config are always applied.
|
|
52
|
+
"""
|
|
53
|
+
root_path = Path(root_dir)
|
|
54
|
+
extensions = get_extensions_for_languages(languages)
|
|
55
|
+
|
|
56
|
+
# Load ignore patterns (.aiignore takes priority over .gitignore)
|
|
57
|
+
ignore_spec = load_ignore_patterns(root_dir)
|
|
58
|
+
|
|
59
|
+
# Load generated directory exclusions from frontend config
|
|
60
|
+
frontend_cfg = load_frontend_config(root_dir)
|
|
61
|
+
excluded_dirs = set(frontend_cfg.generated_dir_exclusions)
|
|
62
|
+
if exclude_dirs:
|
|
63
|
+
excluded_dirs.update(exclude_dirs)
|
|
64
|
+
|
|
65
|
+
files = []
|
|
66
|
+
ext_set = set(extensions)
|
|
67
|
+
|
|
68
|
+
for dirpath, dirnames, filenames in os.walk(root_path):
|
|
69
|
+
# Prune ignored directories before entering them
|
|
70
|
+
# Build relative path for the current directory to check against ignore spec
|
|
71
|
+
current_rel = os.path.relpath(dirpath, root_path)
|
|
72
|
+
if current_rel != '.':
|
|
73
|
+
# Check if this directory itself is ignored
|
|
74
|
+
if ignore_spec.match_file(current_rel + '/') or ignore_spec.match_file(current_rel):
|
|
75
|
+
dirnames[:] = []
|
|
76
|
+
continue
|
|
77
|
+
# Skip test directories and generated directories
|
|
78
|
+
dirnames[:] = [d for d in dirnames if d not in ('test', 'tests') and d not in excluded_dirs]
|
|
79
|
+
for filename in filenames:
|
|
80
|
+
if any(filename.endswith(ext) for ext in ext_set):
|
|
81
|
+
file_path = Path(dirpath) / filename
|
|
82
|
+
relative_path = file_path.relative_to(root_path)
|
|
83
|
+
if not ignore_spec.match_file(str(relative_path)):
|
|
84
|
+
files.append(file_path)
|
|
85
|
+
|
|
86
|
+
return files
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def read_file_content(file_path):
|
|
90
|
+
"""Read file content in binary mode for faster processing."""
|
|
91
|
+
with open(file_path, 'rb') as f:
|
|
92
|
+
return f.read()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_relative_path(file_path, root_dir):
|
|
96
|
+
"""Get relative path from root directory."""
|
|
97
|
+
return str(Path(file_path).relative_to(root_dir))
|
|
File without changes
|