codeix 0.5.0

Fast semantic code search for AI agents — find symbols, references, and callers across any codebase
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
{"file":"README.md","kind":"sample","line":[5,9],"text":"codeix                 # start MCP server, watch for changes\ncodeix build           # parse source files, write .codeindex\ncodeix serve --no-watch  # serve without file watching\n","parent":"codeix"}
{"file":"README.md","kind":"sample","line":[40,46],"text":".codeindex/\n  index.json        # manifest: version, name, languages\n  files.jsonl       # one line per source file (path, lang, hash, line count)\n  symbols.jsonl     # one line per symbol (functions, classes, imports, with signatures)\n  texts.jsonl       # one line per comment, docstring, string literal\n","parent":"codeix/The `.codeindex` format"}
{"file":"README.md","kind":"sample","line":[51,56],"text":"{\"file\":\"src/main.py\",\"name\":\"os\",\"kind\":\"import\",\"line\":[1,1]}\n{\"file\":\"src/main.py\",\"name\":\"Config\",\"kind\":\"class\",\"line\":[22,45]}\n{\"file\":\"src/main.py\",\"name\":\"Config.__init__\",\"kind\":\"method\",\"line\":[23,30],\"parent\":\"Config\",\"sig\":\"def __init__(self, path: str, debug: bool = False)\"}\n{\"file\":\"src/main.py\",\"name\":\"main\",\"kind\":\"function\",\"line\":[48,60],\"sig\":\"def main(args: list[str]) -> int\"}\n","parent":"codeix/The `.codeindex` format"}
{"file":"README.md","kind":"sample","line":[123,140],"text":"# npm / npx — run without installing\nnpx codeix\n\n# pip / uvx — run without installing\nuvx codeix\n\n# Rust\ncargo install codeix\n\n# Homebrew\nbrew install codeix\n\n# Or build from source\ngit clone https://github.com/montanetech/codeix.git\ncd codeix\ncargo build --release\n","parent":"codeix/Install"}
{"file":"README.md","kind":"sample","line":[146,159],"text":"# Build the index for the current project\ncodeix build\n\n# Build from a specific directory (discovers all git repos below)\ncodeix build ~/projects\n\n# Start MCP server (default command, watches for changes)\ncodeix\n\n# Or explicitly\ncodeix serve\ncodeix serve --no-watch\n","parent":"codeix/Usage"}
{"file":"README.md","kind":"sample","line":[165,173],"text":"{\n  \"mcpServers\": {\n    \"codeix\": {\n      \"command\": \"codeix\"\n    }\n  }\n}\n","parent":"codeix/Usage/MCP client configuration"}
{"file":"docs/architecture.md","kind":"sample","line":[42,48],"text":".codeindex/\n  index.json        # manifest: version, name, metadata\n  files.jsonl       # one line per source file\n  symbols.jsonl     # one line per symbol, sorted by file then line\n  texts.jsonl       # one line per comment/string/docstring\n","parent":"Codeindex — Architecture Decisions/ADR-002: Index structure — 4 files"}
{"file":"docs/architecture.md","kind":"sample","line":[51,58],"text":"{\n  \"version\": \"1.0\",\n  \"name\": \"my-project\",\n  \"root\": \".\",\n  \"languages\": [\"python\", \"typescript\"]\n}\n","parent":"Codeindex — Architecture Decisions/ADR-002: Index structure — 4 files/`index.json` — manifest"}
{"file":"docs/architecture.md","kind":"sample","line":[63,66],"text":"{\"path\":\"src/main.py\",\"lang\":\"python\",\"hash\":\"a1b2c3\",\"lines\":142}\n{\"path\":\"src/utils/helpers.py\",\"lang\":\"python\",\"hash\":\"d4e5f6\",\"lines\":87}\n","parent":"Codeindex — Architecture Decisions/ADR-002: Index structure — 4 files/`files.jsonl` — file registry"}
{"file":"docs/architecture.md","kind":"sample","line":[71,77],"text":"{\"file\":\"src/main.py\",\"name\":\"os\",\"kind\":\"import\",\"line\":[1,1]}\n{\"file\":\"src/main.py\",\"name\":\"utils.parse\",\"kind\":\"import\",\"line\":[2,2],\"alias\":\"parse\"}\n{\"file\":\"src/main.py\",\"name\":\"Config\",\"kind\":\"class\",\"line\":[22,45]}\n{\"file\":\"src/main.py\",\"name\":\"Config.__init__\",\"kind\":\"method\",\"line\":[23,30],\"parent\":\"Config\",\"sig\":\"def __init__(self, path: str, debug: bool = False)\"}\n{\"file\":\"src/main.py\",\"name\":\"main\",\"kind\":\"function\",\"line\":[48,60],\"sig\":\"def main(args: list[str]) -> int\"}\n","parent":"Codeindex — Architecture Decisions/ADR-002: Index structure — 4 files/`symbols.jsonl` — symbol index (definitions + imports)"}
{"file":"docs/architecture.md","kind":"sample","line":[86,90],"text":"{\"file\":\"src/main.py\",\"kind\":\"docstring\",\"line\":[15,18],\"text\":\"Validates user credentials against the database.\",\"parent\":\"authenticate\"}\n{\"file\":\"src/main.py\",\"kind\":\"comment\",\"line\":[45,45],\"text\":\"TODO: add rate limiting\"}\n{\"file\":\"src/main.py\",\"kind\":\"string\",\"line\":[22,22],\"text\":\"Invalid credentials for user: %s\"}\n","parent":"Codeindex — Architecture Decisions/ADR-002: Index structure — 4 files/`texts.jsonl` — comments, docstrings, string literals"}
{"file":"docs/architecture.md","kind":"sample","line":[129,134],"text":"server reads package.json → workspaces: [\"packages/*\"]\n  → finds packages/core/.codeindex/\n  → finds packages/ui/.codeindex/\n  → mounts both automatically\n","parent":"Codeindex — Architecture Decisions/ADR-003: Index is self-contained, no dependency declarations"}
{"file":"docs/architecture.md","kind":"sample","line":[137,141],"text":"server reads pyproject.toml → dependencies\n  → checks .venv/lib/.../requests/.codeindex/\n  → if present, loads it\n","parent":"Codeindex — Architecture Decisions/ADR-003: Index is self-contained, no dependency declarations"}
{"file":"docs/architecture.md","kind":"sample","line":[261,269],"text":"$ codeindex serve --watch     # start once, forget about it\n\n# ... edit code ...\n# .codeindex/ updates automatically\n\n$ git add -A                  # .codeindex/ is just another changed file\n$ git commit -m \"feat: ...\"\n","parent":"Codeindex — Architecture Decisions/ADR-007: Index stays on disk via watch mode — committed like a lockfile"}
{"file":"docs/architecture.md","kind":"sample","line":[432,436],"text":"~/myproject/          # has .git/\n  src/\n  .codeindex/         ← built here\n","parent":"Codeindex — Architecture Decisions/ADR-011: Project discovery — `.git/` boundaries"}
{"file":"docs/architecture.md","kind":"sample","line":[439,444],"text":"~/projects/           # no .git/\n  frontend/           # has .git/ → frontend/.codeindex/\n  backend/            # has .git/ → backend/.codeindex/\n  shared-lib/         # has .git/ → shared-lib/.codeindex/\n","parent":"Codeindex — Architecture Decisions/ADR-011: Project discovery — `.git/` boundaries"}
{"file":"docs/architecture.md","kind":"sample","line":[447,451],"text":"~/monorepo/           # has .git/  → monorepo/.codeindex/\n  vendor/libfoo/      # has .git  → vendor/libfoo/.codeindex/\n  vendor/libbar/      # has .git  → vendor/libbar/.codeindex/\n","parent":"Codeindex — Architecture Decisions/ADR-011: Project discovery — `.git/` boundaries"}
{"file":"docs/architecture.md","kind":"sample","line":[470,477],"text":"Mount::walk(root)\n  ├── WalkDir with follow_links(false) — no symlink loops\n  ├── GitignoreBuilder — builds .gitignore rules incrementally during walk\n  ├── SKIP_ENTRIES — always excludes .git, .codeindex, .vscode, .idea, etc.\n  ├── notify watcher — watches directories discovered during walk\n  └── emits MountEvent to handler (FileAdded, FileRemoved, DirAdded, DirRemoved, ProjectAdded)\n","parent":"Codeindex — Architecture Decisions/ADR-011: Project discovery — `.git/` boundaries"}
{"file":"docs/architecture.md","kind":"sample","line":[532,541],"text":"{\n    \"version\": \"1.0\",\n    \"name\": \"my-nuxt-app\",\n    \"mcp\": {\n      \"nuxt-ui\": { \"command\": \"npx nuxi-mcp\" },\n      \"supabase\": { \"url\": \"https://mcp.supabase.com\" }\n    }\n  }\n  ","parent":"Codeindex — Architecture Decisions/Future Considerations/External API documentation — two-tier model"}
{"file":"npm/install.js","kind":"string","line":[2,2],"text":"use strict"}
{"file":"npm/install.js","kind":"comment","line":[4,5],"text":"Postinstall script: downloads the prebuilt codeix binary from GitHub Releases.\nZero dependencies — uses Node.js built-in modules only."}
{"file":"npm/install.js","kind":"string","line":[18,18],"text":"x86_64-unknown-linux-gnu"}
{"file":"npm/install.js","kind":"string","line":[19,19],"text":"x86_64-pc-windows-msvc"}
{"file":"npm/install.js","kind":"string","line":[23,23],"text":"${process.platform}-${process.arch}"}
{"file":"npm/install.js","kind":"string","line":[26,26],"text":"codeix: unsupported platform ${key}"}
{"file":"npm/install.js","kind":"string","line":[27,27],"text":"Supported: ${Object.keys(PLATFORM_MAP).join(\", \")}"}
{"file":"npm/install.js","kind":"string","line":[35,35],"text":"https://github.com/${REPO}/releases/download/v${VERSION}/codeix-${target}.${ext}"}
{"file":"npm/install.js","kind":"comment","line":[41,41],"text":"Follow redirects (GitHub releases redirect to S3)"}
{"file":"npm/install.js","kind":"string","line":[46,46],"text":"HTTP ${res.statusCode} for ${url}"}
{"file":"npm/install.js","kind":"comment","line":[57,57],"text":"Write to temp file then extract with tar (available on macOS/Linux)"}
{"file":"npm/install.js","kind":"string","line":[60,60],"text":"tar xzf \"${tmpFile}\" -C \"${destDir}\""}
{"file":"npm/install.js","kind":"comment","line":[65,65],"text":"Write to temp file then extract with PowerShell (Windows)"}
{"file":"npm/install.js","kind":"string","line":[69,69],"text":"powershell -Command \"Expand-Archive -Path '${tmpFile}' -DestinationPath '${destDir}' -Force\""}
{"file":"npm/install.js","kind":"comment","line":[80,80],"text":"Skip if binary already exists (e.g. CI caching)"}
{"file":"npm/install.js","kind":"string","line":[87,87],"text":"Downloading codeix v${VERSION} for ${target}..."}
{"file":"npm/install.js","kind":"string","line":[100,100],"text":"Installed codeix to ${binPath}"}
{"file":"npm/install.js","kind":"string","line":[104,104],"text":"codeix install failed: ${err.message}"}
{"file":"npm/install.js","kind":"string","line":[105,105],"text":"You can install manually from:"}
{"file":"npm/install.js","kind":"string","line":[106,106],"text":"  https://github.com/${REPO}/releases/tag/v${VERSION}"}
{"file":"npm/install.js","kind":"comment","line":[107,108],"text":"Don't fail the install — the binary just won't be available\nThis avoids breaking `npm install` in CI environments that don't need the binary"}
{"file":"npm/run.js","kind":"string","line":[2,2],"text":"use strict"}
{"file":"npm/run.js","kind":"string","line":[16,16],"text":"codeix: binary not found at ${bin}"}
{"file":"npm/run.js","kind":"string","line":[17,17],"text":"Try reinstalling: npm install -g codeix"}
{"file":"python/codeix/__init__.py","kind":"docstring","line":[1,1],"text":"codeix — Portable, composable code index."}
{"file":"python/codeix/__init__.py","kind":"string","line":[1,1],"text":"codeix — Portable, composable code index."}
{"file":"python/codeix/__init__.py","kind":"comment","line":[15,15],"text":"x-release-please-version"}
{"file":"python/codeix/__init__.py","kind":"string","line":[21,21],"text":"x86_64-unknown-linux-gnu"}
{"file":"python/codeix/__init__.py","kind":"string","line":[22,22],"text":"x86_64-pc-windows-msvc"}
{"file":"python/codeix/__init__.py","kind":"docstring","line":[27,27],"text":"Platform-appropriate cache directory.","parent":"_cache_dir"}
{"file":"python/codeix/__init__.py","kind":"string","line":[41,41],"text":"codeix: unsupported platform {key}","parent":"_get_target"}
{"file":"python/codeix/__init__.py","kind":"string","line":[42,42],"text":"Supported: {list(PLATFORM_MAP.keys())}","parent":"_get_target"}
{"file":"python/codeix/__init__.py","kind":"string","line":[48,48],"text":"codeix-python/{__version__}","parent":"_download"}
{"file":"python/codeix/__init__.py","kind":"docstring","line":[54,54],"text":"Download the binary if not cached, return its path.","parent":"_ensure_binary"}
{"file":"python/codeix/__init__.py","kind":"string","line":[58,58],"text":"codeix-{__version__}{ext}","parent":"_ensure_binary"}
{"file":"python/codeix/__init__.py","kind":"string","line":[64,64],"text":"https://github.com/{REPO}/releases/download/v{__version__}/codeix-{target}.{archive_ext}","parent":"_ensure_binary"}
{"file":"python/codeix/__init__.py","kind":"string","line":[66,66],"text":"Downloading codeix v{__version__} for {target}...","parent":"_ensure_binary"}
{"file":"python/codeix/__init__.py","kind":"string","line":[87,87],"text":"codeix: failed to extract binary from archive","parent":"_ensure_binary"}
{"file":"python/codeix/__init__.py","kind":"comment","line":[90,90],"text":"Make executable on Unix","parent":"_ensure_binary"}
{"file":"python/codeix/__init__.py","kind":"string","line":[94,94],"text":"Cached codeix to {bin_path}","parent":"_ensure_binary"}
{"file":"python/codeix/__init__.py","kind":"docstring","line":[99,99],"text":"Entry point: download binary if needed, then exec with forwarded args.","parent":"main"}
{"file":"python/codeix/__init__.py","kind":"string","line":[103,103],"text":"codeix: failed to download binary: {e}","parent":"main"}
{"file":"python/codeix/__init__.py","kind":"string","line":[104,104],"text":"Install manually from: https://github.com/{REPO}/releases/tag/v{__version__}","parent":"main"}
{"file":"python/codeix/__main__.py","kind":"docstring","line":[1,1],"text":"Allow running as `python -m codeix`."}
{"file":"python/codeix/__main__.py","kind":"string","line":[1,1],"text":"Allow running as `python -m codeix`."}
{"file":"scripts/bench.py","kind":"comment","line":[1,1],"text":"!/usr/bin/env python3"}
{"file":"scripts/bench.py","kind":"docstring","line":[2,14],"text":"Codeix Benchmark Suite\n\nUsage:\n    python scripts/bench.py index-speed [--verbose]\n    python scripts/bench.py search-quality [--question ID]\n    python scripts/bench.py search-value [--question ID]\n\nCommands:\n    index-speed     Quantitative indexing speed benchmark\n    search-quality  A/B: prod codeix vs dev codeix\n    search-value    A/B: codeix vs raw Claude (no MCP)"}
{"file":"scripts/bench.py","kind":"string","line":[2,14],"text":"\nCodeix Benchmark Suite\n\nUsage:\n    python scripts/bench.py index-speed [--verbose]\n    python scripts/bench.py search-quality [--question ID]\n    python scripts/bench.py search-value [--question ID]\n\nCommands:\n    index-speed     Quantitative indexing speed benchmark\n    search-quality  A/B: prod codeix vs dev codeix\n    search-value    A/B: codeix vs raw Claude (no MCP)\n"}
{"file":"scripts/bench/__init__.py","kind":"docstring","line":[1,1],"text":"Codeix Benchmark Suite."}
{"file":"scripts/bench/__init__.py","kind":"string","line":[1,1],"text":"Codeix Benchmark Suite."}
{"file":"scripts/bench/__main__.py","kind":"docstring","line":[1,1],"text":"Entry point for python -m scripts.bench."}
{"file":"scripts/bench/__main__.py","kind":"string","line":[1,1],"text":"Entry point for python -m scripts.bench."}
{"file":"scripts/bench/__main__.py","kind":"docstring","line":[15,15],"text":"Export benchmark results in pytest-like JSON format.","parent":"export_results"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[17,17],"text":"No results to export","parent":"export_results"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[37,37],"text":"{config_name}:{q.get('id', 'unknown')}","parent":"export_results"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[59,59],"text":"Exported {len(results)} results to {output}","parent":"export_results"}
{"file":"scripts/bench/__main__.py","kind":"docstring","line":[63,63],"text":"Extract reason from judge response.","parent":"_extract_reason"}
{"file":"scripts/bench/__main__.py","kind":"comment","line":[66,66],"text":"With --json-schema, output is in structured_output","parent":"_extract_reason"}
{"file":"scripts/bench/__main__.py","kind":"comment","line":[70,70],"text":"Fallback: try result field (for legacy cached responses)","parent":"_extract_reason"}
{"file":"scripts/bench/__main__.py","kind":"comment","line":[75,75],"text":"Try direct JSON parse","parent":"_extract_reason"}
{"file":"scripts/bench/__main__.py","kind":"comment","line":[80,80],"text":"Extract from markdown JSON block","parent":"_extract_reason"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[82,82],"text":"r'\"reason\"\\s*:\\s*\"([^\"]+)\"'","parent":"_extract_reason"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[90,90],"text":"Codeix Benchmark Suite","parent":"main"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[92,106],"text":"\nCommands:\n  index-speed      Quantitative indexing speed benchmark\n  search-quality   A/B: dev codeix vs prod codeix\n  search-value     A/B: codeix vs raw Claude (no MCP)\n  clear-cache      Clear response cache\n\nExamples:\n  python -m scripts.bench index-speed\n  python -m scripts.bench search-quality\n  python -m scripts.bench search-value\n  python -m scripts.bench search-value --question entry-point\n  python -m scripts.bench search-quality --export results.json\n  python -m scripts.bench clear-cache\n","parent":"main"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[108,108],"text":"Benchmark command","parent":"main"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[109,109],"text":"Show detailed output","parent":"main"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[110,110],"text":"Run specific question by ID","parent":"main"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[111,111],"text":"Export results to JSON file (pytest-like format)","parent":"main"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[128,128],"text":"Cleared response cache: {RESPONSE_CACHE_DIR}","parent":"main"}
{"file":"scripts/bench/__main__.py","kind":"string","line":[130,130],"text":"Response cache already empty","parent":"main"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[1,1],"text":"A/B benchmark framework using claude CLI."}
{"file":"scripts/bench/ab.py","kind":"string","line":[1,1],"text":"A/B benchmark framework using claude CLI."}
{"file":"scripts/bench/ab.py","kind":"comment","line":[28,28],"text":"Max parallel questions (each runs 2 Claude calls + 1 judge)"}
{"file":"scripts/bench/ab.py","kind":"string","line":[29,29],"text":"CODEIX_BENCH_PARALLEL"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[37,40],"text":"Build a claude command with codeix MCP tools.\n\n    Standardized arg order ensures cache key consistency across benchmarks.","parent":"build_codeix_cmd"}
{"file":"scripts/bench/ab.py","kind":"string","line":[43,43],"text":"--no-session-persistence","parent":"build_codeix_cmd"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[55,55],"text":"Build a raw claude command (no tools).","parent":"build_claude_cmd"}
{"file":"scripts/bench/ab.py","kind":"string","line":[58,58],"text":"--no-session-persistence","parent":"build_claude_cmd"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[65,69],"text":"Build MCP config JSON for codeix.\n\n    Uses \".\" as repo path since cwd is set to the project repo.\n    This makes the command line consistent across runs (for caching).","parent":"build_mcp_config"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[81,81],"text":"Build standardized prompt for codeix questions.","parent":"build_prompt"}
{"file":"scripts/bench/ab.py","kind":"string","line":[82,82],"text":"Project: {project}\\n\\n{question}\\n\\nUse the codeindex MCP tools to answer.","parent":"build_prompt"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[87,87],"text":"Configuration for A/B benchmark.","parent":"ABConfig"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[92,93],"text":"Called once at start to setup binaries, returns (bin_a, bin_b)\nbin_a/bin_b are versioned names (e.g., \"codeix-abc123\", \"codeix-0.2.0\")","parent":"ABConfig"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[95,96],"text":"Returns (cmd_a, cwd_a, cmd_b, cwd_b) for a question\ncwd is set to the project repo so paths are relative","parent":"ABConfig"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[98,98],"text":"Optional per-question setup callbacks: setup_a(question, ctx) -> bool","parent":"ABConfig"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[101,101],"text":"Extra judge output fields","parent":"ABConfig"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[106,106],"text":"Extract winner from judge response.","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[109,109],"text":"With --json-schema, output is in structured_output","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[113,113],"text":"Fallback: try result field (for legacy cached responses)","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[118,118],"text":"Try direct JSON parse","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[123,123],"text":"Extract JSON from markdown (handles nested braces better)","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"string","line":[124,124],"text":"r'\\{[^{}]*\"winner\"\\s*:\\s*\"([^\"]+)\"[^{}]*\\}'","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[127,127],"text":"Fallback: look for \"winner\": \"X\" pattern anywhere","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"string","line":[128,128],"text":"r'\"winner\"\\s*:\\s*\"([^\"]+)\"'","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[131,131],"text":"Fallback: look for \"Winner: X\" or \"**Winner**: X\" in text","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"string","line":[132,132],"text":"r'\\*?\\*?[Ww]inner\\*?\\*?\\s*:\\s*\\*?\\*?([ABab]|[Tt]ie)\\*?\\*?'","parent":"parse_judge_winner"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[139,142],"text":"Run a subprocess command without TTY (prevents terminal issues with claude).\n\n    If bin_dir is provided, it's prepended to PATH so versioned binaries can be found.","parent":"run_subprocess"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[145,145],"text":"Build environment with bin_dir in PATH","parent":"run_subprocess"}
{"file":"scripts/bench/ab.py","kind":"string","line":[148,148],"text":"{bin_dir}:{env.get('PATH', '')}","parent":"run_subprocess"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[153,153],"text":"No TTY - prevents terminal issues","parent":"run_subprocess"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[158,158],"text":"Detach from controlling terminal","parent":"run_subprocess"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[180,186],"text":"Run A/B test for a single question.\n\n    Cache key = command line. This works because:\n    - Binary is named codeix-{version} (version embedded in filename)\n    - cwd is the project repo (so paths are relative)\n    - All params (--max-turns, prompt, etc.) are in the command","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[187,188],"text":"Get commands first (needed for cache keys)\nThis is cheap - just builds the command strings","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[191,191],"text":"Cache key = command line","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[198,198],"text":"If both cached, skip setup entirely","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[200,200],"text":"  Cache hit: {q['id']} ({q['category']})","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[204,204],"text":"Only setup (clone + build) if we need to run","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[206,206],"text":"  Setup A failed for {q['id']}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[209,209],"text":"  Setup B failed for {q['id']}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[212,212],"text":"Run A and B in parallel (only if not cached)","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[235,235],"text":"Save to cache","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[241,241],"text":"Helper to check for errors","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[247,247],"text":"Check for rate limit in result","parent":"run_question.has_error"}
{"file":"scripts/bench/ab.py","kind":"string","line":[249,249],"text":"hit your limit","parent":"run_question.has_error"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[251,251],"text":"is_error with non-success subtype","parent":"run_question.has_error"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[256,256],"text":"Check for errors and log them","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[260,260],"text":"  A error: {error_a}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[262,262],"text":"  B error: {error_b}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[264,264],"text":"Skip judging if either response has an error","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[281,281],"text":"  Done: {q['id']} (skipped judge due to error)","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[284,285],"text":"Judge using subprocess (with caching)\nTruncate responses for judge prompt","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[289,289],"text":"Get costs for judge evaluation","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[294,294],"text":"\\n\\nCOST:\\nA: ${cost_a:.4f}\\nB: ${cost_b:.4f}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[296,309],"text":"\"\"Compare these two responses to the question: \"{q['question']}\"\n\nRESPONSE A ({config.label_a}):\n{response_a_text}\n\nRESPONSE B ({config.label_b}):\n{response_b_text}{cost_info}\n\nEvaluate:\n1. Accuracy - Which response is more correct?\n2. Completeness - Which found more relevant information?\n3. Efficiency - Consider cost (lower is better for similar quality)\n\nOutput JSON: {{\"winner\": \"A\"|\"B\"|\"tie\", \"reason\": \"brief explanation\"{config.extra_judge_fields}}}\"\"","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[311,311],"text":"Build judge command (for cache key)","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[312,312],"text":"{\"type\":\"object\",\"properties\":{\"winner\":{\"type\":\"string\",\"enum\":[\"A\",\"B\",\"tie\"]},\"reason\":{\"type\":\"string\"}},\"required\":[\"winner\",\"reason\"]}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[315,315],"text":"--no-session-persistence","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[323,323],"text":"Validate judge response contains a winner, bust cache if not","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[328,328],"text":"Valid if structured_output has winner, or result has winner (legacy)","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[338,338],"text":"Run judge via subprocess (no tools needed)","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[340,340],"text":"With --json-schema, output is in structured_output field","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[345,345],"text":"Debug: log when judge fails to return winner","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[347,347],"text":"Judge failed for {q['id']}: structured={structured}, error={error_text[:200] if error_text else 'none'}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[360,360],"text":"No errors if we got here (errors returned early above)","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"string","line":[366,366],"text":"  Done: {q['id']}","parent":"run_question"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[375,375],"text":"Run A/B benchmark with given configuration (async). Returns results list.","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[379,379],"text":"Questions file not found: {questions_file}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[386,386],"text":"Question '{question_id}' not found","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[389,389],"text":"Create temporary run directory with standard structure","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[396,396],"text":"Running {config.name} with {len(questions)} question(s) in parallel","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[397,397],"text":"Run dir: {ctx.run_dir}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[400,401],"text":"Setup binaries (once, before running questions)\nBinaries are named with version embedded (e.g., codeix-abc123)","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[403,403],"text":"A: {config.label_a} ({bin_a})","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[404,404],"text":"B: {config.label_b} ({bin_b})","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[406,406],"text":"Create semaphore to limit parallelism","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[413,413],"text":"Run all questions with limited parallelism","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[420,420],"text":"Cancel all pending tasks","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[423,423],"text":"\\n\\nInterrupted, stopping...","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[429,429],"text":"{CYAN}═══════════════════════════════════════════════════════════════{NC}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[430,430],"text":"{CYAN}{config.title:^63}{NC}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[431,431],"text":"{CYAN}═══════════════════════════════════════════════════════════════{NC}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[433,433],"text":"Show what A and B represent","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[434,434],"text":"A: {config.label_a}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[435,435],"text":"B: {config.label_b}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[437,437],"text":"{'Question':<30} {'Winner':^8}  {'A cost':>8}  {'B cost':>8}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[456,456],"text":"Show errors in output","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[465,465],"text":"  [{', '.join(error_parts)}]","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[467,467],"text":"{r['question']['id']:<30} {winner:^8}  {cost_a:>8}  {cost_b:>8}{error_info}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[469,469],"text":"Summary row","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[473,473],"text":"A:{a_wins} B:{b_wins}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[476,476],"text":"{'TOTAL':<30} {wins_summary:^8}  {cost_a_str:>8}  {cost_b_str:>8}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[480,480],"text":"A ({config.label_a})","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[482,482],"text":"B ({config.label_b})","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[485,485],"text":"Winner: {overall}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"comment","line":[487,487],"text":"Cache stats","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"string","line":[492,492],"text":"Cache: A={cache_hits_a}/{len(results)}, B={cache_hits_b}/{len(results)}, judge={cache_hits_judge}/{len(results)}","parent":"run_async"}
{"file":"scripts/bench/ab.py","kind":"docstring","line":[501,501],"text":"Run A/B benchmark with given configuration. Returns results list.","parent":"run"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[1,1],"text":"Common utilities for benchmark suite."}
{"file":"scripts/bench/common.py","kind":"string","line":[1,1],"text":"Common utilities for benchmark suite."}
{"file":"scripts/bench/common.py","kind":"comment","line":[12,12],"text":"Project root (codeix repo)"}
{"file":"scripts/bench/common.py","kind":"comment","line":[16,16],"text":"Cache dir: persistent across runs (only for response cache)"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[23,23],"text":"Context for a benchmark run - fresh temp directory per run.","parent":"RunContext"}
{"file":"scripts/bench/common.py","kind":"comment","line":[24,29],"text":"Root: /tmp/codeix-bench-xxxxx/\nBinaries: run_dir/bin/\nRepos: run_dir/repos/ (for single-variant benchmarks)\nRepos for A: run_dir/repos/a/ (for A/B benchmarks)\nRepos for B: run_dir/repos/b/ (for A/B benchmarks)\nResults: run_dir/results/","parent":"RunContext"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[33,33],"text":"Create a fresh temporary run directory with standard structure.","parent":"create_run_context"}
{"file":"scripts/bench/common.py","kind":"comment","line":[61,61],"text":"Small repos"}
{"file":"scripts/bench/common.py","kind":"string","line":[62,62],"text":"https://github.com/colinhacks/zod"}
{"file":"scripts/bench/common.py","kind":"string","line":[62,62],"text":"Validation library"}
{"file":"scripts/bench/common.py","kind":"string","line":[63,63],"text":"https://github.com/gin-gonic/gin"}
{"file":"scripts/bench/common.py","kind":"string","line":[63,63],"text":"HTTP framework"}
{"file":"scripts/bench/common.py","kind":"string","line":[64,64],"text":"https://github.com/google/leveldb"}
{"file":"scripts/bench/common.py","kind":"string","line":[64,64],"text":"KV store, has submodules"}
{"file":"scripts/bench/common.py","kind":"comment","line":[65,65],"text":"Medium repos"}
{"file":"scripts/bench/common.py","kind":"string","line":[66,66],"text":"https://github.com/tokio-rs/tokio"}
{"file":"scripts/bench/common.py","kind":"string","line":[66,66],"text":"Async runtime"}
{"file":"scripts/bench/common.py","kind":"string","line":[67,67],"text":"https://github.com/pallets/flask"}
{"file":"scripts/bench/common.py","kind":"string","line":[67,67],"text":"Web micro-framework"}
{"file":"scripts/bench/common.py","kind":"string","line":[68,68],"text":"FizzBuzzEnterpriseEdition"}
{"file":"scripts/bench/common.py","kind":"string","line":[68,68],"text":"https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition"}
{"file":"scripts/bench/common.py","kind":"string","line":[68,68],"text":"Satirical over-engineering"}
{"file":"scripts/bench/common.py","kind":"string","line":[69,69],"text":"https://github.com/jedisct1/libsodium"}
{"file":"scripts/bench/common.py","kind":"string","line":[69,69],"text":"Crypto library"}
{"file":"scripts/bench/common.py","kind":"string","line":[70,70],"text":"https://github.com/faker-ruby/faker"}
{"file":"scripts/bench/common.py","kind":"string","line":[70,70],"text":"Data generation"}
{"file":"scripts/bench/common.py","kind":"string","line":[71,71],"text":"https://github.com/JamesNK/Newtonsoft.Json"}
{"file":"scripts/bench/common.py","kind":"string","line":[71,71],"text":"JSON library"}
{"file":"scripts/bench/common.py","kind":"comment","line":[72,72],"text":"Zig repo"}
{"file":"scripts/bench/common.py","kind":"string","line":[73,73],"text":"https://github.com/zigtools/zls"}
{"file":"scripts/bench/common.py","kind":"string","line":[73,73],"text":"Zig Language Server"}
{"file":"scripts/bench/common.py","kind":"string","line":[86,86],"text":"{BLUE}[bench]{NC} {msg}","parent":"log"}
{"file":"scripts/bench/common.py","kind":"string","line":[90,90],"text":"{GREEN}[bench]{NC} {msg}","parent":"log_success"}
{"file":"scripts/bench/common.py","kind":"string","line":[94,94],"text":"{RED}[bench]{NC} {msg}","parent":"log_error"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[98,98],"text":"Get path to local build, or None if not found.","parent":"get_local_codeix"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[106,106],"text":"Get codeix binary: CODEIX_BIN env var or local build. No PATH fallback.","parent":"get_codeix_bin"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[114,114],"text":"Get a short relative path for display.","parent":"get_short_path"}
{"file":"scripts/bench/common.py","kind":"comment","line":[116,116],"text":"Try relative to PROJECT_ROOT","parent":"get_short_path"}
{"file":"scripts/bench/common.py","kind":"comment","line":[121,121],"text":"Try relative to cwd","parent":"get_short_path"}
{"file":"scripts/bench/common.py","kind":"comment","line":[126,126],"text":"Just the filename","parent":"get_short_path"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[131,134],"text":"Build .codeindex for a single repo using the specified codeix binary.\n\n    Returns True if index exists (already built or successfully built).","parent":"build_index"}
{"file":"scripts/bench/common.py","kind":"comment","line":[139,139],"text":"Build command: either direct binary or npx","parent":"build_index"}
{"file":"scripts/bench/common.py","kind":"string","line":[145,145],"text":"Building index: {repo_path.name}...","parent":"build_index"}
{"file":"scripts/bench/common.py","kind":"string","line":[148,148],"text":"  Failed to build index: {result.stderr[:200]}","parent":"build_index"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[154,154],"text":"Clone a repo to a specific destination.","parent":"clone_repo_to"}
{"file":"scripts/bench/common.py","kind":"string","line":[159,159],"text":"Cloning {repo.name} to {dest.name}...","parent":"clone_repo_to"}
{"file":"scripts/bench/common.py","kind":"string","line":[171,171],"text":"Failed to clone {repo.name}","parent":"clone_repo_to"}
{"file":"scripts/bench/common.py","kind":"comment","line":[174,174],"text":"Shallow submodules if present","parent":"clone_repo_to"}
{"file":"scripts/bench/common.py","kind":"string","line":[177,177],"text":"  Submodules: {repo.name}...","parent":"clone_repo_to"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[188,188],"text":"Get a Repo by name.","parent":"get_repo_by_name"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[196,196],"text":"Count files in repo, excluding common build dirs.","parent":"count_files"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[206,206],"text":"Count lines of code in common source files.","parent":"count_lines"}
{"file":"scripts/bench/common.py","kind":"comment","line":[219,221],"text":"============================================================================\nResponse Cache\n============================================================================"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[224,224],"text":"Get version string for a binary file (hash of contents).","parent":"get_binary_version"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[231,231],"text":"Get version of codeix from npm registry.","parent":"get_npm_codeix_version"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[247,247],"text":"Get version of claude CLI.","parent":"get_claude_version"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[263,269],"text":"Generate cache key from command line.\n\n    The command line IS the cache key. This works because:\n    - Binary is named codeix-{version} (version embedded in filename)\n    - cwd is the project repo (so paths are relative)\n    - All params (--max-turns, prompt, etc.) are in the command","parent":"get_cache_key_from_cmd"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[275,279],"text":"Get cached response if exists and is valid.\n\n    Accepts error responses (they'll be busted when the error is fixed).\n    Only rejects truly invalid cache (corrupted JSON, missing response).","parent":"get_cached_response"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[295,295],"text":"Delete a cached response.","parent":"delete_cached_response"}
{"file":"scripts/bench/common.py","kind":"docstring","line":[302,302],"text":"Save response to cache.","parent":"save_cached_response"}
{"file":"scripts/bench/index_speed.py","kind":"docstring","line":[1,1],"text":"Quantitative indexing speed benchmark."}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[1,1],"text":"Quantitative indexing speed benchmark."}
{"file":"scripts/bench/index_speed.py","kind":"docstring","line":[27,27],"text":"Benchmark indexing a single repo.","parent":"benchmark_repo"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[30,30],"text":"Directory not found: {path}","parent":"benchmark_repo"}
{"file":"scripts/bench/index_speed.py","kind":"comment","line":[36,36],"text":"Clean existing index","parent":"benchmark_repo"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[50,50],"text":"Failed to index {repo.name}","parent":"benchmark_repo"}
{"file":"scripts/bench/index_speed.py","kind":"docstring","line":[68,68],"text":"Run quantitative indexing benchmark.","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[70,70],"text":"{CYAN}╔══════════════════════════════════════════════════════════════════════════════════════════════════╗{NC}","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[71,71],"text":"{CYAN}║                                   CODEIX BENCHMARK                                               ║{NC}","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[72,72],"text":"{CYAN}╚══════════════════════════════════════════════════════════════════════════════════════════════════╝{NC}","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"comment","line":[75,75],"text":"Check codeix - local build or CODEIX_BIN only","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[78,78],"text":"codeix not found (build with 'cargo build --release' or set CODEIX_BIN)","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[80,80],"text":"Using codeix: {codeix_bin}","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"comment","line":[82,82],"text":"Create fresh run context","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[84,84],"text":"Run dir: {ctx.run_dir}","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"comment","line":[90,90],"text":"Copy codeix binary to run dir for reproducibility","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"comment","line":[96,96],"text":"Clone phase","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[98,98],"text":"Phase 1: Cloning repositories...","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[106,106],"text":"Cloning complete in {clone_duration:.1f}s","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"comment","line":[108,108],"text":"Benchmark phase","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[110,110],"text":"Phase 2: Benchmarking indexing...","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[114,114],"text":"{'Repository':<18} │ {'Language':<10} │ {'Size':<7} │ {'Files':>6} │ {'Lines':>8} │ {'Time':>7} │ {'Speed':>8} │ Notes","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[115,115],"text":"───────────────────┼────────────┼─────────┼────────┼──────────┼─────────┼──────────┼─────────────────────────","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[123,125],"text":"{result['name']:<18} │ {result['lang']:<10} │ {result['size']:<7} │ \"\n                f\"{result['files']:>6} │ {result['lines']:>8} │ {result['duration']:>6.2f}s │ \"\n                f\"{result['files_per_sec']:>6}/s │ {result['notes']}","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[128,128],"text":"{repo.name:<18} │ {repo.lang:<10} │ {repo.size:<7} │ {'FAILED':>6} │ {'-':>8} │ {'-':>7} │ {'-':>8} │ {repo.notes}","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[131,131],"text":"Benchmark complete!","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[133,133],"text":"{CYAN}Languages tested:{NC} TypeScript, Go, C++, Rust, Python, Java, C, Ruby, Zig","parent":"run"}
{"file":"scripts/bench/index_speed.py","kind":"string","line":[134,134],"text":"{CYAN}Structural tests:{NC} Small/Medium/Large repos, with/without submodules, polyglot","parent":"run"}
{"file":"scripts/bench/search_quality.py","kind":"docstring","line":[1,1],"text":"Search quality benchmark: dev codeix vs prod codeix."}
{"file":"scripts/bench/search_quality.py","kind":"string","line":[1,1],"text":"Search quality benchmark: dev codeix vs prod codeix."}
{"file":"scripts/bench/search_quality.py","kind":"docstring","line":[25,25],"text":"Run A/B: dev codeix vs prod codeix. Returns results list.","parent":"run"}
{"file":"scripts/bench/search_quality.py","kind":"docstring","line":[28,33],"text":"Setup binaries in run dir, return (bin_a, bin_b).\n\n        Binaries are named with version embedded for cache key stability:\n        - codeix-{hash} for local dev build\n        - codeix-{version} for npm package","parent":"run.setup_run"}
{"file":"scripts/bench/search_quality.py","kind":"comment","line":[34,34],"text":"A: copy local dev binary with version in name","parent":"run.setup_run"}
{"file":"scripts/bench/search_quality.py","kind":"string","line":[37,37],"text":"No local codeix build found. Run 'cargo build --release' first.","parent":"run.setup_run"}
{"file":"scripts/bench/search_quality.py","kind":"comment","line":[43,43],"text":"B: wrapper script for npx codeix, with version in name","parent":"run.setup_run"}
{"file":"scripts/bench/search_quality.py","kind":"string","line":[46,46],"text":"#!/bin/sh\\nexec npx codeix \\\"$@\\\"\\n","parent":"run.setup_run"}
{"file":"scripts/bench/search_quality.py","kind":"docstring","line":[52,52],"text":"Clone repo and build index for A.","parent":"run.setup_a"}
{"file":"scripts/bench/search_quality.py","kind":"comment","line":[59,59],"text":"Find the versioned binary (there's only one codeix-* in bin_dir for A)","parent":"run.setup_a"}
{"file":"scripts/bench/search_quality.py","kind":"docstring","line":[64,64],"text":"Clone repo and build index for B.","parent":"run.setup_b"}
{"file":"scripts/bench/search_quality.py","kind":"comment","line":[71,71],"text":"Find the versioned binary for B (the npm version one)","parent":"run.setup_b"}
{"file":"scripts/bench/search_quality.py","kind":"docstring","line":[77,82],"text":"Generate commands for A and B.\n\n        Returns (cmd_a, cwd_a, cmd_b, cwd_b).\n        cwd is set to project repo so paths are relative (for cache key stability).\n        Binary paths use just the versioned name (e.g., \"codeix-abc123\") for stable cache keys.","parent":"run.get_commands"}
{"file":"scripts/bench/search_quality.py","kind":"comment","line":[83,83],"text":"Find versioned binaries - use just the name, not full path","parent":"run.get_commands"}
{"file":"scripts/bench/search_quality.py","kind":"comment","line":[88,88],"text":"Use just the binary name - we'll set PATH to include bin_dir","parent":"run.get_commands"}
{"file":"scripts/bench/search_quality.py","kind":"comment","line":[96,96],"text":"MCP config uses versioned binary name (PATH will be set to find it)","parent":"run.get_commands"}
{"file":"scripts/bench/search_quality.py","kind":"string","line":[103,103],"text":"search-quality benchmark","parent":"run"}
{"file":"scripts/bench/search_quality.py","kind":"string","line":[106,106],"text":"SEARCH QUALITY BENCHMARK","parent":"run"}
{"file":"scripts/bench/search_value.py","kind":"docstring","line":[1,1],"text":"Search value benchmark: codeix vs raw Claude."}
{"file":"scripts/bench/search_value.py","kind":"string","line":[1,1],"text":"Search value benchmark: codeix vs raw Claude."}
{"file":"scripts/bench/search_value.py","kind":"docstring","line":[26,26],"text":"Run A/B: codeix vs raw Claude. Returns results list.","parent":"run"}
{"file":"scripts/bench/search_value.py","kind":"docstring","line":[29,34],"text":"Setup binaries in run dir, return (bin_a, bin_b).\n\n        Binaries are named with version embedded for cache key stability:\n        - codeix-{hash} for local dev build\n        - claude (version injected in prompt for B)","parent":"run.setup_run"}
{"file":"scripts/bench/search_value.py","kind":"comment","line":[35,35],"text":"A: copy local dev binary with version in name","parent":"run.setup_run"}
{"file":"scripts/bench/search_value.py","kind":"string","line":[38,38],"text":"No local codeix build found. Run 'cargo build --release' first.","parent":"run.setup_run"}
{"file":"scripts/bench/search_value.py","kind":"comment","line":[44,44],"text":"B: raw Claude (version will be injected in prompt)","parent":"run.setup_run"}
{"file":"scripts/bench/search_value.py","kind":"docstring","line":[50,50],"text":"Clone repo and build index for A.","parent":"run.setup_a"}
{"file":"scripts/bench/search_value.py","kind":"comment","line":[57,57],"text":"Find the versioned binary","parent":"run.setup_a"}
{"file":"scripts/bench/search_value.py","kind":"docstring","line":[64,64],"text":"Clone repo for B (raw Claude needs files to read).","parent":"run.setup_b"}
{"file":"scripts/bench/search_value.py","kind":"docstring","line":[72,76],"text":"Generate commands for A and B.\n\n        Returns (cmd_a, cwd_a, cmd_b, cwd_b).\n        cwd is set to project repo so paths are relative (for cache key stability).","parent":"run.get_commands"}
{"file":"scripts/bench/search_value.py","kind":"comment","line":[77,77],"text":"Find versioned binaries","parent":"run.get_commands"}
{"file":"scripts/bench/search_value.py","kind":"comment","line":[82,82],"text":"Use just the binary name - PATH will include bin_dir","parent":"run.get_commands"}
{"file":"scripts/bench/search_value.py","kind":"comment","line":[89,89],"text":"MCP config uses versioned binary name (PATH will be set to find it)","parent":"run.get_commands"}
{"file":"scripts/bench/search_value.py","kind":"comment","line":[91,91],"text":"B: inject claude version in prompt for cache busting","parent":"run.get_commands"}
{"file":"scripts/bench/search_value.py","kind":"string","line":[92,92],"text":"[claude:{version_b}] {q['question']}","parent":"run.get_commands"}
{"file":"scripts/bench/search_value.py","kind":"string","line":[98,98],"text":"search-value benchmark","parent":"run"}
{"file":"scripts/bench/search_value.py","kind":"string","line":[101,101],"text":"CODEIX VALUE BENCHMARK","parent":"run"}
{"file":"scripts/bench/search_value.py","kind":"string","line":[106,106],"text":", \"codeix_value\": \"high|medium|low|none\"","parent":"run"}
{"file":"site/templates/index.html","kind":"string","line":[1256,1256],"text":"0px 0px -40px 0px"}
{"file":"site/templates/index.html","kind":"comment","line":[1262,1262],"text":"Sticky header: show after scrolling past the hero"}
{"file":"site/templates/spec.html","kind":"string","line":[471,471],"text":".spec-nav a[href^=\"#\"]"}
{"file":"site/templates/spec.html","kind":"string","line":[489,489],"text":"-20% 0px -60% 0px"}
{"file":"spec/codeindex.md","kind":"sample","line":[20,26],"text":".codeindex/\n  index.json        # manifest (required)\n  files.jsonl       # file registry (required)\n  symbols.jsonl     # symbol index (required, may be empty)\n  texts.jsonl       # text content index (required, may be empty)\n","parent":"`.codeindex` Format Specification/Directory layout"}
{"file":"spec/codeindex.md","kind":"sample","line":[42,49],"text":"{\n  \"version\": \"1.0\",\n  \"name\": \"my-project\",\n  \"root\": \".\",\n  \"languages\": [\"python\", \"typescript\"]\n}\n","parent":"`.codeindex` Format Specification/`index.json` — manifest"}
{"file":"spec/codeindex.md","kind":"sample","line":[66,70],"text":"{\"path\":\"src/main.py\",\"lang\":\"python\",\"hash\":\"a1b2c3d4e5f6a7b8\",\"lines\":142}\n{\"path\":\"src/utils/helpers.py\",\"lang\":\"python\",\"hash\":\"b2c3d4e5f6a7b8c9\",\"lines\":87}\n{\"path\":\"pytest.ini\",\"lang\":null,\"hash\":\"c3d4e5f6a7b8c9d0\",\"lines\":12}\n","parent":"`.codeindex` Format Specification/`files.jsonl` — file registry"}
{"file":"spec/codeindex.md","kind":"sample","line":[97,103],"text":"{\"file\":\"src/main.py\",\"name\":\"os\",\"kind\":\"import\",\"line\":[1,1]}\n{\"file\":\"src/main.py\",\"name\":\"utils.parse\",\"kind\":\"import\",\"line\":[2,2],\"alias\":\"parse\"}\n{\"file\":\"src/main.py\",\"name\":\"Config\",\"kind\":\"class\",\"line\":[22,45]}\n{\"file\":\"src/main.py\",\"name\":\"Config.__init__\",\"kind\":\"method\",\"line\":[23,30],\"parent\":\"Config\",\"sig\":\"def __init__(self, path: str, debug: bool = False)\"}\n{\"file\":\"src/main.py\",\"name\":\"main\",\"kind\":\"function\",\"line\":[48,60],\"sig\":\"def main(args: list[str]) -> int\"}\n","parent":"`.codeindex` Format Specification/`symbols.jsonl` — symbol index"}
{"file":"spec/codeindex.md","kind":"sample","line":[146,150],"text":"{\"file\":\"src/app.py\",\"name\":\"App\",\"kind\":\"class\",\"line\":[10,50]}\n{\"file\":\"src/app.py\",\"name\":\"App.__init__\",\"kind\":\"method\",\"line\":[11,15],\"parent\":\"App\",\"sig\":\"def __init__(self)\"}\n{\"file\":\"src/app.py\",\"name\":\"App.run\",\"kind\":\"method\",\"line\":[17,50],\"parent\":\"App\",\"sig\":\"def run(self) -> None\"}\n","parent":"`.codeindex` Format Specification/`symbols.jsonl` — symbol index/Nesting"}
{"file":"spec/codeindex.md","kind":"sample","line":[166,170],"text":"{\"file\":\"src/lib.rs\",\"name\":\"Client\",\"kind\":\"struct\",\"line\":[10,50],\"visibility\":\"public\"}\n{\"file\":\"src/lib.rs\",\"name\":\"Client.connect\",\"kind\":\"method\",\"line\":[12,25],\"parent\":\"Client\",\"visibility\":\"public\",\"sig\":\"pub fn connect(&self, url: &str) -> Result<()>\"}\n{\"file\":\"src/lib.rs\",\"name\":\"Client.retry_internal\",\"kind\":\"method\",\"line\":[27,40],\"parent\":\"Client\",\"visibility\":\"private\",\"sig\":\"fn retry_internal(&self, attempts: u32)\"}\n","parent":"`.codeindex` Format Specification/`symbols.jsonl` — symbol index/Visibility"}
{"file":"spec/codeindex.md","kind":"sample","line":[180,184],"text":"{\"file\":\"src/main.py\",\"kind\":\"docstring\",\"line\":[15,18],\"text\":\"Validates user credentials against the database.\",\"parent\":\"authenticate\"}\n{\"file\":\"src/main.py\",\"kind\":\"comment\",\"line\":[45,45],\"text\":\"TODO: add rate limiting\"}\n{\"file\":\"src/main.py\",\"kind\":\"string\",\"line\":[22,22],\"text\":\"Invalid credentials for user: %s\"}\n","parent":"`.codeindex` Format Specification/`texts.jsonl` — text content index"}
{"file":"spec/codeindex.md","kind":"sample","line":[258,264],"text":"my-project/\n  .git/\n  .codeindex/      # committed with the code\n  src/\n  package.json\n","parent":"`.codeindex` Format Specification/Distribution/Git repository (primary)"}
{"file":"spec/codeindex.md","kind":"sample","line":[284,287],"text":"https://example.com/.well-known/codeindex/index.json\nhttps://example.com/.well-known/codeindex/symbols.jsonl\n","parent":"`.codeindex` Format Specification/Distribution/HTTP discovery (future)"}
{"file":"spec/codeindex.md","kind":"sample","line":[292,294],"text":"https://raw.githubusercontent.com/org/repo/main/.codeindex/symbols.jsonl\n","parent":"`.codeindex` Format Specification/Distribution/HTTP discovery (future)"}
{"file":"spec/codeindex.md","kind":"sample","line":[314,318],"text":"{\"file\":\"api/users.py\",\"name\":\"GET /users\",\"kind\":\"endpoint\",\"line\":[15,30],\"sig\":\"GET /users?page=int&limit=int -> UserList\"}\n{\"file\":\"schema.graphql\",\"name\":\"Query.user\",\"kind\":\"query\",\"line\":[5,8],\"sig\":\"user(id: ID!): User\"}\n{\"file\":\"proto/service.proto\",\"name\":\"UserService.GetUser\",\"kind\":\"rpc\",\"line\":[12,14],\"sig\":\"GetUser(GetUserRequest) returns (User)\"}\n","parent":"`.codeindex` Format Specification/Scope and visibility/Remote APIs (future)"}
{"file":"src/cli/build.rs","kind":"docstring","line":[12,12],"text":"Result type for build_index_to_db: (MountTable, SearchDb)"}
{"file":"src/cli/build.rs","kind":"docstring","line":[15,16],"text":"Build the index into a database without flushing to disk.\nReturns MountTable + SearchDb for both build (flush to disk) and serve (keep in memory)."}
{"file":"src/cli/build.rs","kind":"docstring","line":[18,21],"text":"Uses `on_project_discovery` which:\n1. If load_from_cache=true: loads from .codeindex/ if it exists\n2. Otherwise indexes files (stopping at subproject boundaries)\n3. Recursively handles discovered subprojects"}
{"file":"src/cli/build.rs","kind":"docstring","line":[24,29],"text":"- `enable_fts`: If true, creates FTS5 tables for search (serve mode).\nIf false, skips FTS to reduce memory on large repos (build mode).\n- `load_from_cache`: If true (serve), try loading from .codeindex/ first.\nIf false (build), always re-index.\n- `tx`: If provided, initializes notify watchers during walk so directories\nare watched immediately (single walk strategy for serve --watch)."}
{"file":"src/cli/build.rs","kind":"string","line":[38,38],"text":"cannot resolve path: {}"}
{"file":"src/cli/build.rs","kind":"string","line":[40,40],"text":"building index at {}"}
{"file":"src/cli/build.rs","kind":"comment","line":[42,42],"text":"Create mount table and database"}
{"file":"src/cli/build.rs","kind":"string","line":[45,45],"text":"failed to create search database"}
{"file":"src/cli/build.rs","kind":"string","line":[47,47],"text":"failed to create search database"}
{"file":"src/cli/build.rs","kind":"comment","line":[50,51],"text":"Process root project (will recursively discover and handle subprojects)\nPass load_from_cache and tx (for notify watchers during walk, if provided)"}
{"file":"src/cli/build.rs","kind":"string","line":[52,52],"text":"failed to process root project"}
{"file":"src/cli/build.rs","kind":"docstring","line":[57,58],"text":"Build the index: scan the directory tree, parse files with tree-sitter,\nand write the `.codeindex/` output."}
{"file":"src/cli/build.rs","kind":"docstring","line":[60,61],"text":"Discovers .git/ boundaries and creates separate .codeindex/ for each\nproject found. Root is always treated as a project (with or without .git/)."}
{"file":"src/cli/build.rs","kind":"comment","line":[63,65],"text":"Build mode: disable FTS to reduce memory on large repos\nload_from_cache=false: always re-index (ignore .codeindex/)\ntx=None: no watcher"}
{"file":"src/cli/build.rs","kind":"comment","line":[68,68],"text":"Flush each dirty mount to disk"}
{"file":"src/cli/build.rs","kind":"string","line":[71,71],"text":"mount table lock poisoned: {e}"}
{"file":"src/cli/build.rs","kind":"string","line":[80,80],"text":"failed to flush index to disk for {}"}
{"file":"src/cli/build.rs","kind":"comment","line":[82,82],"text":"Get stats for this mount (use relative project path)"}
{"file":"src/cli/build.rs","kind":"string","line":[86,86],"text":"db lock poisoned: {e}"}
{"file":"src/cli/build.rs","kind":"string","line":[96,96],"text":"wrote .codeindex/ for '{}': {} files, {} symbols, {} texts"}
{"file":"src/cli/build.rs","kind":"string","line":[110,110],"text":"total: {} files, {} symbols, {} texts"}
{"file":"src/cli/build.rs","kind":"docstring","line":[117,118],"text":"Run the `build` subcommand: scan the directory tree, parse files with\ntree-sitter, and write the `.codeindex/` output."}
{"file":"src/cli/serve.rs","kind":"docstring","line":[12,13],"text":"Run the `serve` subcommand: load the index into an in-memory SQLite FTS5\ndatabase and start the MCP server over stdio."}
{"file":"src/cli/serve.rs","kind":"string","line":[17,17],"text":"cannot resolve path: {}"}
{"file":"src/cli/serve.rs","kind":"comment","line":[19,21],"text":"If watch mode: create channel BEFORE building\nThis way directories are watched during the single walk (no second walk needed)\nChannel carries (mount_root, event) tuples for direct mount lookup"}
{"file":"src/cli/serve.rs","kind":"string","line":[23,23],"text":"starting watch mode"}
{"file":"src/cli/serve.rs","kind":"comment","line":[30,33],"text":"Build index with FTS enabled (loads from .codeindex/ if exists, otherwise parses files)\nServe mode needs FTS for search functionality\nload_from_cache=true: load from .codeindex/ if available\nPass tx to initialize notify watchers during walk (single walk strategy)"}
{"file":"src/cli/serve.rs","kind":"string","line":[35,35],"text":"failed to build/load index"}
{"file":"src/cli/serve.rs","kind":"comment","line":[37,37],"text":"Flush any dirty mounts to disk (projects that were indexed, not loaded)"}
{"file":"src/cli/serve.rs","kind":"string","line":[41,41],"text":"mount table lock poisoned: {e}"}
{"file":"src/cli/serve.rs","kind":"string","line":[45,45],"text":"failed to flush {}"}
{"file":"src/cli/serve.rs","kind":"comment","line":[50,51],"text":"Spawn event loop AFTER build (needs mount_table and db)\nBut notify watchers are already initialized and watching during build"}
{"file":"src/cli/serve.rs","kind":"string","line":[58,58],"text":"event loop error: {}"}
{"file":"src/cli/serve.rs","kind":"comment","line":[63,63],"text":"Start the tokio runtime"}
{"file":"src/cli/serve.rs","kind":"string","line":[64,64],"text":"failed to create tokio runtime"}
{"file":"src/cli/serve.rs","kind":"string","line":[67,67],"text":"starting MCP server on stdio"}
{"file":"src/index/format.rs","kind":"docstring","line":[3,3],"text":"`index.json` manifest — top-level metadata for a `.codeindex/` directory."}
{"file":"src/index/format.rs","kind":"docstring","line":[12,12],"text":"One line in `files.jsonl` — metadata for a single indexed file."}
{"file":"src/index/format.rs","kind":"docstring","line":[21,21],"text":"File title extracted from the source (e.g., first heading, module doc)."}
{"file":"src/index/format.rs","kind":"docstring","line":[24,24],"text":"File description extracted from the source (e.g., docstring, frontmatter)."}
{"file":"src/index/format.rs","kind":"docstring","line":[29,29],"text":"One line in `symbols.jsonl` — a symbol extracted from the AST."}
{"file":"src/index/format.rs","kind":"docstring","line":[48,48],"text":"One line in `texts.jsonl` — a text block (docstring, comment, etc.)."}
{"file":"src/index/format.rs","kind":"docstring","line":[61,61],"text":"One line in `references.jsonl` — a reference to a symbol (call, import, type, etc.)."}
{"file":"src/index/format.rs","kind":"docstring","line":[64,64],"text":"File containing this reference"}
{"file":"src/index/format.rs","kind":"docstring","line":[66,66],"text":"Symbol being referenced (e.g. \"os.path.join\", \"MyClass\", \"fetch\")"}
{"file":"src/index/format.rs","kind":"docstring","line":[68,68],"text":"Kind of reference: \"call\", \"import\", \"type_annotation\", \"instantiation\", \"definition\""}
{"file":"src/index/format.rs","kind":"docstring","line":[70,70],"text":"Line range [start, end] where this reference appears (1-based)"}
{"file":"src/index/format.rs","kind":"docstring","line":[72,72],"text":"Optional: enclosing symbol where this reference appears (e.g. \"MyClass.method\")"}
{"file":"src/index/format.rs","kind":"docstring","line":[75,75],"text":"Project path (relative from workspace root, empty for root project)"}
{"file":"src/index/reader.rs","kind":"docstring","line":[9,9],"text":"Convenience alias for the tuple returned by `read_index`."}
{"file":"src/index/reader.rs","kind":"docstring","line":[18,19],"text":"Read an existing `.codeindex/` directory from disk.\nReturns the manifest, files, symbols, texts, and references."}
{"file":"src/index/reader.rs","kind":"string","line":[23,23],"text":"failed to read index.json"}
{"file":"src/index/reader.rs","kind":"string","line":[24,24],"text":"failed to parse index.json"}
{"file":"src/index/reader.rs","kind":"string","line":[27,27],"text":"failed to read files.jsonl"}
{"file":"src/index/reader.rs","kind":"string","line":[30,30],"text":"failed to read symbols.jsonl"}
{"file":"src/index/reader.rs","kind":"string","line":[32,32],"text":"failed to read texts.jsonl"}
{"file":"src/index/reader.rs","kind":"comment","line":[34,34],"text":"References are optional for backward compatibility with older indexes"}
{"file":"src/index/reader.rs","kind":"docstring","line":[40,40],"text":"Read a JSONL file into a Vec of deserialized items."}
{"file":"src/index/reader.rs","kind":"string","line":[52,52],"text":"failed to parse line {} of {}"}
{"file":"src/index/writer.rs","kind":"docstring","line":[9,9],"text":"Write a complete `.codeindex/` directory to disk."}
{"file":"src/index/writer.rs","kind":"docstring","line":[11,13],"text":"Note: Data is expected to be pre-sorted from the database export\n(files by path, symbols/texts by file then line). This avoids\nmemory-intensive copies for large repositories."}
{"file":"src/index/writer.rs","kind":"comment","line":[22,22],"text":"Create the output directory"}
{"file":"src/index/writer.rs","kind":"comment","line":[25,25],"text":"Write index.json (pretty-printed)"}
{"file":"src/index/writer.rs","kind":"comment","line":[30,30],"text":"Write JSONL files directly - data is pre-sorted from DB export"}
{"file":"src/index/writer.rs","kind":"docstring","line":[39,39],"text":"Write a slice of serializable items as JSONL (one JSON object per line)."}
{"file":"src/lib.rs","kind":"string","line":[21,21],"text":"target/.rustc_info.json"}
{"file":"src/lib.rs","kind":"comment","line":[23,23],"text":"matched() - what handler.rs uses"}
{"file":"src/lib.rs","kind":"comment","line":[25,25],"text":"matched_path_or_any_parents() - checks parent dirs too"}
{"file":"src/lib.rs","kind":"string","line":[28,28],"text":"matched: {:?}"}
{"file":"src/lib.rs","kind":"string","line":[29,29],"text":"matched_path_or_any_parents: {:?}"}
{"file":"src/lib.rs","kind":"string","line":[33,33],"text":"target/ files should be ignored via matched_path_or_any_parents"}
{"file":"src/main.rs","kind":"string","line":[10,10],"text":"Portable, composable code index\\n\\nhttps://codeix.dev"}
{"file":"src/main.rs","kind":"docstring","line":[19,19],"text":"Build the .codeindex/ for discovered projects"}
{"file":"src/main.rs","kind":"docstring","line":[21,21],"text":"Root directory to scan (defaults to current dir)"}
{"file":"src/main.rs","kind":"docstring","line":[25,25],"text":"Start the MCP server (default when no subcommand given)"}
{"file":"src/main.rs","kind":"docstring","line":[27,27],"text":"Root directory (defaults to current dir)"}
{"file":"src/main.rs","kind":"docstring","line":[30,30],"text":"Disable file watching"}
{"file":"src/main.rs","kind":"comment","line":[45,45],"text":"Interactive: no subcommand given, print help and exit"}
{"file":"src/main.rs","kind":"comment","line":[49,49],"text":"Piped stdin (e.g. MCP client): default to serve"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[13,14],"text":"Built-in gitignore patterns (always applied).\nThese are either internal directories, IDE config, or OS cruft."}
{"file":"src/mount/mod.rs","kind":"comment","line":[16,16],"text":"Git internals (but .git itself is used for project detection)"}
{"file":"src/mount/mod.rs","kind":"comment","line":[18,18],"text":"Our own output"}
{"file":"src/mount/mod.rs","kind":"comment","line":[20,20],"text":"Editor/IDE directories"}
{"file":"src/mount/mod.rs","kind":"comment","line":[24,24],"text":"OS cruft"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[30,30],"text":"Mount mode determines whether the index can be written to."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[33,33],"text":"Read-write: acquires exclusive flock, allows modifications."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[35,35],"text":"Read-only: no lock, index data is immutable."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[39,40],"text":"Check if an EventKind represents a removal operation.\nUsed to determine if we can canonicalize the path (removed files can't be canonicalized)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[48,49],"text":"Filesystem events emitted to external consumers (handler/DB).\nThese are the result of processing raw notify events through mount rules."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[52,52],"text":"A file was discovered or modified."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[54,54],"text":"Absolute path to the mount root."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[56,56],"text":"Path relative to mount root."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[59,59],"text":"A file was deleted."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[61,61],"text":"Absolute path to the mount root."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[63,63],"text":"Path relative to mount root."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[66,66],"text":"A subproject (.git/ directory) was discovered."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[68,68],"text":"Absolute path to the subproject root (parent of .git/)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[73,73],"text":"Event with mount identity attached (avoids lookup in handler)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[76,76],"text":"A single mounted directory with its index."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[78,78],"text":"Root directory of the mount."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[80,80],"text":"Mount mode (read-write or read-only)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[82,82],"text":"File lock handle (only present for ReadWrite mounts)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[84,84],"text":"Whether the index has been modified and needs flushing."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[86,87],"text":"Gitignore rules for this mount (built during walk, used by watcher).\nNone until walk() is called."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[89,89],"text":"All gitignore files discovered (for rebuilding when new ones are added)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[91,91],"text":"File system watcher (only present for ReadWrite mounts)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[93,93],"text":"Directories currently being watched."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[109,109],"text":"Create a new read-only mount (no lock, no watcher).","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[125,126],"text":"Create a new read-write mount with exclusive flock.\nDoes NOT start notify - call `init_notify()` separately.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[165,165],"text":"Initialize gitignore with .git/info/exclude and root .gitignore.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[184,184],"text":"Build gitignore from all tracked files plus built-in patterns.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[207,207],"text":"Handle a filesystem event (from walker or notify).","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[209,213],"text":"This is the central handler that applies ALL rules:\n- Gitignore filtering\n- Project detection (.git/)\n- .gitignore file updates\n- Watch management","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[215,217],"text":"Takes notify's `EventKind` directly - both walker and notify use the same type.\nReturns an external event if this should be forwarded to consumers.\nReturns None for event types we don't care about.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[333,333],"text":"Add a .gitignore file to the rules.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[343,343],"text":"Remove watch for a directory.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[352,352],"text":"Walk all files in this mount, emitting events via callback.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[354,355],"text":"This is a dumb walker - it just iterates and calls on_fs_event for each entry.\nAll the smart logic (gitignore, skip entries, project detection) is in on_fs_event.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[357,357],"text":"After walk completes, the built gitignore is stored for use by the watcher.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[418,418],"text":"Initialize the notify file system watcher for this mount.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[420,421],"text":"Must be called BEFORE walk() so that DirCreated events can add directories.\nDoes nothing for read-only mounts.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[423,424],"text":"Events are sent to the provided channel with mount root attached,\navoiding the need for mount lookup in the handler.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[447,447],"text":"Watch a directory (non-recursive).","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[461,461],"text":"Get the number of watched directories.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[466,466],"text":"Check if a path should be ignored according to gitignore rules.","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[468,468],"text":"Returns false if gitignore hasn't been built yet (walk() not called).","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[478,478],"text":"Get a reference to the gitignore matcher (if built).","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[483,483],"text":"Mark this mount as dirty (needs flushing).","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[488,488],"text":"Clear the dirty flag (after flushing).","parent":"Mount"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[503,503],"text":"Table of mounted directories."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[506,506],"text":"Root of the workspace (where codeix was launched)."}
{"file":"src/mount/mod.rs","kind":"docstring","line":[512,512],"text":"Create a new mount table with the given workspace root.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[520,520],"text":"Get the workspace root.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[525,526],"text":"Compute the relative project path from workspace root.\nReturns empty string for the root project.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[534,535],"text":"Get the absolute path for a relative project path.\nReturns None if the project is not mounted.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[551,551],"text":"Check if a path is already mounted (exact match, not prefix).","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[556,556],"text":"Mount a directory, trying RW first, falling back to RO if lock is held.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[558,558],"text":"Returns the mount and its mode. Use this when you want best-effort RW.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[591,591],"text":"Mount a directory in read-write mode (acquires exclusive lock).","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[607,607],"text":"Mount a directory in read-only mode (no lock).","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[623,624],"text":"Find the mount that contains a given path (longest prefix match).\nCanonicalizes the path first to handle symlinks.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[630,632],"text":"Find the mount that contains a given path (longest prefix match).\nAssumes the path is already canonical - use for hot paths to avoid\nrepeated canonicalization overhead.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[641,642],"text":"Find the mount that contains a given path (mutable, longest prefix match).\nCanonicalizes the path first to handle symlinks.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[651,653],"text":"Find the mount that contains a given path (mutable, longest prefix match).\nAssumes the path is already canonical - use for hot paths to avoid\nrepeated canonicalization overhead.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[666,666],"text":"Unmount a directory (releases lock if held).","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[679,679],"text":"Iterate over all mounts.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[684,684],"text":"Iterate over all mounts (mutable).","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[689,689],"text":"Mark a path's mount as dirty.","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"docstring","line":[699,699],"text":"Mark a path's mount as dirty (assumes path is already canonical).","parent":"MountTable"}
{"file":"src/mount/mod.rs","kind":"comment","line":[725,725],"text":".codeindex/index.json should exist"}
{"file":"src/mount/mod.rs","kind":"string","line":[726,726],"text":".codeindex/index.json"}
{"file":"src/mount/mod.rs","kind":"comment","line":[749,749],"text":"File in subdir should match subdir mount"}
{"file":"src/mount/mod.rs","kind":"comment","line":[759,759],"text":"File in root should match root mount"}
{"file":"src/mount/mod.rs","kind":"comment","line":[810,810],"text":"Create .gitignore"}
{"file":"src/mount/mod.rs","kind":"comment","line":[813,813],"text":"Create files"}
{"file":"src/mount/mod.rs","kind":"string","line":[815,815],"text":"fn main() {}"}
{"file":"src/mount/mod.rs","kind":"comment","line":[825,825],"text":"Collect walked files"}
{"file":"src/mount/mod.rs","kind":"comment","line":[836,836],"text":"Should include src/main.rs"}
{"file":"src/mount/mod.rs","kind":"comment","line":[839,839],"text":"Should NOT include ignored files"}
{"file":"src/mount/mod.rs","kind":"comment","line":[846,847],"text":"Issue #36: symlinks in node_modules caused CPU spin\nVerify that follow_links(false) prevents infinite loops"}
{"file":"src/mount/mod.rs","kind":"comment","line":[850,850],"text":"Create a directory structure with symlinks"}
{"file":"src/mount/mod.rs","kind":"comment","line":[854,854],"text":"Create a symlink pointing to parent (would cause infinite loop if followed)"}
{"file":"src/mount/mod.rs","kind":"comment","line":[858,858],"text":"Symlink to parent directory"}
{"file":"src/mount/mod.rs","kind":"comment","line":[860,860],"text":"Symlink to self"}
{"file":"src/mount/mod.rs","kind":"comment","line":[873,873],"text":"Walk should complete without hanging (symlinks not followed)"}
{"file":"src/mount/mod.rs","kind":"comment","line":[884,884],"text":"Should find the real file"}
{"file":"src/mount/mod.rs","kind":"comment","line":[887,887],"text":"Should NOT have followed symlinks (no duplicates or infinite recursion)"}
{"file":"src/mount/mod.rs","kind":"comment","line":[896,896],"text":"Verify walk adds watches internally (no DirAdded events emitted)"}
{"file":"src/mount/mod.rs","kind":"string","line":[902,902],"text":"fn main() {}"}
{"file":"src/mount/mod.rs","kind":"string","line":[903,903],"text":"src/components/button.rs"}
{"file":"src/mount/mod.rs","kind":"string","line":[903,903],"text":"// button"}
{"file":"src/mount/mod.rs","kind":"comment","line":[906,906],"text":"RW to get watcher"}
{"file":"src/mount/mod.rs","kind":"comment","line":[910,910],"text":"Init watcher"}
{"file":"src/mount/mod.rs","kind":"comment","line":[926,926],"text":"Should have files"}
{"file":"src/mount/mod.rs","kind":"comment","line":[929,930],"text":"Should have watches registered internally\nroot, src, components, tests"}
{"file":"src/mount/mod.rs","kind":"comment","line":[935,935],"text":"Verify gitignore is available immediately after mounting"}
{"file":"src/mount/mod.rs","kind":"comment","line":[937,937],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/mount/mod.rs","kind":"string","line":[942,942],"text":"fn main() {}"}
{"file":"src/mount/mod.rs","kind":"comment","line":[949,949],"text":"Gitignore is built during mount creation"}
{"file":"src/mount/mod.rs","kind":"comment","line":[952,952],"text":"Can use is_ignored() for watcher filtering"}
{"file":"src/mount/mod.rs","kind":"comment","line":[960,960],"text":"Verify nested .gitignore files are respected"}
{"file":"src/mount/mod.rs","kind":"comment","line":[963,963],"text":"Root .gitignore"}
{"file":"src/mount/mod.rs","kind":"comment","line":[966,966],"text":"Nested directory with its own .gitignore"}
{"file":"src/mount/mod.rs","kind":"comment","line":[970,970],"text":"Create files"}
{"file":"src/mount/mod.rs","kind":"string","line":[972,972],"text":"// code"}
{"file":"src/mount/mod.rs","kind":"string","line":[975,975],"text":"subdir/local_ignore/secret.txt"}
{"file":"src/mount/mod.rs","kind":"comment","line":[992,992],"text":"Should include code.rs"}
{"file":"src/mount/mod.rs","kind":"comment","line":[995,995],"text":"Should NOT include .log files (from root .gitignore)"}
{"file":"src/mount/mod.rs","kind":"comment","line":[998,998],"text":"Should NOT include local_ignore/ (from nested .gitignore)"}
{"file":"src/parser/c_lang.rs","kind":"docstring","line":[1,1],"text":"C symbol and text extraction."}
{"file":"src/parser/c_lang.rs","kind":"docstring","line":[9,9],"text":"C-specific stopwords (keywords, common types, etc.)"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[21,21],"text":"Primitive types"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[30,30],"text":"Common standard types"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[35,35],"text":"Common macros and constants"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[38,38],"text":"Common variable patterns"}
{"file":"src/parser/c_lang.rs","kind":"docstring","line":[48,48],"text":"Filter C-specific stopwords from extracted tokens."}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[54,54],"text":"Filter uppercase constants"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[85,85],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[162,162],"text":"Check for static (file-scoped)"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[168,168],"text":"Extract tokens from function body"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[192,193],"text":"Top-level declarations: variables, function prototypes, extern declarations\nSkip if inside a function body (we only want top-level)"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[205,205],"text":"Walk declarators"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[210,210],"text":"Function prototype"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[215,215],"text":"Prototypes don't have a body, so no tokens"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[289,289],"text":"Anonymous struct/union, skip symbol but recurse for comments"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[313,313],"text":"Extract fields"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[373,373],"text":"Extract enum constants"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[401,401],"text":"The typedef name is typically the last declarator"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[426,426],"text":"Strip < > or \" \""}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[476,476],"text":"*name — recurse into the declarator"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[487,487],"text":"parenthesized_declarator"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[488,488],"text":"(name) — look inside"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[505,505],"text":"storage_class_specifier"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[524,524],"text":"symbol not found: {name}"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[529,535],"text":"int add(int a, int b) {\n    return a + b;\n}\n\nstatic void helper() {\n    printf(\\\"helper\\\");\n}"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[540,540],"text":"Token extraction is enabled (may be None if body has no tokens after filtering)"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[549,552],"text":"struct Point {\n    int x;\n    int y;\n};"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[568,572],"text":"enum Status {\n    OK,\n    ERROR,\n    PENDING\n};"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[588,592],"text":"typedef int MyInt;\n\nint add(MyInt a, MyInt b) {\n    return a + b;\n}"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[595,595],"text":"Function should definitely be extracted"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[602,606],"text":"int global = 100;\nstatic int file_scoped = 200;\nextern int external;\n\n#define MAX_SIZE 1000"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[622,623],"text":"#include <stdio.h>\n#include \\\"myheader.h\\\""}
{"file":"src/parser/c_lang.rs","kind":"string","line":[635,636],"text":"#define PI 3.14159\n#define MAX(a, b) ((a) > (b) ? (a) : (b))"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[648,652],"text":"union Data {\n    int i;\n    float f;\n    char str[20];\n};"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[656,656],"text":"unions mapped to struct"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[664,666],"text":"/* Block comment */\n// Single line comment\nint foo() { return 0; }"}
{"file":"src/parser/c_lang.rs","kind":"string","line":[673,674],"text":"int add(int a, int b);\nextern void print(const char* msg);"}
{"file":"src/parser/c_lang.rs","kind":"comment","line":[679,679],"text":"Prototypes don't have bodies, so no tokens"}
{"file":"src/parser/cpp.rs","kind":"docstring","line":[1,1],"text":"C++ symbol and text extraction."}
{"file":"src/parser/cpp.rs","kind":"docstring","line":[3,3],"text":"Extends C extraction with classes, namespaces, templates, and access specifiers."}
{"file":"src/parser/cpp.rs","kind":"docstring","line":[11,11],"text":"C++-specific stopwords (C keywords + C++ keywords, types, etc.)"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[13,13],"text":"C keywords"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[23,23],"text":"C++ keywords"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[43,43],"text":"Primitive types"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[53,53],"text":"STL common"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[67,67],"text":"Common patterns"}
{"file":"src/parser/cpp.rs","kind":"docstring","line":[78,78],"text":"Filter C++-specific stopwords from extracted tokens."}
{"file":"src/parser/cpp.rs","kind":"comment","line":[84,84],"text":"Filter uppercase constants"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[117,117],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[158,158],"text":"Recurse into the templated declaration"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[178,178],"text":"`using Foo = ...;`"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[261,261],"text":"Extract tokens from function body"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[286,286],"text":"Skip declarations inside function bodies"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[323,323],"text":"Declarations don't have bodies"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[440,440],"text":"Walk class body with access tracking"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[442,442],"text":"Default access: private for class, public for struct"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[514,514],"text":"Extract enum values"}
{"file":"src/parser/cpp.rs","kind":"string","line":[526,526],"text":"{full_name}.{const_name}"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[552,552],"text":"Anonymous namespace"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[675,675],"text":"`using namespace std;` or `using std::string;`"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[752,752],"text":"namespace::name — use the full qualified name"}
{"file":"src/parser/cpp.rs","kind":"string","line":[764,764],"text":"parenthesized_declarator"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[775,775],"text":"operator+, operator<< etc."}
{"file":"src/parser/cpp.rs","kind":"string","line":[785,785],"text":"storage_class_specifier"}
{"file":"src/parser/cpp.rs","kind":"string","line":[804,804],"text":"symbol not found: {name}"}
{"file":"src/parser/cpp.rs","kind":"string","line":[809,815],"text":"int add(int a, int b) {\n    return a + b;\n}\n\nstatic void helper() {\n    std::cout << \\\"helper\\\";\n}"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[820,820],"text":"Token extraction is enabled (may be None if body has no tokens after filtering)"}
{"file":"src/parser/cpp.rs","kind":"string","line":[829,842],"text":"class Person {\npublic:\n    Person(std::string name) {}\n\n    std::string getName() const {\n        return name;\n    }\n\nprivate:\n    void privateMethod() {}\n\nprotected:\n    void helper() {}\n};"}
{"file":"src/parser/cpp.rs","kind":"string","line":[861,867],"text":"struct Point {\n    void setX(int value) {}\n    void setY(int value) {}\n\nprivate:\n    void hidden() {}\n};"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[874,874],"text":"struct default"}
{"file":"src/parser/cpp.rs","kind":"string","line":[882,889],"text":"namespace utils {\n    void helper() {}\n\n    class Tool {\n    public:\n        void run() {}\n    };\n}"}
{"file":"src/parser/cpp.rs","kind":"string","line":[907,916],"text":"enum Color {\n    RED,\n    GREEN,\n    BLUE\n};\n\nenum class Status {\n    OK,\n    ERROR\n};"}
{"file":"src/parser/cpp.rs","kind":"string","line":[931,940],"text":"template<typename T>\nclass Container {\npublic:\n    void add(T item) {}\n};\n\ntemplate<typename T>\nT max(T a, T b) {\n    return (a > b) ? a : b;\n}"}
{"file":"src/parser/cpp.rs","kind":"string","line":[955,957],"text":"using namespace std;\nusing std::string;\nusing MyInt = int;"}
{"file":"src/parser/cpp.rs","kind":"string","line":[962,962],"text":"namespace std"}
{"file":"src/parser/cpp.rs","kind":"string","line":[975,976],"text":"#include <iostream>\n#include \\\"myheader.h\\\""}
{"file":"src/parser/cpp.rs","kind":"string","line":[988,990],"text":"namespace MyNamespace {\n    void helper() {}\n}"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[993,993],"text":"Named namespace should be extracted"}
{"file":"src/parser/cpp.rs","kind":"comment","line":[998,998],"text":"Functions inside namespaces might be classified as methods"}
{"file":"src/parser/cpp.rs","kind":"string","line":[1004,1006],"text":"/* Block comment */\n// Single line comment\nclass Foo {};"}
{"file":"src/parser/csharp.rs","kind":"docstring","line":[1,1],"text":"C# symbol and text extraction."}
{"file":"src/parser/csharp.rs","kind":"docstring","line":[9,9],"text":"C#-specific stopwords (keywords, common types, etc.)"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[41,41],"text":"Primitive types"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[56,56],"text":"Common framework types"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[74,74],"text":"Common variable patterns"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[81,81],"text":"Test framework (NUnit, xUnit, MSTest) - lowercase for comparison"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[91,91],"text":"Common methods - lowercase for comparison"}
{"file":"src/parser/csharp.rs","kind":"docstring","line":[100,100],"text":"Filter C#-specific stopwords from extracted tokens."}
{"file":"src/parser/csharp.rs","kind":"comment","line":[106,106],"text":"Filter uppercase constants"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[137,137],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/csharp.rs","kind":"string","line":[157,157],"text":"interface_declaration"}
{"file":"src/parser/csharp.rs","kind":"string","line":[179,179],"text":"namespace_declaration"}
{"file":"src/parser/csharp.rs","kind":"string","line":[179,179],"text":"file_scoped_namespace_declaration"}
{"file":"src/parser/csharp.rs","kind":"string","line":[186,186],"text":"constructor_declaration"}
{"file":"src/parser/csharp.rs","kind":"string","line":[206,206],"text":"verbatim_string_literal"}
{"file":"src/parser/csharp.rs","kind":"string","line":[207,207],"text":"interpolated_string_expression"}
{"file":"src/parser/csharp.rs","kind":"string","line":[258,258],"text":" : {}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[261,261],"text":"{kind} {name}{type_params}{bases}"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[269,269],"text":"Extract tokens from type body"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[285,285],"text":"Walk body"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[335,335],"text":"Extract enum members"}
{"file":"src/parser/csharp.rs","kind":"string","line":[339,339],"text":"enum_member_declaration"}
{"file":"src/parser/csharp.rs","kind":"string","line":[347,347],"text":"{full_name}.{member_name}"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[394,394],"text":"Walk namespace body"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[410,410],"text":"File-scoped namespace: declarations are siblings, not children of body"}
{"file":"src/parser/csharp.rs","kind":"string","line":[411,411],"text":"file_scoped_namespace_declaration"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[412,412],"text":"Walk all siblings after this node"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[459,459],"text":"Extract tokens from method body"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[498,498],"text":"Extract tokens from constructor body"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[569,569],"text":"Walk variable declarators"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[635,635],"text":"Delegates don't have bodies"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[644,644],"text":"`using System.Linq;` or `using Foo = System.Bar;`"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[663,663],"text":"`using Alias = Namespace.Type;`"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[666,666],"text":"The actual type is the next sibling"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[702,702],"text":"XML doc comment"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[754,754],"text":"Check for modifiers list pattern (some tree-sitter versions)"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[765,765],"text":"C# default"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[778,778],"text":"Fallback: check the raw text"}
{"file":"src/parser/csharp.rs","kind":"string","line":[792,792],"text":"symbol not found: {name}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[797,812],"text":"public class Person\n{\n    private string name;\n\n    public Person(string name)\n    {\n        this.name = name;\n    }\n\n    public string GetName()\n    {\n        return name;\n    }\n\n    private void Helper() {}\n}"}
{"file":"src/parser/csharp.rs","kind":"comment","line":[818,819],"text":"Token extraction extracts identifiers from class body\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/csharp.rs","kind":"string","line":[835,839],"text":"public interface IRunnable\n{\n    void Run();\n    int Calculate(int x);\n}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[849,853],"text":"public struct Point\n{\n    public int X;\n    public int Y;\n}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[866,871],"text":"public enum Status\n{\n    Active,\n    Inactive,\n    Pending\n}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[884,890],"text":"namespace MyApp.Utils\n{\n    public class Helper\n    {\n        public void Run() {}\n    }\n}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[900,900],"text":"MyApp.Utils.Helper.Run"}
{"file":"src/parser/csharp.rs","kind":"string","line":[906,910],"text":"public class Config\n{\n    public string Name { get; set; }\n    private int version;\n}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[924,928],"text":"public class Constants\n{\n    public const int MAX_SIZE = 100;\n    private static readonly string Version = \\\"1.0\\\";\n}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[942,944],"text":"using System;\nusing System.Collections.Generic;\nusing System.Linq;"}
{"file":"src/parser/csharp.rs","kind":"string","line":[952,952],"text":"System.Collections.Generic"}
{"file":"src/parser/csharp.rs","kind":"string","line":[962,962],"text":"public delegate void EventHandler(object sender);"}
{"file":"src/parser/csharp.rs","kind":"string","line":[972,978],"text":"public class Foo\n{\n    public void PublicMethod() {}\n    private void PrivateMethod() {}\n    protected void ProtectedMethod() {}\n    internal void InternalMethod() {}\n}"}
{"file":"src/parser/csharp.rs","kind":"string","line":[996,1002],"text":"/// <summary>\n/// XML doc comment\n/// </summary>\npublic class Documented {}\n\n// Single line\n/* Block comment */"}
{"file":"src/parser/go.rs","kind":"docstring","line":[1,1],"text":"Go symbol and text extraction."}
{"file":"src/parser/go.rs","kind":"comment","line":[29,29],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/go.rs","kind":"comment","line":[45,45],"text":"handled recursively"}
{"file":"src/parser/go.rs","kind":"string","line":[64,64],"text":"interpreted_string_literal"}
{"file":"src/parser/go.rs","kind":"comment","line":[95,95],"text":"Extract tokens from function body for FTS"}
{"file":"src/parser/go.rs","kind":"comment","line":[119,119],"text":"Extract receiver type: `func (r *Receiver) Method()`"}
{"file":"src/parser/go.rs","kind":"comment","line":[122,123],"text":"The receiver is a parameter_list with one entry\nTry to extract the type name"}
{"file":"src/parser/go.rs","kind":"comment","line":[125,125],"text":"Strip parens and pointer/reference"}
{"file":"src/parser/go.rs","kind":"comment","line":[138,138],"text":"Extract tokens from method body for FTS"}
{"file":"src/parser/go.rs","kind":"comment","line":[175,175],"text":"`type (...)` block or `type Foo ...`"}
{"file":"src/parser/go.rs","kind":"comment","line":[201,201],"text":"Determine kind from the type definition"}
{"file":"src/parser/go.rs","kind":"comment","line":[222,222],"text":"For structs, extract fields"}
{"file":"src/parser/go.rs","kind":"string","line":[229,229],"text":"field_declaration_list"}
{"file":"src/parser/go.rs","kind":"comment","line":[252,252],"text":"Extract comments inside struct"}
{"file":"src/parser/go.rs","kind":"comment","line":[258,258],"text":"For interfaces, extract method signatures"}
{"file":"src/parser/go.rs","kind":"comment","line":[316,316],"text":"Handle multiple names in one spec: `var a, b, c int`"}
{"file":"src/parser/go.rs","kind":"comment","line":[320,320],"text":"First identifier is captured by field \"name\", subsequent ones need manual check"}
{"file":"src/parser/go.rs","kind":"comment","line":[325,325],"text":"already captured"}
{"file":"src/parser/go.rs","kind":"comment","line":[373,373],"text":"Also handle single import: `import \"fmt\"`"}
{"file":"src/parser/go.rs","kind":"docstring","line":[443,443],"text":"Go-specific stopwords to filter from tokens."}
{"file":"src/parser/go.rs","kind":"comment","line":[445,445],"text":"Keywords and builtins"}
{"file":"src/parser/go.rs","kind":"comment","line":[461,461],"text":"Common short names"}
{"file":"src/parser/go.rs","kind":"comment","line":[481,481],"text":"Test framework"}
{"file":"src/parser/go.rs","kind":"docstring","line":[485,485],"text":"Filter Go-specific tokens from the extracted token string."}
{"file":"src/parser/go.rs","kind":"string","line":[503,503],"text":"symbol not found: {name}"}
{"file":"src/parser/go.rs","kind":"string","line":[508,516],"text":"package main\n\nfunc Hello(name string) string {\n    return \\\"Hello, \\\" + name\n}\n\nfunc privateHelper() {\n    println(\\\"private\\\")\n}"}
{"file":"src/parser/go.rs","kind":"comment","line":[521,522],"text":"Tokens contain identifiers from function body\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/go.rs","kind":"string","line":[531,541],"text":"package main\n\ntype Person struct {\n    Name string\n}\n\nfunc (p *Person) Greet() string {\n    return \\\"Hello, \\\" + p.Name\n}\n\nfunc (p Person) privateMethod() {}"}
{"file":"src/parser/go.rs","kind":"string","line":[558,564],"text":"package main\n\ntype Point struct {\n    X int\n    Y int\n    z int\n}"}
{"file":"src/parser/go.rs","kind":"string","line":[580,585],"text":"package main\n\ntype Reader interface {\n    Read() (int, error)\n    close()\n}"}
{"file":"src/parser/go.rs","kind":"comment","line":[592,594],"text":"Interface methods may or may not be extracted depending on implementation\nJust verify the interface itself is extracted correctly\nat least package + interface"}
{"file":"src/parser/go.rs","kind":"string","line":[599,605],"text":"package main\n\nvar GlobalVar = 100\nvar privateVar = 200\n\nconst MaxSize = 1000\nconst minSize = 10"}
{"file":"src/parser/go.rs","kind":"string","line":[622,628],"text":"package main\n\nimport \\\"fmt\\\"\nimport (\n    \\\"os\\\"\n    io \\\"io/ioutil\\\"\n)"}
{"file":"src/parser/go.rs","kind":"string","line":[643,646],"text":"package main\n\ntype UserID int\ntype Handler func(string) error"}
{"file":"src/parser/go.rs","kind":"string","line":[658,660],"text":"package mypackage\n\nfunc Foo() {}"}
{"file":"src/parser/go.rs","kind":"string","line":[669,674],"text":"package main\n\n// Single line comment\nfunc Helper() {}\n\n/* Block comment */"}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[1,1],"text":"Shared helpers for tree-sitter extraction across all languages."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[8,11],"text":"Universal stopwords filtered from token extraction.\nThese appear across most programming languages.\nLanguage-specific stopwords are handled in each parser.\nSingle-char identifiers are also filtered (< 2 chars)."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[13,13],"text":"Placeholder/example names"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[20,20],"text":"Test assertions"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[27,27],"text":"Control flow (9 languages)"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[38,38],"text":"Common keywords (7+ languages)"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[44,44],"text":"OOP keywords (5+ languages)"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[55,55],"text":"Exception handling (5+ languages)"}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[62,62],"text":"Get the text content of a tree-sitter node."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[69,69],"text":"Get the 1-based [start, end] line range for a node."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[71,71],"text":"tree-sitter is 0-based"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[73,74],"text":"When end_position().column == 0, the node ends at the start of the next line\n(e.g. line_comment includes trailing \\n), so the actual end line is the previous row."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[76,76],"text":"don't add 1, since it's actually the previous line"}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[83,83],"text":"Find a child node by its field name."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[88,88],"text":"Check if a text string is too trivial to index."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[94,94],"text":"Skip whitespace-only strings"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[98,99],"text":"Skip short strings that look like code identifiers rather than prose.\nProse typically contains spaces or is substantially longer."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[106,106],"text":"Collapse multiple whitespace characters into single spaces."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[124,124],"text":"Strip `///` or `//!` prefix from each line of a doc comment."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[143,143],"text":"Strip `/* */` delimiters and leading `*` from block comments."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[166,166],"text":"Strip surrounding quotes from string literals."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[168,168],"text":"Triple-quoted strings (Python, etc.)"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[175,175],"text":"Template literals (JS/TS)"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[179,179],"text":"Raw strings: r\"...\" or r#\"...\"#"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[188,188],"text":"Byte strings: b\"...\""}
{"file":"src/parser/helpers.rs","kind":"comment","line":[193,193],"text":"F-strings: f\"...\" (Python)"}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[211,211],"text":"Extract a comment node as a TextEntry (generic for C-style comments)."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[237,237],"text":"Hash-style comments (Python, Ruby, etc.)"}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[258,258],"text":"Extract a string literal node as a TextEntry."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[284,284],"text":"Push a symbol entry (convenience builder)."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[310,311],"text":"Extract a function/method signature: everything from start to opening `{` or `:`.\nCollapses whitespace."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[329,329],"text":"Extract identifier tokens from a tree-sitter node for FTS indexing."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[331,333],"text":"Recursively walks the AST to collect all identifier nodes, filters by\nlength (>= 2 chars) and universal stopwords, then returns as a\nspace-separated string."}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[335,335],"text":"Language parsers can apply additional filtering on the result."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[344,344],"text":"Filter stopwords, short tokens, and invalid identifiers"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[348,348],"text":"Must be valid identifier (alphanumeric + underscore, not starting with digit)"}
{"file":"src/parser/helpers.rs","kind":"docstring","line":[364,364],"text":"Recursively collect identifier text from AST nodes."}
{"file":"src/parser/helpers.rs","kind":"comment","line":[366,366],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[371,371],"text":"Collect identifier nodes (tree-sitter uses \"identifier\" for most languages)"}
{"file":"src/parser/helpers.rs","kind":"comment","line":[377,377],"text":"Recurse into children"}
{"file":"src/parser/java.rs","kind":"docstring","line":[1,1],"text":"Java symbol and text extraction."}
{"file":"src/parser/java.rs","kind":"docstring","line":[9,9],"text":"Java-specific stopwords (keywords and common patterns)"}
{"file":"src/parser/java.rs","kind":"comment","line":[28,28],"text":"Primitive types"}
{"file":"src/parser/java.rs","kind":"comment","line":[37,37],"text":"Common class names (typically imported)"}
{"file":"src/parser/java.rs","kind":"comment","line":[56,56],"text":"Common variable patterns"}
{"file":"src/parser/java.rs","kind":"docstring","line":[61,61],"text":"Filter Java-specific stopwords from extracted tokens."}
{"file":"src/parser/java.rs","kind":"comment","line":[67,67],"text":"Also filter out uppercase-only tokens (likely type names)"}
{"file":"src/parser/java.rs","kind":"comment","line":[98,98],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/java.rs","kind":"string","line":[112,112],"text":"interface_declaration"}
{"file":"src/parser/java.rs","kind":"string","line":[131,131],"text":"annotation_type_declaration"}
{"file":"src/parser/java.rs","kind":"string","line":[153,153],"text":"constructor_declaration"}
{"file":"src/parser/java.rs","kind":"comment","line":[210,210],"text":"Build signature"}
{"file":"src/parser/java.rs","kind":"comment","line":[219,219],"text":"Extract tokens from class body"}
{"file":"src/parser/java.rs","kind":"comment","line":[235,235],"text":"Walk class body"}
{"file":"src/parser/java.rs","kind":"comment","line":[274,274],"text":"Extract tokens from method body"}
{"file":"src/parser/java.rs","kind":"comment","line":[313,313],"text":"Extract tokens from constructor body"}
{"file":"src/parser/java.rs","kind":"comment","line":[340,340],"text":"Check for static final → constant"}
{"file":"src/parser/java.rs","kind":"comment","line":[350,350],"text":"Find declarators"}
{"file":"src/parser/java.rs","kind":"comment","line":[382,382],"text":"Get the import path"}
{"file":"src/parser/java.rs","kind":"comment","line":[447,447],"text":"package-private (no explicit modifier)"}
{"file":"src/parser/java.rs","kind":"comment","line":[451,451],"text":"default: package-private"}
{"file":"src/parser/java.rs","kind":"string","line":[471,471],"text":" extends {}"}
{"file":"src/parser/java.rs","kind":"string","line":[475,475],"text":" implements {}"}
{"file":"src/parser/java.rs","kind":"string","line":[478,478],"text":"{kind} {name}{type_params}{extends}{implements}"}
{"file":"src/parser/java.rs","kind":"string","line":[490,490],"text":"symbol not found: {name}"}
{"file":"src/parser/java.rs","kind":"string","line":[495,507],"text":"public class Person {\n    private String name;\n\n    public Person(String name) {\n        this.name = name;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    private void helper() {}\n}"}
{"file":"src/parser/java.rs","kind":"comment","line":[513,514],"text":"Token extraction extracts identifiers from class body\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/java.rs","kind":"string","line":[533,536],"text":"public interface Runnable {\n    void run();\n    default void start() {}\n}"}
{"file":"src/parser/java.rs","kind":"string","line":[546,550],"text":"public enum Status {\n    ACTIVE,\n    INACTIVE,\n    PENDING\n}"}
{"file":"src/parser/java.rs","kind":"string","line":[560,564],"text":"class Config {\n    public static final int MAX_SIZE = 100;\n    private int value;\n    protected String name;\n}"}
{"file":"src/parser/java.rs","kind":"string","line":[581,591],"text":"class Calculator {\n    public int add(int a, int b) {\n        return a + b;\n    }\n\n    protected double divide(double x, double y) {\n        return x / y;\n    }\n\n    private void log(String msg) {}\n}"}
{"file":"src/parser/java.rs","kind":"string","line":[607,609],"text":"import java.util.List;\nimport java.util.*;\nimport java.io.File;"}
{"file":"src/parser/java.rs","kind":"comment","line":[612,612],"text":"Check at least one import is extracted"}
{"file":"src/parser/java.rs","kind":"comment","line":[616,616],"text":"Check if we have any java.util imports"}
{"file":"src/parser/java.rs","kind":"string","line":[625,627],"text":"package com.example.app;\n\nclass Foo {}"}
{"file":"src/parser/java.rs","kind":"string","line":[636,638],"text":"class Foo {\n    void packagePrivate() {}\n}"}
{"file":"src/parser/java.rs","kind":"comment","line":[642,642],"text":"default = package-private"}
{"file":"src/parser/java.rs","kind":"string","line":[650,654],"text":"/** Javadoc comment */\nclass Documented {}\n\n// Single line\n/* Block comment */"}
{"file":"src/parser/javascript.rs","kind":"docstring","line":[1,1],"text":"JavaScript symbol and text extraction."}
{"file":"src/parser/javascript.rs","kind":"docstring","line":[9,9],"text":"JavaScript-specific stopwords (common variable names, keywords, etc.)"}
{"file":"src/parser/javascript.rs","kind":"docstring","line":[43,43],"text":"Filter JavaScript-specific stopwords from extracted tokens."}
{"file":"src/parser/javascript.rs","kind":"comment","line":[78,78],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/javascript.rs","kind":"string","line":[89,89],"text":"generator_function_declaration"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[94,94],"text":"handled recursively"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[103,103],"text":"Recurse into the exported declaration"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[132,132],"text":"Recurse into children"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[184,184],"text":"Extract tokens from function body"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[227,227],"text":"Build class signature with extends"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[236,236],"text":"Extract tokens from class body (for class-level properties/static blocks)"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[252,252],"text":"Walk class body"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[283,283],"text":"Check for static/get/set/async modifiers"}
{"file":"src/parser/javascript.rs","kind":"string","line":[328,328],"text":"{prefix}{name}{params}"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[344,344],"text":"Extract tokens from method body"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[380,380],"text":"Determine if const"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[387,387],"text":"Walk declarators"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[395,395],"text":"Only index simple identifiers, not destructuring patterns"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[401,401],"text":"Check if the value is a function/arrow function"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[431,431],"text":"Extract tokens from variable value (for arrow functions etc.)"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[453,453],"text":"Get the source module"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[468,468],"text":"Default import: `import foo from \"...\"`"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[484,484],"text":"`import { foo, bar as baz } from \"...\"`"}
{"file":"src/parser/javascript.rs","kind":"string","line":[494,494],"text":"{source_module}.{imp_name}"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[511,511],"text":"`import * as foo from \"...\"`"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[514,514],"text":"In some grammars, the identifier is a direct child"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[552,552],"text":"JSDoc comment"}
{"file":"src/parser/javascript.rs","kind":"string","line":[586,586],"text":"generator_function_declaration"}
{"file":"src/parser/javascript.rs","kind":"string","line":[589,589],"text":"async function*"}
{"file":"src/parser/javascript.rs","kind":"string","line":[590,590],"text":"async function"}
{"file":"src/parser/javascript.rs","kind":"string","line":[595,595],"text":"{prefix} {name}{params}"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[599,599],"text":"Check for extends clause"}
{"file":"src/parser/javascript.rs","kind":"string","line":[612,612],"text":"class {name}{extends}"}
{"file":"src/parser/javascript.rs","kind":"string","line":[624,624],"text":"symbol not found: {name}"}
{"file":"src/parser/javascript.rs","kind":"string","line":[629,639],"text":"function hello(name) {\n    return `Hello, ${name}!`;\n}\n\nasync function fetchData() {\n    return await fetch('/api');\n}\n\nfunction* generator() {\n    yield 1;\n}"}
{"file":"src/parser/javascript.rs","kind":"comment","line":[645,645],"text":"Token extraction is enabled (may be None if body has no tokens after filtering)"}
{"file":"src/parser/javascript.rs","kind":"string","line":[657,673],"text":"export class Person {\n    constructor(name) {\n        this.name = name;\n    }\n\n    greet() {\n        return `Hi, ${this.name}`;\n    }\n\n    static create() {\n        return new Person('default');\n    }\n\n    get fullName() {\n        return this.name;\n    }\n}"}
{"file":"src/parser/javascript.rs","kind":"string","line":[693,700],"text":"const MAX_SIZE = 100;\nlet debug = true;\nvar legacy = 'old';\n\nexport const API_KEY = 'secret';\n\nconst add = (a, b) => a + b;\nconst asyncFn = async (x) => x * 2;"}
{"file":"src/parser/javascript.rs","kind":"string","line":[721,724],"text":"import React from 'react';\nimport { useState, useEffect } from 'react';\nimport * as Utils from './utils';\nimport { render as renderDOM } from 'react-dom';"}
{"file":"src/parser/javascript.rs","kind":"string","line":[746,752],"text":"class Foo {\n    publicMethod() {}\n\n    _internalMethod() {}\n\n    #privateMethod() {}\n}"}
{"file":"src/parser/javascript.rs","kind":"string","line":[776,784],"text":"/**\n * JSDoc comment\n */\nfunction documented() {}\n\n// Single line comment\nfunction helper() {}\n\n/* Block comment */"}
{"file":"src/parser/languages.rs","kind":"docstring","line":[4,4],"text":"Return the tree-sitter [`Language`] for the given language name."}
{"file":"src/parser/languages.rs","kind":"docstring","line":[6,6],"text":"Languages are feature-gated — only grammars enabled at compile time are"}
{"file":"src/parser/languages.rs","kind":"comment","line":[43,44],"text":"Markdown uses custom parser (tree-sitter-md) with MarkdownParser,\nbut we still register the block language for consistency"}
{"file":"src/parser/languages.rs","kind":"string","line":[48,48],"text":"unsupported language: {name}"}
{"file":"src/parser/languages.rs","kind":"docstring","line":[52,52],"text":"Detect the language from a file extension."}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[1,1],"text":"Markdown symbol and text extraction using tree-sitter-md."}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[3,4],"text":"Headings are extracted as symbols with `kind=\"section\"` and parent relationships\nreflecting the document hierarchy. Fenced code blocks are extracted as text entries."}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[6,8],"text":"tree-sitter-md uses a two-tree architecture:\n- Block tree (`LANGUAGE`): document structure (headings, code blocks, paragraphs)\n- Inline trees (`INLINE_LANGUAGE`): inline content within blocks (text, emphasis, links)"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[17,17],"text":"Parse and extract symbols/texts from markdown using tree-sitter-md."}
{"file":"src/parser/markdown.rs","kind":"string","line":[25,25],"text":"failed to parse markdown: {}"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[30,30],"text":"Extract from block tree"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[34,34],"text":"Heading stack tracks (level, name) for building parent-child relationships"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[49,49],"text":"Walk the block tree to extract headings and code blocks."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[69,69],"text":"Recurse to children"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[78,78],"text":"Extract ATX-style heading (# heading)."}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[109,109],"text":"Extract Setext-style heading (underlined with === or ---)."}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[140,140],"text":"Extract fenced code block as text entry."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[148,148],"text":"Try to find code_fence_content child first"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[153,153],"text":"For code blocks, we don't filter as aggressively as other text types"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[173,173],"text":"Fallback: extract content between fence markers from raw text"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[194,195],"text":"Extract code content from fenced block raw text.\nStrips the opening and closing fence lines."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[202,202],"text":"Skip first line (opening fence) and last line (closing fence)"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[208,208],"text":"Find closing fence"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[222,222],"text":"Get heading text by extracting from child nodes."}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[224,225],"text":"For ATX headings, we look for `heading_content` or `inline` children.\nFor Setext headings, we look for `paragraph` children."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[231,231],"text":"ATX heading content - may include trailing # which we need to strip"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[236,236],"text":"Setext heading: first paragraph is the heading text"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[245,245],"text":"Fallback: extract from raw text and strip markdown syntax"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[250,251],"text":"Strip optional closing sequence of # from ATX heading.\nPer CommonMark spec, the closing # sequence must be preceded by a space."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[253,253],"text":"Find the last non-# character"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[256,257],"text":"Check if it ends with space followed by #\nThe closing sequence is: optional whitespace, one or more #, optional whitespace"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[260,260],"text":"Check if everything after the last space is just #"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[262,262],"text":"This is an optional closing sequence - strip it"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[270,270],"text":"Strip markdown heading markers (# prefix and underlines)."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[274,274],"text":"ATX: strip leading # and optional trailing #"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[276,276],"text":"Get just the first line (ATX headings are single line)"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[278,278],"text":"Strip leading #"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[280,280],"text":"Strip trailing # (markdown allows optional closing hashes)"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[285,285],"text":"Setext: strip underline (text is on first line)"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[293,293],"text":"Count ATX heading level (number of leading #)."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[295,295],"text":"Look for atx_h1_marker, atx_h2_marker, etc."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[300,300],"text":"Extract level from marker name: atx_h1_marker -> 1"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[309,309],"text":"Fallback: count leading # characters"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[315,315],"text":"Get Setext heading level (1 for ===, 2 for ---)."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[317,317],"text":"Look for setext_h1_underline or setext_h2_underline"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[327,327],"text":"Fallback: check for underline character in last line"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[337,337],"text":"Default to h1"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[340,340],"text":"Compute qualified name and parent for a heading based on the heading stack."}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[342,346],"text":"The stack maintains (level, qualified_name) pairs. When we encounter a heading at level N:\n1. Pop all headings at level >= N (they're no longer ancestors)\n2. The parent is the top of the stack (if any)\n3. Build qualified name as \"parent/name\" (or just \"name\" if no parent)\n4. Push (N, qualified_name) onto the stack"}
{"file":"src/parser/markdown.rs","kind":"docstring","line":[348,348],"text":"Returns (qualified_name, parent_qualified_name)."}
{"file":"src/parser/markdown.rs","kind":"comment","line":[354,354],"text":"Pop all headings at same or deeper level"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[363,363],"text":"Parent is the top of the stack (the nearest ancestor heading)"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[366,366],"text":"Build qualified name"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[372,372],"text":"Push current heading onto the stack"}
{"file":"src/parser/markdown.rs","kind":"string","line":[384,384],"text":"# Top Level\\n\\nSome content.\\n\\n## Sub Section\\n\\nMore content.\\n"}
{"file":"src/parser/markdown.rs","kind":"string","line":[388,388],"text":"Top Level"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[392,392],"text":"Qualified name includes parent path"}
{"file":"src/parser/markdown.rs","kind":"string","line":[393,393],"text":"Top Level/Sub Section"}
{"file":"src/parser/markdown.rs","kind":"string","line":[395,395],"text":"Top Level"}
{"file":"src/parser/markdown.rs","kind":"string","line":[401,401],"text":"# Chapter 1\\n## Section A\\n### Detail 1\\n### Detail 2\\n## Section B\\n# Chapter 2\\n"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[406,406],"text":"Chapter 1 has no parent"}
{"file":"src/parser/markdown.rs","kind":"string","line":[407,407],"text":"Chapter 1"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[410,410],"text":"Section A's parent is Chapter 1"}
{"file":"src/parser/markdown.rs","kind":"string","line":[411,411],"text":"Chapter 1/Section A"}
{"file":"src/parser/markdown.rs","kind":"string","line":[412,412],"text":"Chapter 1"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[414,414],"text":"Detail 1's parent is Section A (qualified)"}
{"file":"src/parser/markdown.rs","kind":"string","line":[415,415],"text":"Chapter 1/Section A/Detail 1"}
{"file":"src/parser/markdown.rs","kind":"string","line":[416,416],"text":"Chapter 1/Section A"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[418,418],"text":"Detail 2's parent is Section A (same level as Detail 1)"}
{"file":"src/parser/markdown.rs","kind":"string","line":[419,419],"text":"Chapter 1/Section A/Detail 2"}
{"file":"src/parser/markdown.rs","kind":"string","line":[420,420],"text":"Chapter 1/Section A"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[422,422],"text":"Section B's parent is Chapter 1 (goes back up)"}
{"file":"src/parser/markdown.rs","kind":"string","line":[423,423],"text":"Chapter 1/Section B"}
{"file":"src/parser/markdown.rs","kind":"string","line":[424,424],"text":"Chapter 1"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[426,426],"text":"Chapter 2 has no parent (new top-level)"}
{"file":"src/parser/markdown.rs","kind":"string","line":[427,427],"text":"Chapter 2"}
{"file":"src/parser/markdown.rs","kind":"string","line":[433,433],"text":"Heading One\\n===========\\n\\nSome text.\\n\\nHeading Two\\n-----------\\n"}
{"file":"src/parser/markdown.rs","kind":"string","line":[437,437],"text":"Heading One"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[440,440],"text":"Setext with --- is level 2, so parent is level 1"}
{"file":"src/parser/markdown.rs","kind":"string","line":[441,441],"text":"Heading One/Heading Two"}
{"file":"src/parser/markdown.rs","kind":"string","line":[442,442],"text":"Heading One"}
{"file":"src/parser/markdown.rs","kind":"string","line":[447,447],"text":"# Setup\\n\\n```rust\\nfn main() {\\n    println!(\\\"Hello\\\");\\n}\\n```\\n"}
{"file":"src/parser/markdown.rs","kind":"string","line":[455,455],"text":"fn main"}
{"file":"src/parser/markdown.rs","kind":"string","line":[461,461],"text":"Main Title\\n==========\\n\\n## ATX Subsection\\n\\nContent here.\\n"}
{"file":"src/parser/markdown.rs","kind":"string","line":[465,465],"text":"Main Title"}
{"file":"src/parser/markdown.rs","kind":"string","line":[466,466],"text":"Main Title/ATX Subsection"}
{"file":"src/parser/markdown.rs","kind":"string","line":[467,467],"text":"Main Title"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[472,473],"text":"Per CommonMark: optional closing sequence is space + one or more # at end of line\nThe \"###\" in the middle is content (followed by space), only the final \" #\" is stripped"}
{"file":"src/parser/markdown.rs","kind":"string","line":[474,474],"text":"# Heading with trailing ### #\\n"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[478,478],"text":"The middle \"###\" is content, final \" #\" is stripped"}
{"file":"src/parser/markdown.rs","kind":"string","line":[479,479],"text":"Heading with trailing ###"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[484,484],"text":"When the entire trailing part is the closing sequence"}
{"file":"src/parser/markdown.rs","kind":"string","line":[485,485],"text":"# Simple heading ##\\n"}
{"file":"src/parser/markdown.rs","kind":"string","line":[489,489],"text":"Simple heading"}
{"file":"src/parser/markdown.rs","kind":"string","line":[494,494],"text":"# \\n## Real Heading\\n"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[497,497],"text":"Empty heading should be skipped"}
{"file":"src/parser/markdown.rs","kind":"string","line":[499,499],"text":"Real Heading"}
{"file":"src/parser/markdown.rs","kind":"string","line":[504,504],"text":"```python\\nprint('hello')\\n```\\n"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[510,510],"text":"No heading context"}
{"file":"src/parser/markdown.rs","kind":"string","line":[515,515],"text":"# H1\\n## H2\\n### H3\\n#### H4\\n##### H5\\n###### H6\\n"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[525,525],"text":"Multiple \"Features\" sections under different parents - qualified names disambiguate"}
{"file":"src/parser/markdown.rs","kind":"string","line":[526,526],"text":"# v1.0\\n## Features\\n## Bug Fixes\\n# v2.0\\n## Features\\n## Bug Fixes\\n"}
{"file":"src/parser/markdown.rs","kind":"string","line":[532,532],"text":"v1.0/Bug Fixes"}
{"file":"src/parser/markdown.rs","kind":"string","line":[535,535],"text":"v2.0/Bug Fixes"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[540,540],"text":"Code block under a nested heading should have qualified parent"}
{"file":"src/parser/markdown.rs","kind":"string","line":[541,541],"text":"# Guide\\n## Installation\\n```bash\\nnpm install\\n```\\n"}
{"file":"src/parser/markdown.rs","kind":"comment","line":[550,550],"text":"Parent should be the qualified name"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[1,1],"text":"File metadata extraction (title and description)."}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[3,13],"text":"Extracts file-level metadata from source code for improved search relevance.\nEach language has specific conventions for documenting files:\n- Markdown: YAML frontmatter or first heading/paragraph\n- Python: Module docstring\n- Rust: `//!` module docs\n- JavaScript/TypeScript: Top-level JSDoc\n- Go: Package comment\n- Java: Top-level Javadoc\n- C/C++: File header comment\n- Ruby: Top file comment\n- C#: Top-level XML doc comment"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[20,20],"text":"File metadata: title and description."}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[37,37],"text":"Extract file metadata (title and description) from source code."}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[39,40],"text":"Returns `FileMetadata` with title and/or description if found.\nDescription is truncated to the first sentence or line."}
{"file":"src/parser/metadata.rs","kind":"comment","line":[79,79],"text":"Post-process: truncate description to first sentence/line"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[86,86],"text":"Helper to parse source and extract metadata using a tree-based extractor."}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[107,107],"text":"Truncate text to the first line (up to newline)."}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[116,116],"text":"Truncate text to the first sentence (up to period, or first line)."}
{"file":"src/parser/metadata.rs","kind":"comment","line":[120,120],"text":"First, try to find a sentence boundary (. followed by space or end)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[125,125],"text":"Period at end"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[130,130],"text":"Sentence boundary found"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[136,136],"text":"No sentence boundary, fall back to first line"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[140,142],"text":"---------------------------------------------------------------------------\nMarkdown metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[151,151],"text":"Try YAML frontmatter first"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[158,158],"text":"Fallback: first heading as title, first paragraph as description"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[166,166],"text":"Skip code blocks"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[175,175],"text":"Skip empty lines"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[180,180],"text":"First ATX heading as title"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[183,183],"text":"Strip optional closing hashes"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[191,191],"text":"First non-heading paragraph as description"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[203,203],"text":"YAML frontmatter starts with --- on first line"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[208,208],"text":"Find closing ---"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[234,236],"text":"---------------------------------------------------------------------------\nPython metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[243,243],"text":"Look for module docstring: first expression_statement containing a string"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[257,257],"text":"First line is title, rest is description"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[260,260],"text":"Stop at first non-docstring statement"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[269,271],"text":"---------------------------------------------------------------------------\nRust metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[279,279],"text":"Look for //! module doc comments at the start of the file"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[286,286],"text":"Regular comment, stop looking for module docs"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[292,292],"text":"Block doc comment"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[304,304],"text":"Non-comment node, stop"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[317,319],"text":"---------------------------------------------------------------------------\nJavaScript/TypeScript metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[326,326],"text":"Look for top-level JSDoc comment (/** ... */)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[331,331],"text":"JSDoc comment"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[343,343],"text":"Stop at first non-comment (except shebang)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[351,353],"text":"---------------------------------------------------------------------------\nGo metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[361,361],"text":"Look for package comment (comment block before package clause)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[379,379],"text":"Found package clause, use collected comments"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[382,382],"text":"Non-comment, non-package node"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[395,397],"text":"---------------------------------------------------------------------------\nJava metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[404,404],"text":"Look for top-level Javadoc comment (/** ... */)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[413,413],"text":"Same format as JSDoc"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[420,420],"text":"Stop at first non-comment"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[428,430],"text":"---------------------------------------------------------------------------\nC/C++ metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[438,438],"text":"Look for file header comment at the start"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[449,449],"text":"Skip copyright-only headers"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[455,455],"text":"Skip copyright lines"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[461,461],"text":"Stop at first non-comment"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[474,476],"text":"---------------------------------------------------------------------------\nRuby metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[484,484],"text":"Look for top file comment block"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[489,489],"text":"Skip shebang and encoding lines"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[494,494],"text":"Stop at first non-comment"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[507,509],"text":"---------------------------------------------------------------------------\nC# metadata extraction\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[517,517],"text":"Look for top-level XML doc comments (///)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[524,524],"text":"Regular comment, keep looking"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[528,528],"text":"Stop at first non-comment, non-using"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[537,537],"text":"Parse XML-like content for <summary>"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[548,548],"text":"Simple extraction of <summary>...</summary> content"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[569,571],"text":"---------------------------------------------------------------------------\nHelper functions\n---------------------------------------------------------------------------"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[573,573],"text":"Split a docstring into title (first line) and description (rest)."}
{"file":"src/parser/metadata.rs","kind":"comment","line":[580,580],"text":"First non-empty line is title"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[584,585],"text":"Rest is description: skip decoration lines (e.g., RST underlines like ~~~, ===, ---)\nand empty lines, take first real paragraph"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[607,607],"text":"Check if a line is a decoration/underline (e.g., RST ~~~, ===, ---, etc.)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[613,613],"text":"Common RST/markdown decoration characters"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[618,618],"text":"Clean a block comment by stripping leading * from each line."}
{"file":"src/parser/metadata.rs","kind":"comment","line":[623,623],"text":"Strip leading * (common in block comments)"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[631,631],"text":"Clean a JSDoc/Javadoc comment by stripping * and @ tags."}
{"file":"src/parser/metadata.rs","kind":"comment","line":[637,637],"text":"Strip leading *"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[640,640],"text":"Skip empty lines and @ tags (except @description/@fileoverview)"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[645,645],"text":"Extract content from @description or @fileoverview"}
{"file":"src/parser/metadata.rs","kind":"comment","line":[655,655],"text":"Skip other @ tags"}
{"file":"src/parser/metadata.rs","kind":"docstring","line":[665,665],"text":"Check if a comment is only copyright/license boilerplate."}
{"file":"src/parser/metadata.rs","kind":"string","line":[682,682],"text":"Hello world. This is more."}
{"file":"src/parser/metadata.rs","kind":"string","line":[683,683],"text":"Hello world."}
{"file":"src/parser/metadata.rs","kind":"string","line":[685,685],"text":"No period here"}
{"file":"src/parser/metadata.rs","kind":"string","line":[685,685],"text":"No period here"}
{"file":"src/parser/metadata.rs","kind":"string","line":[687,687],"text":"File v1.2.3 description. More info."}
{"file":"src/parser/metadata.rs","kind":"string","line":[688,688],"text":"File v1.2.3 description."}
{"file":"src/parser/metadata.rs","kind":"string","line":[694,694],"text":"First line\\nSecond line"}
{"file":"src/parser/metadata.rs","kind":"string","line":[694,694],"text":"First line"}
{"file":"src/parser/metadata.rs","kind":"string","line":[695,695],"text":"Single line"}
{"file":"src/parser/metadata.rs","kind":"string","line":[695,695],"text":"Single line"}
{"file":"src/parser/metadata.rs","kind":"string","line":[700,700],"text":"Title here\\n\\nDescription follows."}
{"file":"src/parser/metadata.rs","kind":"string","line":[701,701],"text":"Title here"}
{"file":"src/parser/metadata.rs","kind":"string","line":[702,702],"text":"Description follows."}
{"file":"src/parser/metadata.rs","kind":"string","line":[704,704],"text":"Just a title"}
{"file":"src/parser/metadata.rs","kind":"string","line":[705,705],"text":"Just a title"}
{"file":"src/parser/metadata.rs","kind":"string","line":[711,711],"text":"* First line\\n * Second line\\n * Third"}
{"file":"src/parser/metadata.rs","kind":"string","line":[713,713],"text":"First line\\nSecond line\\nThird"}
{"file":"src/parser/metadata.rs","kind":"string","line":[719,719],"text":"---\\ntitle: My Title\\ndescription: My description\\n---\\n# Heading"}
{"file":"src/parser/metadata.rs","kind":"string","line":[721,721],"text":"My Title"}
{"file":"src/parser/metadata.rs","kind":"string","line":[722,722],"text":"My description"}
{"file":"src/parser/metadata.rs","kind":"string","line":[728,728],"text":"# Main Title\\n\\nFirst paragraph here."}
{"file":"src/parser/metadata.rs","kind":"string","line":[730,730],"text":"Main Title"}
{"file":"src/parser/metadata.rs","kind":"string","line":[731,731],"text":"First paragraph here."}
{"file":"src/parser/mod.rs","kind":"comment","line":[7,7],"text":"Language-specific extractors"}
{"file":"src/parser/python.rs","kind":"docstring","line":[1,1],"text":"Python symbol and text extraction."}
{"file":"src/parser/python.rs","kind":"comment","line":[32,32],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/python.rs","kind":"comment","line":[44,44],"text":"handled recursively"}
{"file":"src/parser/python.rs","kind":"comment","line":[50,50],"text":"handled recursively"}
{"file":"src/parser/python.rs","kind":"string","line":[55,55],"text":"import_from_statement"}
{"file":"src/parser/python.rs","kind":"comment","line":[59,59],"text":"Recurse into the definition inside the decorator"}
{"file":"src/parser/python.rs","kind":"comment","line":[76,76],"text":"Check for module-level assignments and docstrings"}
{"file":"src/parser/python.rs","kind":"comment","line":[83,83],"text":"Could be a module/class docstring"}
{"file":"src/parser/python.rs","kind":"comment","line":[104,104],"text":"Recurse into children"}
{"file":"src/parser/python.rs","kind":"comment","line":[138,138],"text":"Determine if it's a method (inside a class) or function"}
{"file":"src/parser/python.rs","kind":"comment","line":[145,145],"text":"Check for decorators to detect properties, staticmethods, etc."}
{"file":"src/parser/python.rs","kind":"comment","line":[148,148],"text":"Extract tokens from function body for FTS"}
{"file":"src/parser/python.rs","kind":"comment","line":[171,171],"text":"Recurse into function body for nested definitions and references"}
{"file":"src/parser/python.rs","kind":"comment","line":[173,173],"text":"Check for docstring as first statement"}
{"file":"src/parser/python.rs","kind":"comment","line":[177,177],"text":"Check if first statement is a docstring"}
{"file":"src/parser/python.rs","kind":"comment","line":[185,185],"text":"Skip docstring, don't process as regular code"}
{"file":"src/parser/python.rs","kind":"comment","line":[188,188],"text":"Recurse into function body to find calls and nested definitions"}
{"file":"src/parser/python.rs","kind":"comment","line":[222,222],"text":"Extract tokens from class body for FTS"}
{"file":"src/parser/python.rs","kind":"comment","line":[245,245],"text":"Walk class body"}
{"file":"src/parser/python.rs","kind":"comment","line":[250,250],"text":"Check for class docstring"}
{"file":"src/parser/python.rs","kind":"comment","line":[284,284],"text":"`import foo, bar` or `import foo as bar`"}
{"file":"src/parser/python.rs","kind":"comment","line":[301,301],"text":"Also record as import reference"}
{"file":"src/parser/python.rs","kind":"comment","line":[328,328],"text":"Also record as import reference"}
{"file":"src/parser/python.rs","kind":"comment","line":[353,353],"text":"Get module name: `from X import ...`"}
{"file":"src/parser/python.rs","kind":"comment","line":[358,358],"text":"Iterate over imported names"}
{"file":"src/parser/python.rs","kind":"comment","line":[363,363],"text":"Skip the module name itself (already captured)"}
{"file":"src/parser/python.rs","kind":"comment","line":[387,387],"text":"Also record as import reference"}
{"file":"src/parser/python.rs","kind":"comment","line":[419,419],"text":"Also record as import reference"}
{"file":"src/parser/python.rs","kind":"comment","line":[447,447],"text":"Also record as import reference"}
{"file":"src/parser/python.rs","kind":"comment","line":[469,469],"text":"Module/class-level assignments: `FOO = ...` or `foo: type = ...`"}
{"file":"src/parser/python.rs","kind":"comment","line":[475,475],"text":"Only capture simple identifier assignments (not destructuring, subscripts, etc.)"}
{"file":"src/parser/python.rs","kind":"comment","line":[484,484],"text":"UPPER_CASE → constant, otherwise variable"}
{"file":"src/parser/python.rs","kind":"docstring","line":[510,511],"text":"Extract a function call as a reference.\nHandles: simple calls (foo()), method calls (obj.method()), chained calls (a.b.c())."}
{"file":"src/parser/python.rs","kind":"comment","line":[521,521],"text":"The \"function\" field contains the callable expression"}
{"file":"src/parser/python.rs","kind":"comment","line":[526,526],"text":"Extract the name of the called function"}
{"file":"src/parser/python.rs","kind":"comment","line":[529,529],"text":"Simple call: foo()"}
{"file":"src/parser/python.rs","kind":"comment","line":[533,534],"text":"Method call: obj.method() or chained: a.b.c()\nWe capture the full attribute chain"}
{"file":"src/parser/python.rs","kind":"comment","line":[538,539],"text":"Complex expression like lambda calls, subscript calls, etc.\nSkip these as they're hard to resolve statically"}
{"file":"src/parser/python.rs","kind":"comment","line":[544,544],"text":"Skip builtins and common patterns that aren't useful references"}
{"file":"src/parser/python.rs","kind":"docstring","line":[559,559],"text":"Check if a call is to a Python builtin that we want to skip."}
{"file":"src/parser/python.rs","kind":"comment","line":[561,561],"text":"Get the base name (first part for attribute chains)"}
{"file":"src/parser/python.rs","kind":"docstring","line":[657,657],"text":"Python-specific stopwords to filter from tokens."}
{"file":"src/parser/python.rs","kind":"docstring","line":[662,662],"text":"Filter Python-specific tokens from the extracted token string."}
{"file":"src/parser/python.rs","kind":"string","line":[680,680],"text":"symbol not found: {name}"}
{"file":"src/parser/python.rs","kind":"string","line":[685,692],"text":"def hello(name):\n    return f'Hello, {name}!'\n\ndef _private():\n    pass\n\nasync def fetch_data():\n    return None"}
{"file":"src/parser/python.rs","kind":"comment","line":[698,699],"text":"Tokens should contain identifiers from the function body (name param filtered by stopwords)\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/python.rs","kind":"comment","line":[704,704],"text":"Empty body, no meaningful tokens"}
{"file":"src/parser/python.rs","kind":"comment","line":[708,708],"text":"Body just returns None, no meaningful tokens after filtering"}
{"file":"src/parser/python.rs","kind":"string","line":[714,722],"text":"class Person:\n    def __init__(self, name):\n        self.name = name\n\n    def greet(self):\n        return f'Hi, {self.name}'\n\nclass _Private:\n    pass"}
{"file":"src/parser/python.rs","kind":"comment","line":[727,728],"text":"Class body tokens should contain identifiers from methods\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/python.rs","kind":"comment","line":[734,735],"text":"Method body has 'name' identifier\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/python.rs","kind":"string","line":[746,749],"text":"import os\nimport sys as system\nfrom pathlib import Path\nfrom typing import List, Dict as D"}
{"file":"src/parser/python.rs","kind":"comment","line":[764,764],"text":"Check import references were created"}
{"file":"src/parser/python.rs","kind":"string","line":[775,780],"text":"MAX_SIZE = 100\ndebug_mode = True\n\nclass Config:\n    def __init__(self):\n        self.version = '1.0'"}
{"file":"src/parser/python.rs","kind":"string","line":[795,806],"text":"def public_fn():\n    pass\n\ndef _internal():\n    pass\n\ndef __private():\n    pass\n\nclass Foo:\n    def __special__(self):\n        pass"}
{"file":"src/parser/python.rs","kind":"comment","line":[819,819],"text":"__special__ starts with _ so it's internal (not __x without trailing __)"}
{"file":"src/parser/python.rs","kind":"string","line":[825,833],"text":"\\\"\\\"\\\"Module docstring\\\"\\\"\\\"\n\ndef foo():\n    \\\"\\\"\\\"Function docstring\\\"\\\"\\\"\n    pass\n\nclass Bar:\n    \\\"\\\"\\\"Class docstring\\\"\\\"\\\"\n    pass"}
{"file":"src/parser/python.rs","kind":"string","line":[840,846],"text":"def caller():\n    result = some_function()\n    obj.method_call()\n    nested.deep.call()\n\ndef some_function():\n    pass"}
{"file":"src/parser/python.rs","kind":"comment","line":[849,849],"text":"Check call references were created with caller context"}
{"file":"src/parser/ruby.rs","kind":"docstring","line":[1,1],"text":"Ruby symbol and text extraction."}
{"file":"src/parser/ruby.rs","kind":"docstring","line":[9,9],"text":"Ruby-specific stopwords (keywords, common patterns)"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[36,36],"text":"Common patterns"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[50,50],"text":"Common variable patterns"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[57,57],"text":"Very common methods (too generic)"}
{"file":"src/parser/ruby.rs","kind":"docstring","line":[78,78],"text":"Filter Ruby-specific stopwords from extracted tokens."}
{"file":"src/parser/ruby.rs","kind":"comment","line":[84,84],"text":"Filter uppercase constants (ALL_CAPS)"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[115,115],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[143,143],"text":"Capture `require`, `include`, `extend`, `attr_*`"}
{"file":"src/parser/ruby.rs","kind":"string","line":[195,195],"text":"def {name}{params}"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[209,209],"text":"Extract tokens from method body"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[225,225],"text":"Recurse for nested definitions"}
{"file":"src/parser/ruby.rs","kind":"string","line":[272,272],"text":"def self.{name}{params}"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[280,280],"text":"Extract tokens from singleton method body"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[296,296],"text":"Recurse for nested definitions"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[339,339],"text":"Check for superclass"}
{"file":"src/parser/ruby.rs","kind":"string","line":[341,341],"text":" < {}"}
{"file":"src/parser/ruby.rs","kind":"string","line":[344,344],"text":"class {name}{superclass}"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[352,352],"text":"Extract tokens from class body"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[368,368],"text":"Walk class body"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[452,452],"text":"CONSTANT = value"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[471,471],"text":"Module/class level assignment"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[473,473],"text":"Only capture top-level assignments"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[489,489],"text":"@var or @@var"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[532,532],"text":"Extract the required file"}
{"file":"src/parser/ruby.rs","kind":"string","line":[586,586],"text":"symbol not found: {name}"}
{"file":"src/parser/ruby.rs","kind":"string","line":[591,597],"text":"def hello(name)\n  \\\"Hello, #{name}!\\\"\nend\n\ndef _private_helper\n  puts 'private'\nend"}
{"file":"src/parser/ruby.rs","kind":"comment","line":[602,603],"text":"Token extraction extracts identifiers from method body\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/ruby.rs","kind":"string","line":[612,624],"text":"class Person\n  def initialize(name)\n    @name = name\n  end\n\n  def greet\n    \\\"Hi, #{@name}\\\"\n  end\n\n  def self.create\n    Person.new('default')\n  end\nend"}
{"file":"src/parser/ruby.rs","kind":"string","line":[640,649],"text":"module Utils\n  def self.helper\n    puts 'helping'\n  end\nend\n\nmodule Logger\n  class Writer\n  end\nend"}
{"file":"src/parser/ruby.rs","kind":"string","line":[668,673],"text":"MAX_SIZE = 100\nDEFAULT_NAME = 'Unknown'\n\nclass Config\n  VERSION = '1.0'\nend"}
{"file":"src/parser/ruby.rs","kind":"string","line":[686,689],"text":"class Foo\n  @instance_var = 1\n  @@class_var = 2\nend"}
{"file":"src/parser/ruby.rs","kind":"string","line":[703,705],"text":"require 'json'\nrequire_relative 'config'\nrequire 'active_support'"}
{"file":"src/parser/ruby.rs","kind":"string","line":[717,724],"text":"class Animal\nend\n\nclass Dog < Animal\n  def bark\n    'woof'\n  end\nend"}
{"file":"src/parser/ruby.rs","kind":"string","line":[736,740],"text":"class Utils\n  def self.format(text)\n    text.upcase\n  end\nend"}
{"file":"src/parser/ruby.rs","kind":"string","line":[749,755],"text":"# Single line comment\ndef foo\nend\n\n=begin\nMulti-line comment\n=end"}
{"file":"src/parser/ruby.rs","kind":"string","line":[762,766],"text":"def public_method\nend\n\ndef _internal_method\nend"}
{"file":"src/parser/rust_lang.rs","kind":"docstring","line":[1,1],"text":"Rust symbol and text extraction."}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[29,29],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[66,66],"text":"impl is handled recursively inside extract_impl"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[79,79],"text":"Recurse into children"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[109,109],"text":"Extract tokens from function body for FTS"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[188,188],"text":"impl blocks are containers, no meaningful tokens"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[201,201],"text":"Walk children of the body to find methods"}
{"file":"src/parser/rust_lang.rs","kind":"docstring","line":[345,345],"text":"Rust-specific stopwords to filter from tokens."}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[350,351],"text":"Common std types/modules\nVery common short names in Rust"}
{"file":"src/parser/rust_lang.rs","kind":"docstring","line":[355,355],"text":"Filter Rust-specific tokens from the extracted token string."}
{"file":"src/parser/rust_lang.rs","kind":"docstring","line":[364,364],"text":"Rust-specific comment extraction (handles ///, //!, /**, etc.)"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[384,384],"text":"symbol not found: {name}"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[389,395],"text":"pub fn hello(name: &str) -> String {\n    format!(\\\"Hello, {}!\\\", name)\n}\n\nfn private_helper() {\n    println!(\\\"private\\\");\n}"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[401,402],"text":"Tokens contain identifiers from function body (format, name)\nToken may be None if all identifiers are filtered as stopwords"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[412,417],"text":"pub struct Point {\n    pub x: i32,\n    pub y: i32,\n}\n\nstruct Private;"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[432,440],"text":"struct Foo;\n\nimpl Foo {\n    pub fn new() -> Self {\n        Foo\n    }\n\n    fn private_method(&self) {}\n}"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[442,442],"text":"struct + impl + 2 methods"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[445,445],"text":"First is struct, second is impl"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[447,447],"text":"Impl tokens now contain the signature \"impl Foo\""}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[461,469],"text":"pub trait Display {\n    fn fmt(&self) -> String;\n}\n\nimpl Display for Foo {\n    fn fmt(&self) -> String {\n        String::new()\n    }\n}"}
{"file":"src/parser/rust_lang.rs","kind":"comment","line":[479,479],"text":"Trait impls are containers, no tokens"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[485,487],"text":"use std::collections::HashMap;\nuse std::io::{self, Read};\npub use std::fmt::Debug;"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[492,492],"text":"std::collections::HashMap"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[504,507],"text":"pub enum Result<T, E> {\n    Ok(T),\n    Err(E),\n}"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[516,517],"text":"pub mod utils;\nmod private_mod;"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[530,531],"text":"pub const MAX: usize = 100;\nstatic GLOBAL: i32 = 0;"}
{"file":"src/parser/rust_lang.rs","kind":"string","line":[545,550],"text":"/// This is a doc comment\n/// for the function\npub fn documented() {}\n\n// Regular comment\nfn helper() {}"}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[1,1],"text":"Single File Component (SFC) preprocessor."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[3,4],"text":"Extracts `<script>` blocks from Vue, Svelte, and Astro files so they can\nbe fed to the existing TypeScript/JavaScript tree-sitter extractors."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[6,6],"text":"No external dependencies — uses simple byte-level scanning."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[8,8],"text":"A script block extracted from an SFC file."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[10,10],"text":"The script content (without the surrounding tags)."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[12,12],"text":"The language to parse with: `\"typescript\"` or `\"javascript\"`."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[14,14],"text":"1-based line number where the content starts in the original file."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[18,18],"text":"Extract script blocks from an SFC file based on its extension."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[20,20],"text":"Returns an empty vec if no script blocks are found (e.g. template-only"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[32,34],"text":"---------------------------------------------------------------------------\nVue: <script> and <script setup>, with optional lang=\"ts\"\n---------------------------------------------------------------------------"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[40,42],"text":"---------------------------------------------------------------------------\nSvelte: <script> with optional lang=\"ts\"\n---------------------------------------------------------------------------"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[48,50],"text":"---------------------------------------------------------------------------\nAstro: --- frontmatter --- (always TS) + optional <script> blocks\n---------------------------------------------------------------------------"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[56,56],"text":"Extract frontmatter: content between first `---` and second `---`"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[60,60],"text":"Skip leading newline after opening ---"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[73,73],"text":"Count lines before the frontmatter content starts"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[86,86],"text":"Also extract any <script> tags in the body"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[92,94],"text":"---------------------------------------------------------------------------\nShared: extract <script> ... </script> blocks from HTML-like content\n---------------------------------------------------------------------------"}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[96,96],"text":"Extract all `<script ...>...</script>` blocks from HTML-like source."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[98,98],"text":"`default_lang` is used when no `lang=\"...\"` attribute is present."}
{"file":"src/parser/sfc.rs","kind":"comment","line":[109,109],"text":"Make sure it's actually a tag (next char after \"script\" should be whitespace or >)"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[125,125],"text":"Find the closing > of the opening tag"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[131,131],"text":"Extract the opening tag attributes"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[134,134],"text":"Detect language from lang=\"...\" attribute"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[137,137],"text":"Content starts after the > (skip leading newline if present)"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[148,148],"text":"Find the matching </script> — content ends where the close tag begins"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[156,156],"text":"Calculate the 1-based start line of the content"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[167,167],"text":"Move past the closing tag"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[169,169],"text":"Skip past </script>"}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[180,180],"text":"Detect the script language from an opening `<script ...>` tag."}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[182,183],"text":"Looks for `lang=\"ts\"`, `lang=\"typescript\"`, `lang='ts'`, etc.\nReturns `\"typescript\"` or `\"javascript\"`."}
{"file":"src/parser/sfc.rs","kind":"comment","line":[187,187],"text":"Match lang=\"ts\" or lang=\"typescript\" (with either quote style)"}
{"file":"src/parser/sfc.rs","kind":"comment","line":[201,201],"text":"No lang attribute — use the default"}
{"file":"src/parser/sfc.rs","kind":"docstring","line":[209,209],"text":"Count the number of newline characters in a string slice."}
{"file":"src/parser/sfc.rs","kind":"string","line":[220,220],"text":"<template>\\n  <div>hello</div>\\n</template>\\n\\n<script setup lang=\\\"ts\\\">\\nimport { ref } from 'vue'\\nconst msg = ref('hi')\\n</script>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[226,226],"text":"import { ref }"}
{"file":"src/parser/sfc.rs","kind":"string","line":[227,227],"text":"const msg"}
{"file":"src/parser/sfc.rs","kind":"string","line":[232,232],"text":"<script>\\nexport default { name: 'Foo' }\\n</script>\\n\\n<script setup lang=\\\"ts\\\">\\nconst x = 1\\n</script>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[243,243],"text":"<template>\\n  <div>hello</div>\\n</template>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[250,250],"text":"---\\nimport Layout from './Layout.astro'\\nconst title = 'Hello'\\n---\\n\\n<Layout title={title}>\\n  <h1>Hello</h1>\\n</Layout>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[256,256],"text":"import Layout"}
{"file":"src/parser/sfc.rs","kind":"string","line":[261,261],"text":"<script lang=\\\"ts\\\">\\n  let count = 0\\n  function inc() { count++ }\\n</script>\\n\\n<button on:click={inc}>{count}</button>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[270,270],"text":"<!DOCTYPE html>\\n<html>\\n<head>\\n<script>\\nfunction greet(name) {\\n  return 'Hello ' + name;\\n}\\n</script>\\n</head>\\n<body></body>\\n</html>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[276,276],"text":"function greet"}
{"file":"src/parser/sfc.rs","kind":"string","line":[281,281],"text":"<!DOCTYPE html>\\n<html><body><p>Hello</p></body></html>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[288,288],"text":"<html>\\n<body>\\n<script lang=\\\"ts\\\">\\nconst x: number = 42;\\n</script>\\n</body>\\n</html>\\n"}
{"file":"src/parser/sfc.rs","kind":"string","line":[297,297],"text":"<script lang=\\\"ts\\\">"}
{"file":"src/parser/sfc.rs","kind":"string","line":[301,301],"text":"<script lang='typescript'>"}
{"file":"src/parser/sfc.rs","kind":"string","line":[305,305],"text":"<script setup lang=\\\"ts\\\">"}
{"file":"src/parser/sfc.rs","kind":"string","line":[314,314],"text":"<script setup>"}
{"file":"src/parser/treesitter.rs","kind":"docstring","line":[9,9],"text":"Maximum recursion depth for AST traversal to prevent stack overflow on deeply nested code."}
{"file":"src/parser/treesitter.rs","kind":"docstring","line":[12,12],"text":"Parse a single file using tree-sitter and extract symbols, text blocks, and references."}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[18,18],"text":"SFC preprocessing: extract script blocks from Vue/Svelte/Astro files"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[31,31],"text":"Markdown uses a custom two-pass parser (tree-sitter-md with MarkdownParser)"}
{"file":"src/parser/treesitter.rs","kind":"string","line":[44,44],"text":"failed to parse {file_path}"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[97,97],"text":"For unsupported languages, just extract comments and strings"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[102,102],"text":"Merge consecutive doc comments (/// lines) into single entries"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[108,110],"text":"---------------------------------------------------------------------------\nGeneric text extraction (for unsupported languages)\n---------------------------------------------------------------------------"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[113,113],"text":"Use iterative traversal with explicit stack to avoid stack overflow"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[151,151],"text":"Push children in reverse order so they're processed in forward order"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[160,162],"text":"---------------------------------------------------------------------------\nPost-processing: merge consecutive doc comments\n---------------------------------------------------------------------------"}
{"file":"src/parser/treesitter.rs","kind":"docstring","line":[164,164],"text":"Merge consecutive text entries of the same kind on adjacent lines."}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[192,194],"text":"---------------------------------------------------------------------------\nSFC (Single File Component) handling\n---------------------------------------------------------------------------"}
{"file":"src/parser/treesitter.rs","kind":"docstring","line":[196,197],"text":"Parse an SFC file by extracting script blocks and running them through the\nappropriate JS/TS parser, adjusting line numbers back to the original file."}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[214,214],"text":"Parse each script block with the detected language"}
{"file":"src/parser/treesitter.rs","kind":"string","line":[220,220],"text":"failed to parse {} script block in {}: {}"}
{"file":"src/parser/treesitter.rs","kind":"comment","line":[229,230],"text":"Adjust line numbers: add the block's start_line offset (minus 1 because\nthe parser already counts from line 1)"}
{"file":"src/parser/typescript.rs","kind":"docstring","line":[1,1],"text":"TypeScript symbol and text extraction."}
{"file":"src/parser/typescript.rs","kind":"docstring","line":[3,5],"text":"TypeScript extends JavaScript with type annotations, interfaces,\nenums, type aliases, and namespaces. We reuse the JS extraction\nfor most constructs and add TS-specific ones."}
{"file":"src/parser/typescript.rs","kind":"docstring","line":[13,13],"text":"TypeScript-specific stopwords (JS keywords + TS type system keywords)"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[15,15],"text":"JavaScript common"}
{"file":"src/parser/typescript.rs","kind":"docstring","line":[72,72],"text":"Filter TypeScript-specific stopwords from extracted tokens."}
{"file":"src/parser/typescript.rs","kind":"comment","line":[107,107],"text":"Prevent stack overflow on deeply nested code"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[115,115],"text":"--- JS constructs ---"}
{"file":"src/parser/typescript.rs","kind":"string","line":[116,116],"text":"generator_function_declaration"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[148,148],"text":"--- TS-specific constructs ---"}
{"file":"src/parser/typescript.rs","kind":"string","line":[149,149],"text":"interface_declaration"}
{"file":"src/parser/typescript.rs","kind":"string","line":[153,153],"text":"type_alias_declaration"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[160,160],"text":"`namespace Foo { ... }` or `module Foo { ... }`"}
{"file":"src/parser/typescript.rs","kind":"string","line":[164,164],"text":"abstract_class_declaration"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[180,180],"text":"Recurse into children"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[195,195],"text":"--- Shared JS-like extraction (adapted for TS node names) ---"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[230,230],"text":"Extract tokens from function body"}
{"file":"src/parser/typescript.rs","kind":"string","line":[268,268],"text":"abstract_class_declaration"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[277,277],"text":"Extract tokens from class body"}
{"file":"src/parser/typescript.rs","kind":"string","line":[336,336],"text":"accessibility_modifier"}
{"file":"src/parser/typescript.rs","kind":"string","line":[354,354],"text":": {}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[375,375],"text":"{prefix}{name}{params}{return_type}"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[390,390],"text":"Extract tokens from method body"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[469,469],"text":"Extract tokens from variable value"}
{"file":"src/parser/typescript.rs","kind":"string","line":[527,527],"text":"{source_module}.{name}"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[572,572],"text":"--- TS-specific constructs ---"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[595,595],"text":"Build signature with type parameters and extends"}
{"file":"src/parser/typescript.rs","kind":"string","line":[606,606],"text":" extends {}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[609,609],"text":"interface {name}{type_params}{extends}"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[617,617],"text":"Extract tokens from interface body (type references)"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[633,633],"text":"Walk interface body for method signatures"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[647,647],"text":"Interface signatures don't have bodies, so no tokens"}
{"file":"src/parser/typescript.rs","kind":"string","line":[651,651],"text":"{full_name}.{member_name}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[693,693],"text":"type {name}{type_params}"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[701,701],"text":"Extract tokens from type definition"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[795,795],"text":"Recurse into namespace body"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[812,812],"text":"--- Helpers ---"}
{"file":"src/parser/typescript.rs","kind":"string","line":[857,857],"text":": {}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[867,867],"text":"async function"}
{"file":"src/parser/typescript.rs","kind":"string","line":[872,872],"text":"{prefix} {name}{type_params}{params}{return_type}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[890,890],"text":"abstract class"}
{"file":"src/parser/typescript.rs","kind":"string","line":[895,895],"text":"{prefix} {name}{type_params}{extends}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[907,907],"text":"symbol not found: {name}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[912,918],"text":"function greet(name: string): string {\n    return `Hello, ${name}!`;\n}\n\nasync function fetch(): Promise<Data> {\n    return await api.get();\n}"}
{"file":"src/parser/typescript.rs","kind":"comment","line":[924,924],"text":"Token extraction is enabled (may be None if body has no tokens after filtering)"}
{"file":"src/parser/typescript.rs","kind":"string","line":[932,940],"text":"export interface User {\n    id: number;\n    name: string;\n    getEmail(): string;\n}\n\ninterface Private {\n    data: any;\n}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[957,958],"text":"export type Result<T> = Success<T> | Error;\ntype ID = string | number;"}
{"file":"src/parser/typescript.rs","kind":"string","line":[972,976],"text":"export enum Status {\n    Active,\n    Inactive,\n    Pending\n}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[986,1005],"text":"export abstract class Base {\n    protected abstract doWork(): void;\n}\n\nexport class Worker extends Base {\n    private data: string;\n\n    constructor(data: string) {\n        super();\n        this.data = data;\n    }\n\n    protected doWork(): void {\n        console.log(this.data);\n    }\n\n    public run(): void {\n        this.doWork();\n    }\n}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[1023,1025],"text":"export namespace Utils {\n    export function helper(): void {}\n}"}
{"file":"src/parser/typescript.rs","kind":"string","line":[1038,1041],"text":"import React from 'react';\nimport { Component, useState } from 'react';\nimport * as Utils from './utils';\nimport type { User } from './types';"}
{"file":"src/parser/typescript.rs","kind":"string","line":[1059,1063],"text":"class Foo {\n    public publicMethod(): void {}\n    private privateMethod(): void {}\n    protected protectedMethod(): void {}\n}"}
{"file":"src/server/db.rs","kind":"docstring","line":[6,7],"text":"An in-memory SQLite database with FTS5 virtual tables for fast text search\nover the code index."}
{"file":"src/server/db.rs","kind":"docstring","line":[10,10],"text":"Whether FTS5 virtual tables are enabled. Disabled in build mode to save memory."}
{"file":"src/server/db.rs","kind":"docstring","line":[15,15],"text":"Create a new in-memory database with FTS5 enabled (for serve mode).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[20,21],"text":"Create a new in-memory database without FTS5 (for build mode).\nThis significantly reduces memory usage for large repositories.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[26,26],"text":"Internal constructor with configurable FTS support.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[145,145],"text":"Load index data into the database for a specific project.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[238,240],"text":"Search or list symbols.\n- With query (no glob in file): FTS5 full-text search on symbol names (BM25-ranked)\n- Without query OR with glob file pattern: List matching symbols (ordered by file, line)","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[242,243],"text":"File filter supports glob patterns with * (e.g. \"src/*.py\").\nNote: When file contains glob patterns, uses SQL GLOB for filtering (case-sensitive).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[266,266],"text":"FTS5 search on symbol names (BM25-ranked).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[320,322],"text":"List symbols matching filters (no FTS, ordered by file and line).\nFile filter supports SQLite GLOB patterns: * matches any sequence, ? matches single char.\nQuery performs substring match on symbol name when provided.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[406,406],"text":"FTS5 search on text content, with optional kind, file, and project filters.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[453,453],"text":"FTS5 search on file paths, titles, and descriptions, with optional language and project filters.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[503,503],"text":"Get all symbols in a file, ordered by start line.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[533,533],"text":"Get direct children of a symbol in a file.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[563,563],"text":"Get all imports for a file (symbols with kind \"import\").","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[593,594],"text":"Get all references TO a symbol (who calls/uses this symbol).\nReturns references sorted by file, then line.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[642,643],"text":"Get all references FROM a symbol (what does this symbol call/use).\nReturns references sorted by file, then line.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[691,691],"text":"Search references by name using FTS5 (BM25-ranked).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[740,740],"text":"Get the hash of a file from the DB (for change detection).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[753,754],"text":"Remove all data for a file (from files, symbols, texts, refs tables).\nDoes not rebuild FTS indexes - caller should call rebuild_fts() after batch operations.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[779,781],"text":"Upsert a single file and its symbols/texts/references.\nRemoves old data for this path first, then inserts new data.\nDoes not rebuild FTS indexes - caller should call rebuild_fts() after batch operations.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[868,870],"text":"Rebuild all FTS5 indexes.\nCall this after batch upsert/remove operations.\nNo-op when FTS is disabled (build mode).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[886,886],"text":"Export all data from DB back to vecs (for flushing to disk).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[994,994],"text":"Export data for a specific project from DB back to vecs (for flushing to disk).","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[1106,1106],"text":"List all unique projects in the database.","parent":"SearchDb"}
{"file":"src/server/db.rs","kind":"docstring","line":[1120,1121],"text":"Quote a string for use in an FTS5 MATCH expression.\nWraps in double quotes and escapes any internal double quotes."}
{"file":"src/server/mcp.rs","kind":"comment","line":[21,21],"text":"Parameter structs for each tool"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[24,24],"text":"Search query for symbol names. If omitted, lists all symbols matching the filters."}
{"file":"src/server/mcp.rs","kind":"docstring","line":[26,26],"text":"Filter by symbol kind (e.g. function, struct, class, method)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[28,28],"text":"Filter by file path. Supports glob patterns with * (e.g. \"src/utils/*.py\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[30,30],"text":"Filter by project (relative path from workspace root, e.g. \"libs/utils\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[32,32],"text":"Maximum number of results to return (default: 100)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[34,34],"text":"Number of results to skip for pagination (default: 0)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[36,36],"text":"Number of code snippet lines: 0=none, -1=all, N=N lines (default: 10)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[42,42],"text":"Search query for file paths"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[44,44],"text":"Filter by language (e.g. python, rust, javascript)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[46,46],"text":"Filter by project (relative path from workspace root, e.g. \"libs/utils\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[52,52],"text":"Search query for text content"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[54,54],"text":"Filter by text kind (e.g. docstring, comment)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[56,56],"text":"Filter by file path"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[58,58],"text":"Filter by project (relative path from workspace root, e.g. \"libs/utils\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[64,64],"text":"File path to get symbols for"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[66,66],"text":"Number of code snippet lines: 0=none, -1=all, N=N lines (default: 10)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[72,72],"text":"File path containing the parent symbol"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[74,74],"text":"Name of the parent symbol"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[76,76],"text":"Number of code snippet lines: 0=none, -1=all, N=N lines (default: 10)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[82,82],"text":"File path to get imports for"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[88,88],"text":"Symbol name to find callers for (e.g. \"my_function\", \"MyClass.method\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[90,90],"text":"Filter by reference kind (e.g. \"call\", \"import\", \"type_annotation\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[92,92],"text":"Filter by project (relative path from workspace root, e.g. \"libs/utils\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[98,98],"text":"Symbol name to find callees for (e.g. \"my_function\", \"MyClass.method\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[100,100],"text":"Filter by reference kind (e.g. \"call\", \"import\", \"type_annotation\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[102,102],"text":"Filter by project (relative path from workspace root, e.g. \"libs/utils\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[108,108],"text":"Search query for reference names"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[110,110],"text":"Filter by reference kind (e.g. \"call\", \"import\", \"type_annotation\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[112,112],"text":"Filter by file path"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[114,114],"text":"Filter by project (relative path from workspace root, e.g. \"libs/utils\")"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[116,116],"text":"Maximum number of results to return (default: 100)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[118,118],"text":"Number of results to skip for pagination (default: 0)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[122,122],"text":"Response wrapper for SymbolEntry with optional snippet."}
{"file":"src/server/mcp.rs","kind":"docstring","line":[131,131],"text":"MCP server exposing code-index query tools."}
{"file":"src/server/mcp.rs","kind":"docstring","line":[133,134],"text":"`SearchDb` wraps a `rusqlite::Connection` which is not `Sync`, so we protect\nit with a `Mutex` to satisfy rmcp's `Send + Sync` requirements."}
{"file":"src/server/mcp.rs","kind":"docstring","line":[159,159],"text":"Enrich symbols with snippets, filtering out symbols whose files are missing.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[191,191],"text":"Search or list symbols. With query: FTS5 search (BM25-ranked). Without query: list all matching filters.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[193,193],"text":"Search or list symbols. Provide query for full-text search, or omit to list all symbols matching filters. File filter supports glob patterns (e.g. 'src/*.py'). Returns code snippets by default.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[227,227],"text":"Search files by path using FTS5 full-text search (BM25-ranked).","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[228,228],"text":"Search files by path with optional language filter","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[251,251],"text":"Search text entries (docstrings, comments) using FTS5 full-text search (BM25-ranked).","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[253,253],"text":"Search text entries (docstrings, comments) with optional kind/file filters","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[278,278],"text":"Get all symbols in a file, ordered by line number.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[280,280],"text":"Get all symbols in a file, ordered by line number. Returns code snippets by default.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[305,305],"text":"Get direct children of a symbol (e.g. methods of a class).","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[307,307],"text":"Get direct children of a symbol (e.g. methods of a class). Returns code snippets by default.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[334,334],"text":"Get all import statements for a file.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[335,335],"text":"Get all import statements for a file","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[354,354],"text":"List all indexed projects with metadata from package manifests.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[356,356],"text":"List all indexed projects with metadata extracted from package manifests (package.json, Cargo.toml, pyproject.toml, go.mod, pom.xml, *.gemspec). Returns name, description, and list of manifest files found.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[408,408],"text":"Get all references TO a symbol (who calls/uses this symbol).","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[410,410],"text":"Find all places that call or reference a symbol. Returns references sorted by file and line. Useful for understanding symbol usage and finding callers of a function.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[434,434],"text":"Get all references FROM a symbol (what does this symbol call/use).","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[436,436],"text":"Find all symbols that a given function/method calls or references. Returns references sorted by file and line. Useful for understanding dependencies and call chains.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[460,460],"text":"Search references by name using FTS5.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"string","line":[462,462],"text":"Search for symbol references (calls, imports, type annotations) using full-text search. Filter by kind, file, or project.","parent":"CodeIndexServer"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[494,494],"text":"Project info returned by list_projects, combining path with manifest metadata."}
{"file":"src/server/mcp.rs","kind":"docstring","line":[497,497],"text":"Relative path from workspace root (empty string for root project)"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[499,499],"text":"Metadata extracted from package manifests"}
{"file":"src/server/mcp.rs","kind":"docstring","line":[523,523],"text":"Start the MCP server over stdio with the given search database and mount table."}
{"file":"src/server/mcp.rs","kind":"string","line":[532,532],"text":"MCP serve error: {e}"}
{"file":"src/server/mcp.rs","kind":"string","line":[536,536],"text":"MCP runtime error: {e}"}
{"file":"src/server/snippet.rs","kind":"docstring","line":[4,4],"text":"Extracts code snippets from source files at query time."}
{"file":"src/server/snippet.rs","kind":"docstring","line":[6,7],"text":"Resolves file paths relative to workspace root and reads\nthe specified line ranges from disk."}
{"file":"src/server/snippet.rs","kind":"docstring","line":[14,14],"text":"Create a new snippet extractor with the given workspace root.","parent":"SnippetExtractor"}
{"file":"src/server/snippet.rs","kind":"docstring","line":[19,19],"text":"Resolve absolute file path from project and relative file path.","parent":"SnippetExtractor"}
{"file":"src/server/snippet.rs","kind":"docstring","line":[28,28],"text":"Extract a code snippet from a file.","parent":"SnippetExtractor"}
{"file":"src/server/snippet.rs","kind":"docstring","line":[30,38],"text":"# Arguments\n* `project` - Relative project path from workspace root (e.g., \"libs/utils\", \"\" for root)\n* `file` - File path relative to project root\n* `line_start` - Starting line number (1-indexed, inclusive)\n* `line_end` - Ending line number (1-indexed, inclusive)\n* `snippet_lines` - Number of lines to include:\n- `0`: No snippet (returns None immediately)\n- `-1`: All lines in range (blank lines skipped)\n- `N > 0`: First N non-blank lines","parent":"SnippetExtractor"}
{"file":"src/server/snippet.rs","kind":"docstring","line":[40,41],"text":"Returns `None` if file cannot be read or snippet_lines is 0.\nAdds \"...\" suffix when truncated.","parent":"SnippetExtractor"}
{"file":"src/server/snippet.rs","kind":"docstring","line":[99,99],"text":"Check if a file exists (for filtering symbols with missing files).","parent":"SnippetExtractor"}
{"file":"src/server/snippet.rs","kind":"string","line":[123,123],"text":"fn main() {\\n    println!(\\\"hello\\\");\\n}\\n"}
{"file":"src/server/snippet.rs","kind":"string","line":[131,131],"text":"fn main() {\\n    println!(\\\"hello\\\");\\n}"}
{"file":"src/server/snippet.rs","kind":"string","line":[138,138],"text":"line1\\nline2\\nline3\\nline4\\nline5\\n"}
{"file":"src/server/snippet.rs","kind":"string","line":[149,149],"text":"line1\\n\\n  \\nline2\\n\\nline3\\n"}
{"file":"src/server/snippet.rs","kind":"string","line":[160,160],"text":"fn main() {}"}
{"file":"src/server/snippet.rs","kind":"string","line":[182,182],"text":"pub fn test() {}"}
{"file":"src/server/snippet.rs","kind":"string","line":[187,187],"text":"pub fn test() {}"}
{"file":"src/utils/hasher.rs","kind":"docstring","line":[5,6],"text":"Compute the BLAKE3 hash of a file's contents, truncated to 64 bits,\nreturned as a 16-character hex string."}
{"file":"src/utils/hasher.rs","kind":"docstring","line":[12,13],"text":"Compute the BLAKE3 hash of byte content, truncated to 64 bits,\nreturned as a 16-character hex string."}
{"file":"src/utils/hasher.rs","kind":"comment","line":[17,17],"text":"Truncate to first 8 bytes (64 bits), hex-encode to 16 chars"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[1,1],"text":"Package manifest parsing for project metadata extraction."}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[3,4],"text":"Parses common package manifests (package.json, Cargo.toml, pyproject.toml, go.mod, pom.xml, *.gemspec)\nand returns both fixed metadata (name, description) and list of manifest files found."}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[11,11],"text":"Fixed project metadata extracted from manifests."}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[14,14],"text":"Human-readable project name (from first manifest found, or directory name)"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[16,16],"text":"Project description (from first manifest with description)"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[18,18],"text":"List of manifest files found (e.g., [\"package.json\", \"Cargo.toml\"])"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[22,22],"text":"Extract project metadata from all manifests found in the project root."}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[24,25],"text":"Checks for: package.json, Cargo.toml, pyproject.toml, go.mod, pom.xml, *.gemspec\nReturns fixed metadata (name, description) plus list of manifest files found."}
{"file":"src/utils/manifest.rs","kind":"comment","line":[31,31],"text":"Try each manifest type"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[66,66],"text":"go.mod has no description"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[90,90],"text":"Fallback: directory name"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[106,107],"text":"Parse package.json and return (name, description)\nHandles both regular packages and monorepo roots (private: true without name)."}
{"file":"src/utils/manifest.rs","kind":"comment","line":[113,113],"text":"Try to get name from the package"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[122,122],"text":"Handle monorepo roots (private: true without name) - use directory name"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[139,140],"text":"Parse Cargo.toml and return (name, description)\nHandles both package manifests ([package]) and workspace manifests ([workspace])."}
{"file":"src/utils/manifest.rs","kind":"comment","line":[146,146],"text":"Try [package] first (standard crate)"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[157,157],"text":"Try [workspace] (workspace root) - use directory name, no description"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[170,170],"text":"Parse pyproject.toml and return (name, description)"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[176,176],"text":"Try project.name (PEP 621)"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[187,187],"text":"Try tool.poetry.name (Poetry)"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[202,203],"text":"Parse go.mod and return the module name\ngo.mod has no description field"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[219,219],"text":"Use last segment as name, filter out empty strings"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[227,228],"text":"Parse pom.xml (Maven) and return (name, description)\nUses simple regex-based extraction to avoid adding an XML dependency."}
{"file":"src/utils/manifest.rs","kind":"comment","line":[233,234],"text":"Extract artifactId as name (prefer <name> if present at top level)\nWe look for top-level elements, not nested in <parent> or <dependency>"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[243,244],"text":"Simple XML element extraction (first occurrence, top-level only).\nThis is a basic implementation that works for common pom.xml structures."}
{"file":"src/utils/manifest.rs","kind":"comment","line":[254,254],"text":"Empty or contains nested elements"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[261,262],"text":"Parse *.gemspec (Ruby gem) and return (filename, name, description)\nLooks for .name and .summary/.description assignments."}
{"file":"src/utils/manifest.rs","kind":"comment","line":[264,264],"text":"Find *.gemspec file in the directory"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[273,273],"text":"Extract name: look for .name = \"...\" or .name = '...'"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[276,276],"text":"Extract description: prefer .summary, fall back to .description"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[283,283],"text":"Extract a Ruby string assignment like `s.name = \"value\"` or `spec.name = 'value'`"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[285,285],"text":"Pattern: <var>.field = \"value\" or <var>.field = 'value'"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[290,290],"text":"Find .field in the line (e.g., \"s.name\" or \"spec.name\")"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[296,296],"text":"Handle quoted strings"}
{"file":"src/utils/manifest.rs","kind":"docstring","line":[306,306],"text":"Extract a quoted string (single or double quotes)"}
{"file":"src/utils/manifest.rs","kind":"string","line":[330,330],"text":"{\"name\": \"my-app\", \"description\": \"A cool app\", \"version\": \"1.0.0\"}\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[336,336],"text":"A cool app"}
{"file":"src/utils/manifest.rs","kind":"string","line":[345,350],"text":"\n[package]\nname = \"my-crate\"\nversion = \"0.1.0\"\ndescription = \"A Rust library\"\n\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[356,356],"text":"A Rust library"}
{"file":"src/utils/manifest.rs","kind":"string","line":[365,370],"text":"\n[project]\nname = \"my-python-pkg\"\ndescription = \"A Python package\"\nversion = \"1.0.0\"\n\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[376,376],"text":"A Python package"}
{"file":"src/utils/manifest.rs","kind":"string","line":[385,390],"text":"\n[tool.poetry]\nname = \"poetry-pkg\"\ndescription = \"A Poetry package\"\nversion = \"2.0.0\"\n\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[396,396],"text":"A Poetry package"}
{"file":"src/utils/manifest.rs","kind":"string","line":[404,404],"text":"module github.com/user/myrepo\\n\\ngo 1.21\\n"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[410,410],"text":"go.mod has no description"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[417,417],"text":"No manifest files"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[420,420],"text":"Name should be the temp directory name (starts with '.')"}
{"file":"src/utils/manifest.rs","kind":"string","line":[431,431],"text":"{\"name\": \"npm-name\", \"description\": \"NPM desc\"}\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[436,440],"text":"\n[package]\nname = \"cargo-name\"\ndescription = \"Cargo desc\"\n\""}
{"file":"src/utils/manifest.rs","kind":"comment","line":[445,445],"text":"First found (npm) wins for name/description"}
{"file":"src/utils/manifest.rs","kind":"string","line":[447,447],"text":"NPM desc"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[448,448],"text":"But both manifest files are listed"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[456,456],"text":"package.json with name but no description"}
{"file":"src/utils/manifest.rs","kind":"string","line":[457,457],"text":"{\"name\": \"npm-name\"}\""}
{"file":"src/utils/manifest.rs","kind":"comment","line":[458,458],"text":"Cargo.toml with description"}
{"file":"src/utils/manifest.rs","kind":"string","line":[461,465],"text":"\n[package]\nname = \"cargo-name\"\ndescription = \"Cargo has the description\"\n\""}
{"file":"src/utils/manifest.rs","kind":"comment","line":[470,470],"text":"npm first"}
{"file":"src/utils/manifest.rs","kind":"string","line":[471,471],"text":"Cargo has the description"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[471,471],"text":"cargo provides description"}
{"file":"src/utils/manifest.rs","kind":"string","line":[479,488],"text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.example</groupId>\n    <artifactId>my-java-app</artifactId>\n    <version>1.0.0</version>\n    <name>My Java Application</name>\n    <description>A sample Java application</description>\n</project>\n\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[493,493],"text":"My Java Application"}
{"file":"src/utils/manifest.rs","kind":"string","line":[494,494],"text":"A sample Java application"}
{"file":"src/utils/manifest.rs","kind":"string","line":[503,509],"text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n    <groupId>com.example</groupId>\n    <artifactId>simple-app</artifactId>\n    <version>1.0.0</version>\n</project>\n\""}
{"file":"src/utils/manifest.rs","kind":"comment","line":[514,514],"text":"Falls back to artifactId when <name> is not present"}
{"file":"src/utils/manifest.rs","kind":"string","line":[525,533],"text":"\nGem::Specification.new do |s|\n  s.name        = \"my_gem\"\n  s.version     = \"1.0.0\"\n  s.summary     = \"A sample Ruby gem\"\n  s.description = \"A longer description of my gem\"\n  s.authors     = [\"Test Author\"]\nend\n\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[539,539],"text":"A sample Ruby gem"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[539,539],"text":"uses summary"}
{"file":"src/utils/manifest.rs","kind":"string","line":[548,554],"text":"\nGem::Specification.new do |spec|\n  spec.name    = 'another-gem'\n  spec.version = '2.0.0'\n  spec.summary = 'Single quoted summary'\nend\n\""}
{"file":"src/utils/manifest.rs","kind":"string","line":[560,560],"text":"Single quoted summary"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[567,567],"text":"Create a subdirectory with a specific name"}
{"file":"src/utils/manifest.rs","kind":"string","line":[572,576],"text":"\n[workspace]\nresolver = \"2\"\nmembers = [\"crate-a\", \"crate-b\"]\n\""}
{"file":"src/utils/manifest.rs","kind":"comment","line":[581,582],"text":"Uses directory name\nWorkspaces don't have description"}
{"file":"src/utils/manifest.rs","kind":"comment","line":[589,589],"text":"Create a subdirectory with a specific name"}
{"file":"src/utils/manifest.rs","kind":"string","line":[594,594],"text":"{\"private\": true, \"workspaces\": [\"packages/*\"]}\""}
{"file":"src/utils/manifest.rs","kind":"comment","line":[599,599],"text":"Uses directory name"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[23,23],"text":"Run the main event loop for file watching."}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[25,27],"text":"Receives events from all mounts via `rx` (notify watchers already initialized).\nEach event includes the mount root, avoiding the need for mount lookup.\nUses `tx` for passing to new project discoveries."}
{"file":"src/watcher/handler.rs","kind":"string","line":[37,37],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[41,41],"text":"event loop ready ({} directories watched)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[43,43],"text":"Debounce state: path -> (last event time, event kind, mount root)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[48,48],"text":"Wait for events with timeout"}
{"file":"src/watcher/handler.rs","kind":"string","line":[57,57],"text":"notify error: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[60,60],"text":"Check for debounced events ready to process"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[63,63],"text":"Flush all dirty mounts before shutting down"}
{"file":"src/watcher/handler.rs","kind":"string","line":[65,65],"text":"event loop channel closed, shutting down"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[70,70],"text":"Process debounced events"}
{"file":"src/watcher/handler.rs","kind":"string","line":[84,84],"text":"error handling watch events: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[88,88],"text":"Flush dirty mounts to disk after quiet period"}
{"file":"src/watcher/handler.rs","kind":"string","line":[91,91],"text":"failed to flush index to disk: {}"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[100,101],"text":"Handle when a project is discovered (during walk or watch).\nMounts the project and loads/indexes it."}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[104,106],"text":"- `load_from_cache`: If true (serve mode), try loading from .codeindex/ first\nIf false (build mode), always re-index\n- `tx`: If provided, initializes file watcher during walk"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[109,112],"text":"1. If already mounted, skip\n2. Try mount RW, fall back to RO if lock is held\n3. If load_from_cache && .codeindex/ exists, load from disk\n4. Otherwise, index files (walks and discovers subprojects)"}
{"file":"src/watcher/handler.rs","kind":"string","line":[122,122],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[124,124],"text":"Check if already mounted (exact match, not prefix match)"}
{"file":"src/watcher/handler.rs","kind":"string","line":[127,127],"text":"failed to canonicalize {:?}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[132,132],"text":"Mount the new project (tries RW, falls back to RO if lock held)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[145,145],"text":"Try loading from .codeindex/ first (only if load_from_cache is true)"}
{"file":"src/watcher/handler.rs","kind":"string","line":[152,152],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[161,161],"text":"failed to load index for '{}'"}
{"file":"src/watcher/handler.rs","kind":"string","line":[165,165],"text":"loaded '{}' ({}) from .codeindex/: {} files, {} symbols, {} texts, {} refs"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[174,174],"text":"Loaded from cache - no need to walk (subprojects have their own .codeindex/)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[179,179],"text":"Can't rebuild in RO mode, just warn"}
{"file":"src/watcher/handler.rs","kind":"string","line":[181,181],"text":"failed to read .codeindex/ for '{}' (read-only): {}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[188,188],"text":"failed to read .codeindex/ for '{}', rebuilding: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[192,192],"text":"Fall through to index files"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[196,196],"text":"No .codeindex/ and read-only in serve mode - nothing to do"}
{"file":"src/watcher/handler.rs","kind":"string","line":[198,198],"text":"mounted '{}' ({}) - no .codeindex/, read-only"}
{"file":"src/watcher/handler.rs","kind":"string","line":[205,205],"text":"indexing '{}' ({})"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[207,207],"text":"Walk and index all files in the new project (also discovers subprojects)"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[213,213],"text":"Walk a project directory, indexing files and discovering subprojects."}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[215,215],"text":"Uses Mount's `walk()` method which handles gitignore filtering and subproject discovery."}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[217,218],"text":"- `load_from_cache`: passed to recursive on_project_discovery calls for subprojects\n- `tx`: If provided, initializes watcher and adds directories during walk"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[226,226],"text":"Use relative project path from workspace root"}
{"file":"src/watcher/handler.rs","kind":"string","line":[230,230],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[234,235],"text":"Collect events first, then process them\nThis allows us to release the mount table lock before recursive calls"}
{"file":"src/watcher/handler.rs","kind":"string","line":[242,242],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[246,246],"text":"no mount found for {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[248,248],"text":"Initialize watcher before walk (if tx provided)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[253,254],"text":"Walk the mount, collecting events\nWatches are added internally by on_fs_event during walk"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[258,258],"text":"Reconstruct abs_path from mount + path"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[265,265],"text":"Not emitted during walk"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[269,269],"text":"MountTable lock released here"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[271,271],"text":"Process files"}
{"file":"src/watcher/handler.rs","kind":"string","line":[277,277],"text":"processed {} files so far for project '{}'"}
{"file":"src/watcher/handler.rs","kind":"string","line":[283,283],"text":"failed to index {}: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[287,288],"text":"Process subprojects (always - this is the single walk strategy)\nPass load_from_cache to recursive calls"}
{"file":"src/watcher/handler.rs","kind":"string","line":[291,291],"text":"failed to handle subproject {}: {}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[296,296],"text":"finished indexing project '{}': {} files, {} subprojects"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[302,302],"text":"Rebuild FTS after batch indexing"}
{"file":"src/watcher/handler.rs","kind":"string","line":[305,305],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[308,308],"text":"Mark mount as dirty"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[317,317],"text":"Handle a batch of file system events."}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[319,320],"text":"All logic (gitignore, SKIP_ENTRIES, project detection, watches) is delegated\nto `Mount::on_fs_event()` - the same rules apply for notify events as for walker."}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[322,322],"text":"Each event includes the mount root, so we can directly get the mount without lookup."}
{"file":"src/watcher/handler.rs","kind":"string","line":[333,333],"text":"processing {} file events"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[335,335],"text":"Collect mount events to process"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[339,339],"text":"Early filter: skip .codeindex/ paths before expensive canonicalize()"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[344,345],"text":"For file removal, the path may not exist anymore\nFor creation/modification, canonicalize to handle symlinks"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[347,347],"text":"Use the path as-is for removal (can't canonicalize deleted files)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[352,352],"text":"Path doesn't exist"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[356,356],"text":"Get mount directly using the mount root from the event"}
{"file":"src/watcher/handler.rs","kind":"string","line":[359,359],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[361,361],"text":"Pass EventKind directly to on_fs_event (same type as walker uses)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[369,369],"text":"Process mount events"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[373,374],"text":"Discover the new project (watcher is initialized during walk)\nWatch mode always uses cache (load_from_cache=true)"}
{"file":"src/watcher/handler.rs","kind":"string","line":[376,376],"text":"failed to handle project discovery: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[382,382],"text":"Compute relative project path from workspace root"}
{"file":"src/watcher/handler.rs","kind":"string","line":[386,386],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[391,391],"text":"failed to process file {}: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[393,393],"text":"Mark mount as dirty"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[403,403],"text":"Compute relative project path from workspace root"}
{"file":"src/watcher/handler.rs","kind":"string","line":[407,407],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[411,411],"text":"file deleted: {} (project: {})"}
{"file":"src/watcher/handler.rs","kind":"string","line":[414,414],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"string","line":[416,416],"text":"failed to remove file {}: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[418,418],"text":"Mark mount as dirty"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[427,427],"text":"Rebuild FTS indexes once after all changes"}
{"file":"src/watcher/handler.rs","kind":"string","line":[431,431],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[438,438],"text":"Process a single file change (create or modify)."}
{"file":"src/watcher/handler.rs","kind":"comment","line":[445,445],"text":"Read file content once"}
{"file":"src/watcher/handler.rs","kind":"string","line":[447,447],"text":"failed to read {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[449,449],"text":"Hash the content"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[452,452],"text":"Check if hash changed"}
{"file":"src/watcher/handler.rs","kind":"string","line":[455,455],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[459,459],"text":"No change, skip"}
{"file":"src/watcher/handler.rs","kind":"string","line":[461,461],"text":"skipping unchanged file: {} (project: {})"}
{"file":"src/watcher/handler.rs","kind":"string","line":[469,469],"text":"indexing file: {} (project: {})"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[471,471],"text":"Count lines"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[474,474],"text":"Detect language"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[487,487],"text":"Parse source files for symbols, texts, and references"}
{"file":"src/watcher/handler.rs","kind":"string","line":[496,496],"text":"failed to parse {}: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[500,500],"text":"Extract file metadata (title and description)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[516,516],"text":"Upsert into database"}
{"file":"src/watcher/handler.rs","kind":"string","line":[519,519],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[525,525],"text":"Flush all dirty mounts to disk."}
{"file":"src/watcher/handler.rs","kind":"string","line":[532,532],"text":"mount table lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[534,534],"text":"Collect dirty RW mounts"}
{"file":"src/watcher/handler.rs","kind":"string","line":[543,543],"text":"failed to flush {}: {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[545,545],"text":"Clear dirty flag"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[555,555],"text":"Flush a single mount's index from memory to disk."}
{"file":"src/watcher/handler.rs","kind":"comment","line":[561,561],"text":"Use relative project path from workspace root"}
{"file":"src/watcher/handler.rs","kind":"string","line":[566,566],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[571,571],"text":"Clear project field for disk export - the .codeindex/ location implies the project"}
{"file":"src/watcher/handler.rs","kind":"string","line":[586,586],"text":"no files to flush for {}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[590,590],"text":"Collect languages"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[598,598],"text":"Derive project name from directory name"}
{"file":"src/watcher/handler.rs","kind":"string","line":[616,616],"text":"flushed index to disk for {}: {} files, {} symbols, {} texts, {} refs"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[627,628],"text":"Flush the entire index from memory to disk (legacy single-project).\nThis is used during initial index building before MountTable is set up."}
{"file":"src/watcher/handler.rs","kind":"string","line":[632,632],"text":"db lock poisoned: {e}"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[636,636],"text":"Collect languages"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[644,644],"text":"Derive project name from directory name"}
{"file":"src/watcher/handler.rs","kind":"string","line":[662,662],"text":"flushed index to disk: {} files, {} symbols, {} texts, {} refs"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[672,672],"text":"Count the number of lines in a byte buffer."}
{"file":"src/watcher/handler.rs","kind":"comment","line":[678,678],"text":"If file doesn't end with newline, the last line still counts"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[692,692],"text":"Helper to create a minimal .git directory (just the directory, not a real repo)"}
{"file":"src/watcher/handler.rs","kind":"docstring","line":[697,697],"text":"Helper to create a source file"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[708,708],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[711,711],"text":"Create a simple project structure"}
{"file":"src/watcher/handler.rs","kind":"string","line":[715,715],"text":"fn main() {\\n    println!(\\\"hello\\\");\\n}\\n"}
{"file":"src/watcher/handler.rs","kind":"string","line":[719,719],"text":"pub fn greet() -> String {\\n    \\\"hello\\\".to_string()\\n}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[722,722],"text":"Index the project (load_from_cache=false to force indexing)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[728,728],"text":"Verify: should have 2 files indexed"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[732,732],"text":"Root project has empty string"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[734,734],"text":"Search for the main function"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[744,744],"text":"Search for greet function"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[758,758],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[761,761],"text":"Create root project"}
{"file":"src/watcher/handler.rs","kind":"string","line":[763,763],"text":"fn app_main() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[765,765],"text":"Create a subproject"}
{"file":"src/watcher/handler.rs","kind":"string","line":[768,768],"text":"pub fn utility() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[770,770],"text":"Index from root (load_from_cache=false to force indexing)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[776,776],"text":"Verify: should have 2 projects"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[783,783],"text":"Root project should have app_main (search without filter, check project field)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[790,790],"text":"Subproject should have utility"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[801,801],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[804,804],"text":"Create root project"}
{"file":"src/watcher/handler.rs","kind":"string","line":[806,806],"text":"fn root_fn() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[808,808],"text":"Create nested subprojects: root > libs/core > libs/core/nested"}
{"file":"src/watcher/handler.rs","kind":"string","line":[811,811],"text":"fn core_fn() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"string","line":[815,815],"text":"fn nested_fn() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[817,817],"text":"Index from root (load_from_cache=false to force indexing)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[823,823],"text":"Verify: should have 3 projects"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[828,828],"text":"Each function should be in its respective project (search without filter, verify project)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[856,856],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[859,859],"text":"Create root with a subproject"}
{"file":"src/watcher/handler.rs","kind":"string","line":[861,861],"text":"fn root_fn() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"string","line":[865,865],"text":"fn sub_fn() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[867,867],"text":"Index (load_from_cache=false to force indexing)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[873,873],"text":"Verify: sub.rs should NOT appear in root project"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[876,876],"text":"Search without project filter - should find both"}
{"file":"src/watcher/handler.rs","kind":"string","line":[883,883],"text":"root_fn should appear exactly once"}
{"file":"src/watcher/handler.rs","kind":"string","line":[884,884],"text":"sub_fn should appear exactly once"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[886,886],"text":"Verify project assignment"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[897,897],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[900,900],"text":"Create root with two subprojects"}
{"file":"src/watcher/handler.rs","kind":"string","line":[902,902],"text":"fn main() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"string","line":[906,906],"text":"fn a() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"string","line":[910,910],"text":"fn b() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[912,912],"text":"Index (load_from_cache=false to force indexing)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[918,918],"text":"Verify mount table has all 3 mounts"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[923,923],"text":"All should be mounted (lib_a/lib_b are already based on canonicalized root)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[932,932],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[935,935],"text":"Create two projects with same-named function"}
{"file":"src/watcher/handler.rs","kind":"string","line":[937,937],"text":"fn helper() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"string","line":[941,941],"text":"fn helper() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[943,943],"text":"Index (load_from_cache=false to force indexing)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[951,951],"text":"Without filter: should find 2 helpers"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[957,957],"text":"One should be root (empty project), one should be sub"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[963,963],"text":"With sub filter: should find 1"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[974,974],"text":"Canonicalize for macOS where /var -> /private/var"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[977,977],"text":"Create deeply nested subproject"}
{"file":"src/watcher/handler.rs","kind":"string","line":[981,981],"text":"fn deep_fn() {}\\n"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[983,983],"text":"Index (load_from_cache=false to force indexing)"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[989,989],"text":"Verify relative path is correct"}
{"file":"src/watcher/handler.rs","kind":"comment","line":[995,995],"text":"Symbol should have correct project"}