@rigstate/mcp 0.4.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigstate/mcp",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "description": "Rigstate MCP Server - Model Context Protocol for AI Editors",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -15,9 +15,12 @@
15
15
  "test": "node dist/index.js --help"
16
16
  },
17
17
  "dependencies": {
18
+ "@ai-sdk/google": "^3.0.13",
19
+ "@google/generative-ai": "^0.24.1",
18
20
  "@modelcontextprotocol/sdk": "^1.0.0",
19
- "@supabase/supabase-js": "^2.39.0",
20
21
  "@rigstate/rules-engine": "0.1.0",
22
+ "@supabase/supabase-js": "^2.39.0",
23
+ "ai": "^6.0.5",
21
24
  "dotenv": "^17.2.3",
22
25
  "uuid": "^9.0.0",
23
26
  "zod": "^3.22.4"
package/roadmap.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "project": "Rigstate Core",
3
- "last_synced": "2026-01-22T20:06:06.152Z",
3
+ "last_synced": "2026-01-23T10:05:02.143Z",
4
4
  "roadmap": [
5
5
  {
6
6
  "id": "e503e35a-d480-457b-a771-63cf0297b48a",
@@ -47,7 +47,10 @@
47
47
  "metadata": null,
48
48
  "started_at": null,
49
49
  "description": null,
50
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
50
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
51
+ "source_cycle_id": null,
52
+ "archived_at": null,
53
+ "archived_reason": null
51
54
  },
52
55
  {
53
56
  "id": "8f2f2655-f846-4561-bde8-b4618fa8ae28",
@@ -89,7 +92,10 @@
89
92
  "metadata": null,
90
93
  "started_at": null,
91
94
  "description": null,
92
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
95
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
96
+ "source_cycle_id": null,
97
+ "archived_at": null,
98
+ "archived_reason": null
93
99
  },
94
100
  {
95
101
  "id": "8b31ac01-cf36-4668-98bd-3b6f83fd0042",
@@ -131,7 +137,10 @@
131
137
  "metadata": null,
132
138
  "started_at": null,
133
139
  "description": null,
134
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
140
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
141
+ "source_cycle_id": null,
142
+ "archived_at": null,
143
+ "archived_reason": null
135
144
  },
136
145
  {
137
146
  "id": "9c28bc40-043c-4c68-9235-f47b71ca5d86",
@@ -173,7 +182,10 @@
173
182
  "metadata": null,
174
183
  "started_at": null,
175
184
  "description": null,
176
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
185
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
186
+ "source_cycle_id": null,
187
+ "archived_at": null,
188
+ "archived_reason": null
177
189
  },
178
190
  {
179
191
  "id": "f3735dc7-ade5-4eee-bfd5-bb75c63fd399",
@@ -215,7 +227,10 @@
215
227
  "metadata": null,
216
228
  "started_at": null,
217
229
  "description": null,
218
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
230
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
231
+ "source_cycle_id": null,
232
+ "archived_at": null,
233
+ "archived_reason": null
219
234
  },
220
235
  {
221
236
  "id": "31ae7181-be64-4d59-80f5-7a9d880f5741",
@@ -257,7 +272,10 @@
257
272
  "metadata": null,
258
273
  "started_at": null,
259
274
  "description": null,
260
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
275
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
276
+ "source_cycle_id": null,
277
+ "archived_at": null,
278
+ "archived_reason": null
261
279
  },
262
280
  {
263
281
  "id": "aa6a6ff4-8028-4e91-8af0-0fa53c05dbb0",
@@ -299,7 +317,10 @@
299
317
  "metadata": null,
300
318
  "started_at": null,
301
319
  "description": null,
302
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
320
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
321
+ "source_cycle_id": null,
322
+ "archived_at": null,
323
+ "archived_reason": null
303
324
  },
304
325
  {
305
326
  "id": "a8e185f3-f9c5-4534-96f5-fd5d50bc84fb",
@@ -341,7 +362,10 @@
341
362
  "metadata": null,
342
363
  "started_at": null,
343
364
  "description": null,
344
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
365
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
366
+ "source_cycle_id": null,
367
+ "archived_at": null,
368
+ "archived_reason": null
345
369
  },
346
370
  {
347
371
  "id": "e1c1d0b4-f636-4f4c-99a4-736c575935fc",
@@ -383,7 +407,10 @@
383
407
  "metadata": null,
384
408
  "started_at": null,
385
409
  "description": null,
386
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
410
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
411
+ "source_cycle_id": null,
412
+ "archived_at": null,
413
+ "archived_reason": null
387
414
  },
388
415
  {
389
416
  "id": "5fca8601-8fb3-4bf9-bfb2-7bc24feda26f",
@@ -425,7 +452,10 @@
425
452
  "metadata": null,
426
453
  "started_at": null,
427
454
  "description": null,
428
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
455
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
456
+ "source_cycle_id": null,
457
+ "archived_at": null,
458
+ "archived_reason": null
429
459
  },
430
460
  {
431
461
  "id": "a8165a27-1f1d-45d5-87f4-468b2cfce98d",
@@ -467,7 +497,10 @@
467
497
  "metadata": null,
468
498
  "started_at": null,
469
499
  "description": null,
470
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
500
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
501
+ "source_cycle_id": null,
502
+ "archived_at": null,
503
+ "archived_reason": null
471
504
  },
472
505
  {
473
506
  "id": "41baefd7-baf3-44d3-9aad-8faf64fb7d6a",
@@ -509,7 +542,10 @@
509
542
  "metadata": null,
510
543
  "started_at": null,
511
544
  "description": null,
512
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
545
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
546
+ "source_cycle_id": null,
547
+ "archived_at": null,
548
+ "archived_reason": null
513
549
  },
514
550
  {
515
551
  "id": "de44fe4e-fc90-442f-87ec-8432c69324cd",
@@ -551,7 +587,10 @@
551
587
  "metadata": null,
552
588
  "started_at": null,
553
589
  "description": null,
554
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
590
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
591
+ "source_cycle_id": null,
592
+ "archived_at": null,
593
+ "archived_reason": null
555
594
  },
556
595
  {
557
596
  "id": "569aad50-0096-40c5-8e3a-41a65fb7e30f",
@@ -593,7 +632,10 @@
593
632
  "metadata": null,
594
633
  "started_at": null,
595
634
  "description": null,
596
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
635
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
636
+ "source_cycle_id": null,
637
+ "archived_at": null,
638
+ "archived_reason": null
597
639
  },
598
640
  {
599
641
  "id": "2cf3faac-067d-4a6c-99dc-938cf8bfd1b8",
@@ -635,7 +677,10 @@
635
677
  "metadata": null,
636
678
  "started_at": null,
637
679
  "description": null,
638
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
680
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
681
+ "source_cycle_id": null,
682
+ "archived_at": null,
683
+ "archived_reason": null
639
684
  },
640
685
  {
641
686
  "id": "a0500716-55ec-4e66-99b0-4f51f59243f1",
@@ -677,7 +722,10 @@
677
722
  "metadata": null,
678
723
  "started_at": null,
679
724
  "description": null,
680
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
725
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
726
+ "source_cycle_id": null,
727
+ "archived_at": null,
728
+ "archived_reason": null
681
729
  },
682
730
  {
683
731
  "id": "4d51757b-2c33-4e14-9cf4-0d4dc638c6e9",
@@ -719,7 +767,10 @@
719
767
  "metadata": null,
720
768
  "started_at": null,
721
769
  "description": null,
722
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
770
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
771
+ "source_cycle_id": null,
772
+ "archived_at": null,
773
+ "archived_reason": null
723
774
  },
724
775
  {
725
776
  "id": "8eb5f854-30e0-41d4-bb88-27d854e3c60e",
@@ -761,7 +812,10 @@
761
812
  "metadata": null,
762
813
  "started_at": null,
763
814
  "description": null,
764
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
815
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
816
+ "source_cycle_id": null,
817
+ "archived_at": null,
818
+ "archived_reason": null
765
819
  },
766
820
  {
767
821
  "id": "3784e7a0-629c-419d-9327-1743444466dc",
@@ -803,7 +857,10 @@
803
857
  "metadata": null,
804
858
  "started_at": null,
805
859
  "description": null,
806
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
860
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
861
+ "source_cycle_id": null,
862
+ "archived_at": null,
863
+ "archived_reason": null
807
864
  },
808
865
  {
809
866
  "id": "d95fba4b-170c-4713-a80d-dc4d255a281c",
@@ -845,7 +902,10 @@
845
902
  "metadata": null,
846
903
  "started_at": null,
847
904
  "description": null,
848
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
905
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
906
+ "source_cycle_id": null,
907
+ "archived_at": null,
908
+ "archived_reason": null
849
909
  },
850
910
  {
851
911
  "id": "19688111-5f4c-4a4b-a826-249643adeb80",
@@ -887,7 +947,10 @@
887
947
  "metadata": null,
888
948
  "started_at": null,
889
949
  "description": null,
890
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
950
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
951
+ "source_cycle_id": null,
952
+ "archived_at": null,
953
+ "archived_reason": null
891
954
  },
892
955
  {
893
956
  "id": "6c2d2efe-70a9-44fc-8b53-53d24142adb7",
@@ -929,7 +992,10 @@
929
992
  "metadata": null,
930
993
  "started_at": null,
931
994
  "description": null,
932
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
995
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
996
+ "source_cycle_id": null,
997
+ "archived_at": null,
998
+ "archived_reason": null
933
999
  },
934
1000
  {
935
1001
  "id": "cdfe0a5c-3287-453c-87b5-afa4138d90b7",
@@ -971,7 +1037,10 @@
971
1037
  "metadata": null,
972
1038
  "started_at": null,
973
1039
  "description": null,
974
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1040
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1041
+ "source_cycle_id": null,
1042
+ "archived_at": null,
1043
+ "archived_reason": null
975
1044
  },
976
1045
  {
977
1046
  "id": "7a452451-23d0-4a00-ae94-36eae05adac0",
@@ -1013,7 +1082,10 @@
1013
1082
  "metadata": null,
1014
1083
  "started_at": null,
1015
1084
  "description": null,
1016
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1085
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1086
+ "source_cycle_id": null,
1087
+ "archived_at": null,
1088
+ "archived_reason": null
1017
1089
  },
1018
1090
  {
1019
1091
  "id": "05d106da-37a5-46f0-bca1-f19746aa5e0f",
@@ -1055,7 +1127,10 @@
1055
1127
  "metadata": null,
1056
1128
  "started_at": null,
1057
1129
  "description": null,
1058
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1130
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1131
+ "source_cycle_id": null,
1132
+ "archived_at": null,
1133
+ "archived_reason": null
1059
1134
  },
1060
1135
  {
1061
1136
  "id": "6dfd911a-ec75-4a73-a91f-f2ea0943f6c0",
@@ -1100,7 +1175,10 @@
1100
1175
  "metadata": null,
1101
1176
  "started_at": null,
1102
1177
  "description": null,
1103
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1178
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1179
+ "source_cycle_id": null,
1180
+ "archived_at": null,
1181
+ "archived_reason": null
1104
1182
  },
1105
1183
  {
1106
1184
  "id": "94c8d12a-1aed-4745-89dc-e95c8ff9be1a",
@@ -1145,7 +1223,10 @@
1145
1223
  "metadata": null,
1146
1224
  "started_at": null,
1147
1225
  "description": null,
1148
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1226
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1227
+ "source_cycle_id": null,
1228
+ "archived_at": null,
1229
+ "archived_reason": null
1149
1230
  },
1150
1231
  {
1151
1232
  "id": "bde519dc-b6ff-443c-b39b-a05f3d85b965",
@@ -1190,7 +1271,10 @@
1190
1271
  "metadata": null,
1191
1272
  "started_at": null,
1192
1273
  "description": null,
1193
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1274
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1275
+ "source_cycle_id": null,
1276
+ "archived_at": null,
1277
+ "archived_reason": null
1194
1278
  },
1195
1279
  {
1196
1280
  "id": "0b8da658-fc25-423a-a556-bddfb50f6fca",
@@ -1235,7 +1319,10 @@
1235
1319
  "metadata": null,
1236
1320
  "started_at": null,
1237
1321
  "description": null,
1238
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1322
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1323
+ "source_cycle_id": null,
1324
+ "archived_at": null,
1325
+ "archived_reason": null
1239
1326
  },
1240
1327
  {
1241
1328
  "id": "2ff8f7ef-0351-4b54-aaf2-ad0bf984af4b",
@@ -1277,7 +1364,10 @@
1277
1364
  "metadata": null,
1278
1365
  "started_at": null,
1279
1366
  "description": null,
1280
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1367
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1368
+ "source_cycle_id": null,
1369
+ "archived_at": null,
1370
+ "archived_reason": null
1281
1371
  },
1282
1372
  {
1283
1373
  "id": "7f70a61d-be0a-40f3-821f-d0c0740bfce1",
@@ -1319,7 +1409,100 @@
1319
1409
  "metadata": null,
1320
1410
  "started_at": null,
1321
1411
  "description": null,
1322
- "updated_at": "2026-01-21T18:40:49.607549+00:00"
1412
+ "updated_at": "2026-01-21T18:40:49.607549+00:00",
1413
+ "source_cycle_id": null,
1414
+ "archived_at": null,
1415
+ "archived_reason": null
1416
+ },
1417
+ {
1418
+ "id": "2cb8d1a2-a2c0-4bdd-b720-7add6f97d658",
1419
+ "project_id": "bb9f8445-39fd-438c-8ab6-8057f5514395",
1420
+ "step_number": 1025,
1421
+ "title": "[SOVEREIGN] Autonomous REFAC: File Split",
1422
+ "status": "ACTIVE",
1423
+ "prompt_content": "Decompose apps/web/src/components/admin/global-nexus-sovereign.tsx into smaller, modular components to satisfy ARC-001.",
1424
+ "verification_criteria": null,
1425
+ "type": "CODE",
1426
+ "created_at": "2026-01-22T23:08:30.360978+00:00",
1427
+ "sprint_id": 0,
1428
+ "sprint_focus": "Foundation",
1429
+ "sprint_description": null,
1430
+ "estimated_minutes": 20,
1431
+ "verification_type": null,
1432
+ "verification_path": null,
1433
+ "verification_match": null,
1434
+ "summary": null,
1435
+ "sprint_number": 1,
1436
+ "escalated_by": null,
1437
+ "escalated_at": "2026-01-22T23:08:30.360978+00:00",
1438
+ "visibility": "private",
1439
+ "priority": "MEDIUM",
1440
+ "is_legacy": false,
1441
+ "completed_at": null,
1442
+ "uid": "T-03feaa",
1443
+ "severity": null,
1444
+ "category": "ARCHITECTURE",
1445
+ "origin_id": null,
1446
+ "architectural_brief": "Frank has identified structural debt in apps/web/src/components/admin/global-nexus-sovereign.tsx. \n Governance: SOVEREIGN. Worker dispatched to apply fixes.",
1447
+ "icon": null,
1448
+ "tags": null,
1449
+ "context_summary": null,
1450
+ "origin_feature_id": null,
1451
+ "feature_id": null,
1452
+ "checklist": [],
1453
+ "origin_type": "AUTONOMOUS",
1454
+ "metadata": null,
1455
+ "started_at": null,
1456
+ "description": null,
1457
+ "updated_at": "2026-01-22T23:08:30.360978+00:00",
1458
+ "source_cycle_id": "1d2da87d-3b90-4a69-930e-d60c2380427c",
1459
+ "archived_at": null,
1460
+ "archived_reason": null
1461
+ },
1462
+ {
1463
+ "id": "622cbd96-ea02-4180-ba17-74985a1dadc5",
1464
+ "project_id": "bb9f8445-39fd-438c-8ab6-8057f5514395",
1465
+ "step_number": 1026,
1466
+ "title": "[SOVEREIGN] Autonomous SECURITY_SCAN: Security Patch",
1467
+ "status": "ACTIVE",
1468
+ "prompt_content": "Apply missing security validators (Zod/RLS) identified in latest pulse.",
1469
+ "verification_criteria": null,
1470
+ "type": "CODE",
1471
+ "created_at": "2026-01-23T00:58:55.548607+00:00",
1472
+ "sprint_id": 0,
1473
+ "sprint_focus": "Foundation",
1474
+ "sprint_description": null,
1475
+ "estimated_minutes": 20,
1476
+ "verification_type": null,
1477
+ "verification_path": null,
1478
+ "verification_match": null,
1479
+ "summary": null,
1480
+ "sprint_number": 1,
1481
+ "escalated_by": null,
1482
+ "escalated_at": "2026-01-23T00:58:55.548607+00:00",
1483
+ "visibility": "private",
1484
+ "priority": "HIGH",
1485
+ "is_legacy": false,
1486
+ "completed_at": null,
1487
+ "uid": "T-089a43",
1488
+ "severity": null,
1489
+ "category": "SECURITY",
1490
+ "origin_id": null,
1491
+ "architectural_brief": "Frank has identified security gaps in Project Core. \n Governance: SOVEREIGN. Worker dispatched to apply fixes.",
1492
+ "icon": null,
1493
+ "tags": null,
1494
+ "context_summary": null,
1495
+ "origin_feature_id": null,
1496
+ "feature_id": null,
1497
+ "checklist": [],
1498
+ "origin_type": "AUTONOMOUS",
1499
+ "metadata": null,
1500
+ "started_at": null,
1501
+ "description": null,
1502
+ "updated_at": "2026-01-23T00:58:55.548607+00:00",
1503
+ "source_cycle_id": "80b163aa-4b22-450c-bfd5-e4198ec5fca5",
1504
+ "archived_at": null,
1505
+ "archived_reason": null
1323
1506
  }
1324
1507
  ]
1325
1508
  }
@@ -96,7 +96,8 @@ export async function authenticateApiKey(apiKey: string): Promise<{
96
96
  .then();
97
97
 
98
98
  // Create a user-scoped client for subsequent operations
99
- const userSupabase = createSupabaseClient(SUPABASE_URL, SUPABASE_ANON_KEY);
99
+ // Use the most privileged key available (SERVICE_KEY or ANON_KEY)
100
+ const userSupabase = createSupabaseClient(SUPABASE_URL, clientKey);
100
101
 
101
102
  return {
102
103
  success: true,
@@ -34,15 +34,27 @@ architecture rules, decisions, and constraints.`,
34
34
  }
35
35
  });
36
36
 
37
- // Simple embedding generation using text normalization
38
- async function generateQueryEmbedding(query: string): Promise<number[]> {
39
- // For MCP server, we'll use the match_memories_text RPC if available,
40
- // or fall back to keyword-based search.
41
- // This is a placeholder - the actual embedding should be done via the Supabase edge function
42
- // or passed through to the main Rigstate API.
43
-
44
- // For now, return null to trigger keyword fallback
45
- return [];
37
+ // Simple embedding generation using Google Gemini
38
+ async function generateQueryEmbedding(query: string): Promise<number[] | null> {
39
+ const apiKey = process.env.GOOGLE_GENERATIVE_AI_API_KEY;
40
+ if (!apiKey) {
41
+ console.warn('GOOGLE_GENERATIVE_AI_API_KEY not found, skipping vector search.');
42
+ return null;
43
+ }
44
+
45
+ try {
46
+ const { google } = await import('@ai-sdk/google');
47
+ const { embed } = await import('ai');
48
+
49
+ const { embedding } = await embed({
50
+ model: google.embedding('text-embedding-004'),
51
+ value: query.replace(/\n/g, ' '),
52
+ });
53
+ return embedding;
54
+ } catch (error) {
55
+ console.error('Failed to generate embedding for search:', error);
56
+ return null;
57
+ }
46
58
  }
47
59
 
48
60
  export async function queryBrain(
@@ -67,45 +79,24 @@ export async function queryBrain(
67
79
 
68
80
  // Try semantic search first using the match_memories RPC
69
81
  // This requires the embedding to be generated, so we'll try
70
- // a text-based search as fallback
82
+ // Generate embedding if possible for semantic search
83
+ const embedding = await generateQueryEmbedding(query);
71
84
  let memories: MemoryRecord[] = [];
72
85
 
73
- // Attempt keyword-based search using ilike on content
74
- // This is a simpler approach that works without embeddings
75
- const searchTerms = query.toLowerCase().split(/\s+/).filter(t => t.length > 2);
76
-
77
- if (searchTerms.length > 0) {
78
- // Build OR condition for fuzzy matching
79
- const orConditions = searchTerms.map(term => `content.ilike.%${term}%`).join(',');
80
-
81
- const { data: keywordMatches, error: searchError } = await supabase
82
- .from('project_memories')
83
- .select('id, content, category, tags, importance, created_at')
84
- .eq('project_id', projectId)
85
- .eq('is_active', true)
86
- .or(orConditions)
87
- .order('importance', { ascending: false, nullsFirst: false })
88
- .limit(limit);
89
-
90
- if (searchError) {
91
- console.error('Search error:', searchError);
92
- }
93
-
94
- if (keywordMatches) {
95
- memories = keywordMatches.map(m => ({
96
- id: m.id,
97
- content: m.content,
98
- category: m.category || 'general',
99
- tags: m.tags || [],
100
- netVotes: m.importance || 0,
101
- createdAt: m.created_at
102
- }));
103
- }
104
- }
105
-
106
- // If no keyword matches, fetch recent memories
107
- if (memories.length === 0) {
108
- const { data: recentMemories, error: recentError } = await supabase
86
+ // Use the hybrid search RPC
87
+ const { data: searchResults, error: searchError } = await supabase
88
+ .rpc('hybrid_search_memories', {
89
+ p_project_id: projectId,
90
+ p_query: query,
91
+ p_embedding: embedding,
92
+ p_limit: limit,
93
+ p_similarity_threshold: threshold || 0.2
94
+ });
95
+
96
+ if (searchError) {
97
+ console.error('Hybrid search error:', searchError);
98
+ // Fallback to basic recent fetch if RPC fails
99
+ const { data: recentMemories } = await supabase
109
100
  .from('project_memories')
110
101
  .select('id, content, category, tags, importance, created_at')
111
102
  .eq('project_id', projectId)
@@ -113,10 +104,6 @@ export async function queryBrain(
113
104
  .order('created_at', { ascending: false })
114
105
  .limit(limit);
115
106
 
116
- if (recentError) {
117
- console.error('Recent error:', recentError);
118
- }
119
-
120
107
  if (recentMemories) {
121
108
  memories = recentMemories.map(m => ({
122
109
  id: m.id,
@@ -127,17 +114,30 @@ export async function queryBrain(
127
114
  createdAt: m.created_at
128
115
  }));
129
116
  }
117
+ } else if (searchResults) {
118
+ memories = searchResults.map((m: any) => ({
119
+ id: m.id,
120
+ content: m.content,
121
+ category: m.category,
122
+ tags: m.tags,
123
+ netVotes: m.importance,
124
+ createdAt: m.created_at
125
+ }));
130
126
  }
131
127
 
132
128
  // Format memories into a readable context block
133
129
  const contextLines = memories.map((m) => {
134
130
  const voteIndicator = m.netVotes && m.netVotes < 0 ? ` [⚠️ POORLY RATED: ${m.netVotes}]` : '';
135
- const tagStr = m.tags.length > 0 ? ` [${m.tags.join(', ')}]` : '';
136
- return `- [${m.category.toUpperCase()}]${tagStr}${voteIndicator}: ${m.content}`;
131
+ const tagStr = m.tags && m.tags.length > 0 ? ` [${m.tags.join(', ')}]` : '';
132
+ const category = m.category ? m.category.toUpperCase() : 'GENERAL';
133
+ return `- [${category}]${tagStr}${voteIndicator}: ${m.content}`;
137
134
  });
138
135
 
136
+ const searchType = embedding ? 'TRIPLE-HYBRID (Vector + FTS + Fuzzy)' : 'HYBRID (FTS + Fuzzy)';
137
+
139
138
  const formatted = memories.length > 0
140
139
  ? `=== PROJECT BRAIN: RELEVANT MEMORIES ===
140
+ Search Mode: ${searchType}
141
141
  Query: "${query}"
142
142
  Found ${memories.length} relevant memories:
143
143