superlocalmemory 2.8.6 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/LICENSE +9 -1
  2. package/NOTICE +63 -0
  3. package/README.md +165 -480
  4. package/bin/slm +17 -449
  5. package/bin/slm-npm +62 -48
  6. package/conftest.py +5 -0
  7. package/docs/api-reference.md +284 -0
  8. package/docs/architecture.md +149 -0
  9. package/docs/auto-memory.md +150 -0
  10. package/docs/cli-reference.md +276 -0
  11. package/docs/compliance.md +191 -0
  12. package/docs/configuration.md +182 -0
  13. package/docs/getting-started.md +102 -0
  14. package/docs/ide-setup.md +261 -0
  15. package/docs/mcp-tools.md +220 -0
  16. package/docs/migration-from-v2.md +170 -0
  17. package/docs/profiles.md +173 -0
  18. package/docs/troubleshooting.md +310 -0
  19. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  20. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  21. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  22. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  23. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  24. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  25. package/ide/configs/cursor-mcp.json +15 -0
  26. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  27. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  28. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  29. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  30. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  31. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  32. package/{configs → ide/configs}/zed-mcp.json +2 -2
  33. package/{hooks → ide/hooks}/context-hook.js +9 -20
  34. package/ide/hooks/memory-list-skill.js +70 -0
  35. package/ide/hooks/memory-profile-skill.js +101 -0
  36. package/ide/hooks/memory-recall-skill.js +62 -0
  37. package/ide/hooks/memory-remember-skill.js +68 -0
  38. package/ide/hooks/memory-reset-skill.js +160 -0
  39. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  40. package/ide/integrations/langchain/README.md +106 -0
  41. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  42. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  43. package/ide/integrations/langchain/pyproject.toml +38 -0
  44. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  45. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  46. package/ide/integrations/langchain/tests/test_security.py +117 -0
  47. package/ide/integrations/llamaindex/README.md +81 -0
  48. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  49. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  50. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  51. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  52. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  53. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  54. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  55. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  56. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  57. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  58. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  59. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  60. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  61. package/package.json +13 -22
  62. package/pyproject.toml +85 -0
  63. package/scripts/build-dmg.sh +417 -0
  64. package/scripts/install-skills.ps1 +334 -0
  65. package/scripts/postinstall.js +2 -2
  66. package/scripts/start-dashboard.ps1 +52 -0
  67. package/scripts/start-dashboard.sh +41 -0
  68. package/scripts/sync-wiki.ps1 +127 -0
  69. package/scripts/sync-wiki.sh +82 -0
  70. package/scripts/test-dmg.sh +161 -0
  71. package/scripts/test-npm-package.ps1 +252 -0
  72. package/scripts/test-npm-package.sh +207 -0
  73. package/scripts/verify-install.ps1 +294 -0
  74. package/scripts/verify-install.sh +266 -0
  75. package/src/superlocalmemory/__init__.py +0 -0
  76. package/src/superlocalmemory/attribution/__init__.py +9 -0
  77. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  78. package/src/superlocalmemory/attribution/signer.py +153 -0
  79. package/src/superlocalmemory/attribution/watermark.py +189 -0
  80. package/src/superlocalmemory/cli/__init__.py +5 -0
  81. package/src/superlocalmemory/cli/commands.py +245 -0
  82. package/src/superlocalmemory/cli/main.py +89 -0
  83. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  84. package/src/superlocalmemory/cli/post_install.py +99 -0
  85. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  86. package/src/superlocalmemory/compliance/__init__.py +0 -0
  87. package/src/superlocalmemory/compliance/abac.py +204 -0
  88. package/src/superlocalmemory/compliance/audit.py +314 -0
  89. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  90. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  91. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  92. package/src/superlocalmemory/compliance/retention.py +232 -0
  93. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  94. package/src/superlocalmemory/core/__init__.py +0 -0
  95. package/src/superlocalmemory/core/config.py +391 -0
  96. package/src/superlocalmemory/core/embeddings.py +293 -0
  97. package/src/superlocalmemory/core/engine.py +701 -0
  98. package/src/superlocalmemory/core/hooks.py +65 -0
  99. package/src/superlocalmemory/core/maintenance.py +172 -0
  100. package/src/superlocalmemory/core/modes.py +140 -0
  101. package/src/superlocalmemory/core/profiles.py +234 -0
  102. package/src/superlocalmemory/core/registry.py +117 -0
  103. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  104. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  105. package/src/superlocalmemory/encoding/__init__.py +0 -0
  106. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  107. package/src/superlocalmemory/encoding/emotional.py +125 -0
  108. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  109. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  110. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  111. package/src/superlocalmemory/encoding/foresight.py +91 -0
  112. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  113. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  114. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  115. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  116. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  117. package/src/superlocalmemory/encoding/type_router.py +235 -0
  118. package/src/superlocalmemory/hooks/__init__.py +3 -0
  119. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  120. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  121. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  122. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  123. package/src/superlocalmemory/infra/__init__.py +3 -0
  124. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  125. package/src/superlocalmemory/infra/backup.py +317 -0
  126. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  127. package/src/superlocalmemory/infra/event_bus.py +381 -0
  128. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  129. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  130. package/src/superlocalmemory/learning/__init__.py +0 -0
  131. package/src/superlocalmemory/learning/adaptive.py +172 -0
  132. package/src/superlocalmemory/learning/behavioral.py +490 -0
  133. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  134. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  135. package/src/superlocalmemory/learning/cross_project.py +399 -0
  136. package/src/superlocalmemory/learning/database.py +376 -0
  137. package/src/superlocalmemory/learning/engagement.py +323 -0
  138. package/src/superlocalmemory/learning/features.py +138 -0
  139. package/src/superlocalmemory/learning/feedback.py +316 -0
  140. package/src/superlocalmemory/learning/outcomes.py +255 -0
  141. package/src/superlocalmemory/learning/project_context.py +366 -0
  142. package/src/superlocalmemory/learning/ranker.py +155 -0
  143. package/src/superlocalmemory/learning/source_quality.py +303 -0
  144. package/src/superlocalmemory/learning/workflows.py +309 -0
  145. package/src/superlocalmemory/llm/__init__.py +0 -0
  146. package/src/superlocalmemory/llm/backbone.py +316 -0
  147. package/src/superlocalmemory/math/__init__.py +0 -0
  148. package/src/superlocalmemory/math/fisher.py +356 -0
  149. package/src/superlocalmemory/math/langevin.py +398 -0
  150. package/src/superlocalmemory/math/sheaf.py +257 -0
  151. package/src/superlocalmemory/mcp/__init__.py +0 -0
  152. package/src/superlocalmemory/mcp/resources.py +245 -0
  153. package/src/superlocalmemory/mcp/server.py +61 -0
  154. package/src/superlocalmemory/mcp/tools.py +18 -0
  155. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  156. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  157. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  158. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  159. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  160. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  161. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  162. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  163. package/src/superlocalmemory/retrieval/engine.py +390 -0
  164. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  165. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  166. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  167. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  168. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  169. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  170. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  171. package/src/superlocalmemory/server/__init__.py +1 -0
  172. package/src/superlocalmemory/server/api.py +248 -0
  173. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  174. package/src/superlocalmemory/server/routes/agents.py +107 -0
  175. package/src/superlocalmemory/server/routes/backup.py +91 -0
  176. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  177. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  178. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  179. package/src/superlocalmemory/server/routes/events.py +183 -0
  180. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  181. package/src/superlocalmemory/server/routes/learning.py +273 -0
  182. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  183. package/src/superlocalmemory/server/routes/memories.py +399 -0
  184. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  185. package/src/superlocalmemory/server/routes/stats.py +346 -0
  186. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  187. package/src/superlocalmemory/server/routes/ws.py +82 -0
  188. package/src/superlocalmemory/server/security_middleware.py +57 -0
  189. package/src/superlocalmemory/server/ui.py +245 -0
  190. package/src/superlocalmemory/storage/__init__.py +0 -0
  191. package/src/superlocalmemory/storage/access_control.py +182 -0
  192. package/src/superlocalmemory/storage/database.py +594 -0
  193. package/src/superlocalmemory/storage/migrations.py +303 -0
  194. package/src/superlocalmemory/storage/models.py +406 -0
  195. package/src/superlocalmemory/storage/schema.py +726 -0
  196. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  197. package/src/superlocalmemory/trust/__init__.py +0 -0
  198. package/src/superlocalmemory/trust/gate.py +130 -0
  199. package/src/superlocalmemory/trust/provenance.py +124 -0
  200. package/src/superlocalmemory/trust/scorer.py +347 -0
  201. package/src/superlocalmemory/trust/signals.py +153 -0
  202. package/ui/index.html +278 -5
  203. package/ui/js/auto-settings.js +70 -0
  204. package/ui/js/dashboard.js +90 -0
  205. package/ui/js/fact-detail.js +92 -0
  206. package/ui/js/feedback.js +2 -2
  207. package/ui/js/ide-status.js +102 -0
  208. package/ui/js/math-health.js +98 -0
  209. package/ui/js/recall-lab.js +127 -0
  210. package/ui/js/settings.js +2 -2
  211. package/ui/js/trust-dashboard.js +73 -0
  212. package/api_server.py +0 -724
  213. package/bin/aider-smart +0 -72
  214. package/bin/superlocalmemoryv2-learning +0 -4
  215. package/bin/superlocalmemoryv2-list +0 -3
  216. package/bin/superlocalmemoryv2-patterns +0 -4
  217. package/bin/superlocalmemoryv2-profile +0 -3
  218. package/bin/superlocalmemoryv2-recall +0 -3
  219. package/bin/superlocalmemoryv2-remember +0 -3
  220. package/bin/superlocalmemoryv2-reset +0 -3
  221. package/bin/superlocalmemoryv2-status +0 -3
  222. package/configs/chatgpt-desktop-mcp.json +0 -16
  223. package/configs/cursor-mcp.json +0 -15
  224. package/hooks/memory-list-skill.js +0 -139
  225. package/hooks/memory-profile-skill.js +0 -273
  226. package/hooks/memory-recall-skill.js +0 -114
  227. package/hooks/memory-remember-skill.js +0 -127
  228. package/hooks/memory-reset-skill.js +0 -274
  229. package/mcp_server.py +0 -1808
  230. package/requirements-core.txt +0 -22
  231. package/requirements-learning.txt +0 -12
  232. package/requirements.txt +0 -12
  233. package/src/agent_registry.py +0 -411
  234. package/src/auth_middleware.py +0 -61
  235. package/src/auto_backup.py +0 -459
  236. package/src/behavioral/__init__.py +0 -49
  237. package/src/behavioral/behavioral_listener.py +0 -203
  238. package/src/behavioral/behavioral_patterns.py +0 -275
  239. package/src/behavioral/cross_project_transfer.py +0 -206
  240. package/src/behavioral/outcome_inference.py +0 -194
  241. package/src/behavioral/outcome_tracker.py +0 -193
  242. package/src/behavioral/tests/__init__.py +0 -4
  243. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  244. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  245. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  246. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  247. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  248. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  249. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  250. package/src/cache_manager.py +0 -518
  251. package/src/compliance/__init__.py +0 -48
  252. package/src/compliance/abac_engine.py +0 -149
  253. package/src/compliance/abac_middleware.py +0 -116
  254. package/src/compliance/audit_db.py +0 -215
  255. package/src/compliance/audit_logger.py +0 -148
  256. package/src/compliance/retention_manager.py +0 -289
  257. package/src/compliance/retention_scheduler.py +0 -186
  258. package/src/compliance/tests/__init__.py +0 -4
  259. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  260. package/src/compliance/tests/test_abac_engine.py +0 -124
  261. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  262. package/src/compliance/tests/test_audit_db.py +0 -123
  263. package/src/compliance/tests/test_audit_logger.py +0 -98
  264. package/src/compliance/tests/test_mcp_audit.py +0 -128
  265. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  266. package/src/compliance/tests/test_retention_manager.py +0 -131
  267. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  268. package/src/compression/__init__.py +0 -25
  269. package/src/compression/cli.py +0 -150
  270. package/src/compression/cold_storage.py +0 -217
  271. package/src/compression/config.py +0 -72
  272. package/src/compression/orchestrator.py +0 -133
  273. package/src/compression/tier2_compressor.py +0 -228
  274. package/src/compression/tier3_compressor.py +0 -153
  275. package/src/compression/tier_classifier.py +0 -148
  276. package/src/db_connection_manager.py +0 -536
  277. package/src/embedding_engine.py +0 -63
  278. package/src/embeddings/__init__.py +0 -47
  279. package/src/embeddings/cache.py +0 -70
  280. package/src/embeddings/cli.py +0 -113
  281. package/src/embeddings/constants.py +0 -47
  282. package/src/embeddings/database.py +0 -91
  283. package/src/embeddings/engine.py +0 -247
  284. package/src/embeddings/model_loader.py +0 -145
  285. package/src/event_bus.py +0 -562
  286. package/src/graph/__init__.py +0 -36
  287. package/src/graph/build_helpers.py +0 -74
  288. package/src/graph/cli.py +0 -87
  289. package/src/graph/cluster_builder.py +0 -188
  290. package/src/graph/cluster_summary.py +0 -148
  291. package/src/graph/constants.py +0 -47
  292. package/src/graph/edge_builder.py +0 -162
  293. package/src/graph/entity_extractor.py +0 -95
  294. package/src/graph/graph_core.py +0 -226
  295. package/src/graph/graph_search.py +0 -231
  296. package/src/graph/hierarchical.py +0 -207
  297. package/src/graph/schema.py +0 -99
  298. package/src/graph_engine.py +0 -52
  299. package/src/hnsw_index.py +0 -628
  300. package/src/hybrid_search.py +0 -46
  301. package/src/learning/__init__.py +0 -217
  302. package/src/learning/adaptive_ranker.py +0 -682
  303. package/src/learning/bootstrap/__init__.py +0 -69
  304. package/src/learning/bootstrap/constants.py +0 -93
  305. package/src/learning/bootstrap/db_queries.py +0 -316
  306. package/src/learning/bootstrap/sampling.py +0 -82
  307. package/src/learning/bootstrap/text_utils.py +0 -71
  308. package/src/learning/cross_project_aggregator.py +0 -857
  309. package/src/learning/db/__init__.py +0 -40
  310. package/src/learning/db/constants.py +0 -44
  311. package/src/learning/db/schema.py +0 -279
  312. package/src/learning/engagement_tracker.py +0 -628
  313. package/src/learning/feature_extractor.py +0 -708
  314. package/src/learning/feedback_collector.py +0 -806
  315. package/src/learning/learning_db.py +0 -915
  316. package/src/learning/project_context_manager.py +0 -572
  317. package/src/learning/ranking/__init__.py +0 -33
  318. package/src/learning/ranking/constants.py +0 -84
  319. package/src/learning/ranking/helpers.py +0 -278
  320. package/src/learning/source_quality_scorer.py +0 -676
  321. package/src/learning/synthetic_bootstrap.py +0 -755
  322. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  323. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  324. package/src/learning/tests/test_aggregator.py +0 -306
  325. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  326. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  327. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  328. package/src/learning/tests/test_feedback_collector.py +0 -294
  329. package/src/learning/tests/test_learning_db.py +0 -602
  330. package/src/learning/tests/test_learning_db_v28.py +0 -110
  331. package/src/learning/tests/test_learning_init_v28.py +0 -48
  332. package/src/learning/tests/test_outcome_signals.py +0 -48
  333. package/src/learning/tests/test_project_context.py +0 -292
  334. package/src/learning/tests/test_schema_migration.py +0 -319
  335. package/src/learning/tests/test_signal_inference.py +0 -397
  336. package/src/learning/tests/test_source_quality.py +0 -351
  337. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  338. package/src/learning/tests/test_workflow_miner.py +0 -318
  339. package/src/learning/workflow_pattern_miner.py +0 -655
  340. package/src/lifecycle/__init__.py +0 -54
  341. package/src/lifecycle/bounded_growth.py +0 -239
  342. package/src/lifecycle/compaction_engine.py +0 -226
  343. package/src/lifecycle/lifecycle_engine.py +0 -355
  344. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  345. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  346. package/src/lifecycle/retention_policy.py +0 -285
  347. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  348. package/src/lifecycle/tests/test_compaction.py +0 -179
  349. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  350. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  351. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  352. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  353. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  354. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  355. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  356. package/src/mcp_tools_v28.py +0 -281
  357. package/src/memory/__init__.py +0 -36
  358. package/src/memory/cli.py +0 -205
  359. package/src/memory/constants.py +0 -39
  360. package/src/memory/helpers.py +0 -28
  361. package/src/memory/schema.py +0 -166
  362. package/src/memory-profiles.py +0 -595
  363. package/src/memory-reset.py +0 -491
  364. package/src/memory_compression.py +0 -989
  365. package/src/memory_store_v2.py +0 -1155
  366. package/src/migrate_v1_to_v2.py +0 -629
  367. package/src/pattern_learner.py +0 -34
  368. package/src/patterns/__init__.py +0 -24
  369. package/src/patterns/analyzers.py +0 -251
  370. package/src/patterns/learner.py +0 -271
  371. package/src/patterns/scoring.py +0 -171
  372. package/src/patterns/store.py +0 -225
  373. package/src/patterns/terminology.py +0 -140
  374. package/src/provenance_tracker.py +0 -312
  375. package/src/qualixar_attribution.py +0 -139
  376. package/src/qualixar_watermark.py +0 -78
  377. package/src/query_optimizer.py +0 -511
  378. package/src/rate_limiter.py +0 -83
  379. package/src/search/__init__.py +0 -20
  380. package/src/search/cli.py +0 -77
  381. package/src/search/constants.py +0 -26
  382. package/src/search/engine.py +0 -241
  383. package/src/search/fusion.py +0 -122
  384. package/src/search/index_loader.py +0 -114
  385. package/src/search/methods.py +0 -162
  386. package/src/search_engine_v2.py +0 -401
  387. package/src/setup_validator.py +0 -482
  388. package/src/subscription_manager.py +0 -391
  389. package/src/tree/__init__.py +0 -59
  390. package/src/tree/builder.py +0 -185
  391. package/src/tree/nodes.py +0 -202
  392. package/src/tree/queries.py +0 -257
  393. package/src/tree/schema.py +0 -80
  394. package/src/tree_manager.py +0 -19
  395. package/src/trust/__init__.py +0 -45
  396. package/src/trust/constants.py +0 -66
  397. package/src/trust/queries.py +0 -157
  398. package/src/trust/schema.py +0 -95
  399. package/src/trust/scorer.py +0 -299
  400. package/src/trust/signals.py +0 -95
  401. package/src/trust_scorer.py +0 -44
  402. package/ui/app.js +0 -1588
  403. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  404. package/ui/js/graph-cytoscape.js +0 -1168
  405. package/ui/js/graph-d3-backup.js +0 -32
  406. package/ui/js/graph.js +0 -32
  407. package/ui_server.py +0 -286
  408. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  409. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  410. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  411. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  412. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  413. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  414. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  415. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  416. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  417. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  418. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  419. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  420. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  421. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  422. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  423. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  424. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  425. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  426. /package/{completions → ide/completions}/slm.bash +0 -0
  427. /package/{completions → ide/completions}/slm.zsh +0 -0
  428. /package/{configs → ide/configs}/cody-commands.json +0 -0
  429. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
  430. /package/{install.ps1 → scripts/install.ps1} +0 -0
  431. /package/{install.sh → scripts/install.sh} +0 -0
package/src/hnsw_index.py DELETED
@@ -1,628 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """HNSWIndex - Fast Approximate Nearest Neighbor Search for SuperLocalMemory V2
5
-
6
- Implements HNSW (Hierarchical Navigable Small World) algorithm for:
7
- - Sub-10ms vector similarity search for 10K+ memories
8
- - Incremental updates without full rebuild
9
- - Disk persistence for instant startup
10
- - Graceful fallback to linear search if hnswlib unavailable
11
-
12
- All processing is local - no external APIs.
13
-
14
- LIMITS:
15
- - MAX_MEMORIES_FOR_HNSW: 100,000 (prevents memory exhaustion)
16
- - MAX_DIMENSION: 5000 (typical: 384 for sentence embeddings)
17
- - Performance target: <10ms for 10K memories, <50ms for 100K memories
18
- """
19
- # SECURITY: HNSW index limits to prevent resource exhaustion
20
- MAX_MEMORIES_FOR_HNSW = 100_000
21
- MAX_DIMENSION = 5000
22
- DEFAULT_M = 16 # HNSW parameter: number of connections per layer
23
- DEFAULT_EF_CONSTRUCTION = 200 # HNSW parameter: size of dynamic candidate list
24
- DEFAULT_EF_SEARCH = 50 # HNSW parameter: search-time candidate list size
25
-
26
- import sqlite3
27
- import json
28
- import time
29
- import logging
30
- from datetime import datetime
31
- from pathlib import Path
32
- from typing import List, Dict, Optional, Tuple, Any
33
- import numpy as np
34
-
35
- # Core dependencies for fallback
36
- try:
37
- from sklearn.metrics.pairwise import cosine_similarity
38
- SKLEARN_AVAILABLE = True
39
- except ImportError:
40
- SKLEARN_AVAILABLE = False
41
-
42
- # Optional HNSW dependency
43
- HNSW_AVAILABLE = False
44
- try:
45
- import hnswlib
46
- HNSW_AVAILABLE = True
47
- except ImportError:
48
- HNSW_AVAILABLE = False
49
- # Graceful degradation - will use linear search fallback
50
-
51
- MEMORY_DIR = Path.home() / ".claude-memory"
52
- HNSW_INDEX_PATH = MEMORY_DIR / "hnsw_index.bin"
53
- HNSW_METADATA_PATH = MEMORY_DIR / "hnsw_metadata.json"
54
-
55
- logger = logging.getLogger(__name__)
56
-
57
-
58
- class HNSWIndex:
59
- """
60
- Fast approximate nearest neighbor search using HNSW algorithm.
61
-
62
- Features:
63
- - Sub-10ms search for 10K memories
64
- - Incremental updates (no full rebuild needed)
65
- - Disk persistence with automatic loading
66
- - Graceful fallback to linear search if hnswlib unavailable
67
-
68
- Performance:
69
- - 10K memories: <10ms search time
70
- - 100K memories: <50ms search time
71
- - Memory overhead: ~200 bytes per vector (configurable)
72
- """
73
-
74
- def __init__(
75
- self,
76
- dimension: int = 384,
77
- max_elements: int = MAX_MEMORIES_FOR_HNSW,
78
- m: int = DEFAULT_M,
79
- ef_construction: int = DEFAULT_EF_CONSTRUCTION,
80
- ef_search: int = DEFAULT_EF_SEARCH,
81
- index_path: Optional[Path] = None,
82
- metadata_path: Optional[Path] = None
83
- ):
84
- """
85
- Initialize HNSW index.
86
-
87
- Args:
88
- dimension: Vector dimension (e.g., 384 for all-MiniLM-L6-v2)
89
- max_elements: Maximum number of vectors to index
90
- m: HNSW M parameter (connections per layer, typical: 16)
91
- ef_construction: HNSW ef_construction (candidate list size, typical: 200)
92
- ef_search: HNSW ef_search (search candidate list size, typical: 50)
93
- index_path: Custom path for index file
94
- metadata_path: Custom path for metadata file
95
-
96
- Raises:
97
- ValueError: If parameters exceed security limits
98
- """
99
- # SECURITY: Input validation
100
- if dimension > MAX_DIMENSION:
101
- raise ValueError(f"Dimension {dimension} exceeds maximum {MAX_DIMENSION}")
102
-
103
- if max_elements > MAX_MEMORIES_FOR_HNSW:
104
- raise ValueError(f"Max elements {max_elements} exceeds limit {MAX_MEMORIES_FOR_HNSW}")
105
-
106
- self.dimension = dimension
107
- self.max_elements = max_elements
108
- self.m = m
109
- self.ef_construction = ef_construction
110
- self.ef_search = ef_search
111
-
112
- self.index_path = index_path or HNSW_INDEX_PATH
113
- self.metadata_path = metadata_path or HNSW_METADATA_PATH
114
-
115
- # Initialize index and metadata
116
- self.index = None
117
- self.memory_ids = [] # Maps index position to memory ID
118
- self.id_to_idx = {} # Maps memory ID to index position
119
- self.use_hnsw = HNSW_AVAILABLE
120
-
121
- # Fallback: store vectors for linear search
122
- self.vectors = None
123
-
124
- # Load existing index if available
125
- self._load()
126
-
127
- def _load(self):
128
- """Load existing index and metadata from disk."""
129
- if not self.use_hnsw:
130
- logger.info("HNSW unavailable - will use linear search fallback")
131
- return
132
-
133
- if not self.index_path.exists() or not self.metadata_path.exists():
134
- logger.info("No existing HNSW index found - will create new index")
135
- return
136
-
137
- try:
138
- # Load metadata
139
- with open(self.metadata_path, 'r') as f:
140
- metadata = json.load(f)
141
-
142
- # Validate metadata — auto-rebuild on dimension mismatch
143
- if metadata.get('dimension') != self.dimension:
144
- logger.info(
145
- "Index dimension changed: %s -> %s. "
146
- "Deleting old index files and rebuilding.",
147
- metadata.get('dimension'), self.dimension,
148
- )
149
- try:
150
- self.index_path.unlink(missing_ok=True)
151
- self.metadata_path.unlink(missing_ok=True)
152
- except OSError as del_err:
153
- logger.warning("Could not delete old index files: %s", del_err)
154
- return
155
-
156
- # Load HNSW index
157
- self.index = hnswlib.Index(space='cosine', dim=self.dimension)
158
- self.index.load_index(str(self.index_path))
159
- self.index.set_ef(self.ef_search)
160
-
161
- # Load memory ID mapping
162
- self.memory_ids = metadata.get('memory_ids', [])
163
- self.id_to_idx = {mem_id: idx for idx, mem_id in enumerate(self.memory_ids)}
164
-
165
- logger.info(f"Loaded HNSW index with {len(self.memory_ids)} vectors")
166
-
167
- except Exception as e:
168
- logger.error(f"Failed to load HNSW index: {e}. Will rebuild.")
169
- self.index = None
170
- self.memory_ids = []
171
- self.id_to_idx = {}
172
-
173
- def _save(self):
174
- """Save index and metadata to disk."""
175
- if not self.use_hnsw or self.index is None:
176
- return
177
-
178
- try:
179
- # Create directory if needed
180
- self.index_path.parent.mkdir(parents=True, exist_ok=True)
181
-
182
- # Save HNSW index
183
- self.index.save_index(str(self.index_path))
184
-
185
- # Save metadata
186
- metadata = {
187
- 'dimension': self.dimension,
188
- 'max_elements': self.max_elements,
189
- 'm': self.m,
190
- 'ef_construction': self.ef_construction,
191
- 'ef_search': self.ef_search,
192
- 'memory_ids': self.memory_ids,
193
- 'created_at': datetime.now().isoformat(),
194
- 'version': '2.2.0'
195
- }
196
-
197
- with open(self.metadata_path, 'w') as f:
198
- json.dump(metadata, f, indent=2)
199
-
200
- logger.info(f"Saved HNSW index with {len(self.memory_ids)} vectors")
201
-
202
- except Exception as e:
203
- logger.error(f"Failed to save HNSW index: {e}")
204
-
205
- def build(self, vectors: np.ndarray, memory_ids: List[int]) -> None:
206
- """
207
- Build HNSW index from vectors.
208
-
209
- Args:
210
- vectors: Array of shape (n_memories, dimension)
211
- memory_ids: List of memory IDs corresponding to vectors
212
-
213
- Raises:
214
- ValueError: If input validation fails
215
- """
216
- # SECURITY: Input validation
217
- if len(vectors) > self.max_elements:
218
- raise ValueError(
219
- f"Cannot index {len(vectors)} vectors (max: {self.max_elements}). "
220
- "Use incremental updates or increase max_elements."
221
- )
222
-
223
- if vectors.shape[1] != self.dimension:
224
- raise ValueError(
225
- f"Vector dimension {vectors.shape[1]} does not match index dimension {self.dimension}"
226
- )
227
-
228
- if len(vectors) != len(memory_ids):
229
- raise ValueError("Number of vectors must match number of memory IDs")
230
-
231
- # Convert to float32 for efficiency
232
- vectors = vectors.astype('float32')
233
-
234
- if self.use_hnsw:
235
- # Build HNSW index
236
- try:
237
- start_time = time.time()
238
-
239
- self.index = hnswlib.Index(space='cosine', dim=self.dimension)
240
- self.index.init_index(
241
- max_elements=self.max_elements,
242
- M=self.m,
243
- ef_construction=self.ef_construction,
244
- random_seed=42
245
- )
246
- self.index.set_ef(self.ef_search)
247
-
248
- # Add vectors in batch
249
- self.index.add_items(vectors, list(range(len(vectors))))
250
-
251
- self.memory_ids = list(memory_ids)
252
- self.id_to_idx = {mem_id: idx for idx, mem_id in enumerate(memory_ids)}
253
-
254
- # Save to disk
255
- self._save()
256
-
257
- elapsed = time.time() - start_time
258
- logger.info(f"Built HNSW index with {len(vectors)} vectors in {elapsed:.2f}s")
259
-
260
- except Exception as e:
261
- logger.error(f"HNSW build failed: {e}. Falling back to linear search.")
262
- self.use_hnsw = False
263
- self._build_fallback(vectors, memory_ids)
264
- else:
265
- # Fallback: store vectors for linear search
266
- self._build_fallback(vectors, memory_ids)
267
-
268
- def _build_fallback(self, vectors: np.ndarray, memory_ids: List[int]):
269
- """Build fallback index using linear search."""
270
- if not SKLEARN_AVAILABLE:
271
- logger.warning("sklearn unavailable - search functionality disabled")
272
- return
273
-
274
- self.vectors = vectors.astype('float32')
275
- self.memory_ids = list(memory_ids)
276
- self.id_to_idx = {mem_id: idx for idx, mem_id in enumerate(memory_ids)}
277
- logger.info(f"Built fallback index with {len(vectors)} vectors (linear search)")
278
-
279
- def add(self, vector: np.ndarray, memory_id: int) -> None:
280
- """
281
- Add single vector to index (incremental update).
282
-
283
- Args:
284
- vector: Vector of shape (dimension,)
285
- memory_id: Memory ID for this vector
286
-
287
- Raises:
288
- ValueError: If index is full or vector invalid
289
- """
290
- # SECURITY: Input validation
291
- if len(self.memory_ids) >= self.max_elements:
292
- raise ValueError(f"Index is full (max: {self.max_elements})")
293
-
294
- if len(vector) != self.dimension:
295
- raise ValueError(f"Vector dimension {len(vector)} does not match {self.dimension}")
296
-
297
- vector = vector.astype('float32').reshape(1, -1)
298
-
299
- if self.use_hnsw and self.index is not None:
300
- try:
301
- # Add to HNSW index
302
- idx = len(self.memory_ids)
303
- self.index.add_items(vector, [idx])
304
- self.memory_ids.append(memory_id)
305
- self.id_to_idx[memory_id] = idx
306
-
307
- # Save updated index
308
- self._save()
309
-
310
- except Exception as e:
311
- logger.error(f"Failed to add vector to HNSW: {e}")
312
- # Continue with best effort - don't crash
313
- else:
314
- # Fallback: append to vectors array
315
- if self.vectors is None:
316
- self.vectors = vector
317
- else:
318
- self.vectors = np.vstack([self.vectors, vector])
319
-
320
- idx = len(self.memory_ids)
321
- self.memory_ids.append(memory_id)
322
- self.id_to_idx[memory_id] = idx
323
-
324
- def search(
325
- self,
326
- query_vector: np.ndarray,
327
- k: int = 5,
328
- filter_ids: Optional[List[int]] = None
329
- ) -> List[Tuple[int, float]]:
330
- """
331
- Search for k nearest neighbors.
332
-
333
- Args:
334
- query_vector: Query vector of shape (dimension,)
335
- k: Number of results to return
336
- filter_ids: Optional list of memory IDs to restrict search
337
-
338
- Returns:
339
- List of (memory_id, distance) tuples, sorted by distance (lower = more similar)
340
-
341
- Performance:
342
- - HNSW: <10ms for 10K vectors, <50ms for 100K vectors
343
- - Fallback: O(n) linear search, ~100ms for 10K vectors
344
- """
345
- if len(self.memory_ids) == 0:
346
- return []
347
-
348
- # SECURITY: Input validation
349
- if len(query_vector) != self.dimension:
350
- raise ValueError(f"Query dimension {len(query_vector)} does not match {self.dimension}")
351
-
352
- query_vector = query_vector.astype('float32').reshape(1, -1)
353
- k = min(k, len(self.memory_ids)) # Don't request more than available
354
-
355
- if self.use_hnsw and self.index is not None:
356
- # HNSW search
357
- try:
358
- start_time = time.time()
359
-
360
- # Get more candidates if filtering is needed
361
- search_k = k * 3 if filter_ids else k
362
- search_k = min(search_k, len(self.memory_ids))
363
-
364
- labels, distances = self.index.knn_query(query_vector, k=search_k)
365
-
366
- # Convert to results
367
- results = []
368
- for idx, dist in zip(labels[0], distances[0]):
369
- mem_id = self.memory_ids[idx]
370
-
371
- # Apply filter if provided
372
- if filter_ids is None or mem_id in filter_ids:
373
- # Convert cosine distance to similarity score (1 - distance)
374
- similarity = 1.0 - dist
375
- results.append((mem_id, float(similarity)))
376
-
377
- if len(results) >= k:
378
- break
379
-
380
- elapsed = time.time() - start_time
381
- logger.debug(f"HNSW search took {elapsed*1000:.2f}ms for {len(self.memory_ids)} vectors")
382
-
383
- return results
384
-
385
- except Exception as e:
386
- logger.error(f"HNSW search failed: {e}. Falling back to linear search.")
387
- # Fall through to fallback
388
-
389
- # Fallback: linear search with sklearn
390
- if SKLEARN_AVAILABLE and self.vectors is not None:
391
- start_time = time.time()
392
-
393
- # Compute similarities
394
- similarities = cosine_similarity(query_vector, self.vectors)[0]
395
-
396
- # Get top k indices
397
- if filter_ids:
398
- # Filter first, then sort
399
- filtered_indices = [idx for idx, mem_id in enumerate(self.memory_ids) if mem_id in filter_ids]
400
- if not filtered_indices:
401
- return []
402
- filtered_similarities = similarities[filtered_indices]
403
- top_indices = np.argsort(filtered_similarities)[::-1][:k]
404
- results = [(self.memory_ids[filtered_indices[idx]], float(filtered_similarities[idx]))
405
- for idx in top_indices]
406
- else:
407
- # Direct sorting
408
- top_indices = np.argsort(similarities)[::-1][:k]
409
- results = [(self.memory_ids[idx], float(similarities[idx])) for idx in top_indices]
410
-
411
- elapsed = time.time() - start_time
412
- logger.debug(f"Linear search took {elapsed*1000:.2f}ms for {len(self.memory_ids)} vectors")
413
-
414
- return results
415
-
416
- logger.warning("No search method available (HNSW and sklearn both unavailable)")
417
- return []
418
-
419
- def update(self, memory_id: int, vector: np.ndarray) -> None:
420
- """
421
- Update vector for existing memory.
422
-
423
- Note: HNSW doesn't support in-place updates efficiently.
424
- This marks the item for rebuild or uses a workaround.
425
-
426
- Args:
427
- memory_id: Memory ID to update
428
- vector: New vector of shape (dimension,)
429
- """
430
- if memory_id not in self.id_to_idx:
431
- logger.warning(f"Memory ID {memory_id} not in index - adding as new")
432
- self.add(vector, memory_id)
433
- return
434
-
435
- # For HNSW, mark as dirty and suggest rebuild
436
- # HNSW doesn't support efficient updates - best practice is periodic rebuild
437
- logger.warning(
438
- f"Updated memory {memory_id} - HNSW index is now stale. "
439
- "Consider calling rebuild() periodically for optimal performance."
440
- )
441
-
442
- # Update fallback index if available
443
- if self.vectors is not None:
444
- idx = self.id_to_idx[memory_id]
445
- self.vectors[idx] = vector.astype('float32')
446
-
447
- def delete(self, memory_id: int):
448
- """
449
- Delete memory from index.
450
-
451
- Note: HNSW doesn't support efficient deletion.
452
- This marks the item for rebuild.
453
-
454
- Args:
455
- memory_id: Memory ID to delete
456
- """
457
- if memory_id not in self.id_to_idx:
458
- logger.warning(f"Memory ID {memory_id} not in index")
459
- return
460
-
461
- # For now, just remove from mapping (soft delete)
462
- # Physical removal requires full rebuild
463
- idx = self.id_to_idx[memory_id]
464
- del self.id_to_idx[memory_id]
465
-
466
- logger.info(
467
- f"Soft-deleted memory {memory_id} from index. "
468
- "Call rebuild() to physically remove."
469
- )
470
-
471
- def rebuild_from_db(self, db_path: Path, embedding_column: str = 'embedding'):
472
- """
473
- Rebuild index from database.
474
-
475
- Args:
476
- db_path: Path to SQLite database
477
- embedding_column: Name of column containing embeddings (JSON array)
478
- """
479
- conn = sqlite3.connect(db_path)
480
- cursor = conn.cursor()
481
-
482
- try:
483
- # Check if embedding column exists
484
- cursor.execute("PRAGMA table_info(memories)")
485
- columns = {row[1] for row in cursor.fetchall()}
486
-
487
- if embedding_column not in columns:
488
- logger.warning(f"Column '{embedding_column}' not found in database")
489
- conn.close()
490
- return
491
-
492
- # Load embeddings
493
- cursor.execute(f'SELECT id, {embedding_column} FROM memories WHERE {embedding_column} IS NOT NULL')
494
- rows = cursor.fetchall()
495
-
496
- if not rows:
497
- logger.info("No embeddings found in database")
498
- conn.close()
499
- return
500
-
501
- # Parse embeddings
502
- memory_ids = []
503
- vectors = []
504
-
505
- for mem_id, embedding_json in rows:
506
- try:
507
- embedding = json.loads(embedding_json)
508
- memory_ids.append(mem_id)
509
- vectors.append(embedding)
510
- except json.JSONDecodeError:
511
- logger.warning(f"Invalid embedding JSON for memory {mem_id}")
512
-
513
- if not vectors:
514
- logger.info("No valid embeddings to index")
515
- conn.close()
516
- return
517
-
518
- vectors = np.array(vectors, dtype='float32')
519
-
520
- # Build index
521
- self.build(vectors, memory_ids)
522
- logger.info(f"Rebuilt HNSW index from database with {len(memory_ids)} vectors")
523
-
524
- finally:
525
- conn.close()
526
-
527
- def get_stats(self) -> Dict[str, Any]:
528
- """
529
- Get index statistics.
530
-
531
- Returns:
532
- Dictionary with index stats
533
- """
534
- return {
535
- 'hnsw_available': HNSW_AVAILABLE,
536
- 'use_hnsw': self.use_hnsw,
537
- 'sklearn_available': SKLEARN_AVAILABLE,
538
- 'dimension': self.dimension,
539
- 'max_elements': self.max_elements,
540
- 'indexed_count': len(self.memory_ids),
541
- 'capacity_used_pct': (len(self.memory_ids) / self.max_elements * 100) if self.max_elements > 0 else 0,
542
- 'm': self.m,
543
- 'ef_construction': self.ef_construction,
544
- 'ef_search': self.ef_search,
545
- 'index_exists': self.index is not None,
546
- 'fallback_active': self.vectors is not None
547
- }
548
-
549
-
550
- # CLI interface for testing
551
- if __name__ == "__main__":
552
- import sys
553
-
554
- # Configure logging
555
- logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
556
-
557
- if len(sys.argv) < 2:
558
- print("HNSWIndex CLI - Fast Approximate Nearest Neighbor Search")
559
- print("\nCommands:")
560
- print(" python hnsw_index.py stats # Show index statistics")
561
- print(" python hnsw_index.py rebuild # Rebuild from database")
562
- print(" python hnsw_index.py test # Run performance test")
563
- sys.exit(0)
564
-
565
- command = sys.argv[1]
566
-
567
- if command == "stats":
568
- index = HNSWIndex()
569
- stats = index.get_stats()
570
- print(json.dumps(stats, indent=2))
571
-
572
- elif command == "rebuild":
573
- db_path = MEMORY_DIR / "memory.db"
574
- if not db_path.exists():
575
- print(f"Database not found at {db_path}")
576
- sys.exit(1)
577
-
578
- print("Rebuilding HNSW index from database...")
579
- index = HNSWIndex()
580
- index.rebuild_from_db(db_path)
581
- print("Rebuild complete!")
582
- print(json.dumps(index.get_stats(), indent=2))
583
-
584
- elif command == "test":
585
- print("Running HNSW performance test...")
586
-
587
- # Generate random test data
588
- n_vectors = 10000
589
- dimension = 384
590
-
591
- print(f"Generating {n_vectors} random {dimension}-dim vectors...")
592
- vectors = np.random.randn(n_vectors, dimension).astype('float32')
593
- memory_ids = list(range(n_vectors))
594
-
595
- # Build index
596
- print("Building index...")
597
- index = HNSWIndex(dimension=dimension)
598
- start = time.time()
599
- index.build(vectors, memory_ids)
600
- build_time = time.time() - start
601
- print(f"Build time: {build_time:.2f}s ({n_vectors/build_time:.0f} vectors/sec)")
602
-
603
- # Test search performance
604
- print("\nTesting search performance...")
605
- query = np.random.randn(dimension).astype('float32')
606
-
607
- # Warm-up
608
- for _ in range(10):
609
- index.search(query, k=5)
610
-
611
- # Benchmark
612
- n_queries = 100
613
- start = time.time()
614
- for _ in range(n_queries):
615
- results = index.search(query, k=5)
616
- search_time = (time.time() - start) / n_queries
617
-
618
- print(f"Average search time: {search_time*1000:.2f}ms")
619
- print(f"Queries per second: {1/search_time:.0f}")
620
- print(f"\nSample results: {results[:3]}")
621
-
622
- # Print stats
623
- print("\nIndex statistics:")
624
- print(json.dumps(index.get_stats(), indent=2))
625
-
626
- else:
627
- print(f"Unknown command: {command}")
628
- print("Run without arguments to see available commands.")
@@ -1,46 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """SuperLocalMemory V2 - Hybrid Search System
5
-
6
- Solution Architect & Original Creator
7
-
8
- (see LICENSE file)
9
-
10
- ATTRIBUTION REQUIRED: This notice must be preserved in all copies.
11
- """
12
- """
13
- BACKWARD-COMPATIBILITY SHIM
14
- ----------------------------
15
- This file re-exports every public symbol from the ``search`` package so that
16
- existing code using ``from hybrid_search import HybridSearchEngine`` continues
17
- to work without modification.
18
-
19
- The actual implementation now lives in:
20
- src/search/constants.py - Shared imports and constants
21
- src/search/index_loader.py - Index building and graph lazy-loading
22
- src/search/methods.py - BM25, semantic, and graph search methods
23
- src/search/fusion.py - Score normalization and fusion strategies
24
- src/search/engine.py - HybridSearchEngine orchestrator
25
- src/search/cli.py - CLI demo interface
26
- """
27
-
28
- # Re-export everything from the search package
29
- from search import (
30
- HybridSearchEngine,
31
- FusionMixin,
32
- SearchMethodsMixin,
33
- IndexLoaderMixin,
34
- main,
35
- )
36
-
37
- __all__ = [
38
- "HybridSearchEngine",
39
- "FusionMixin",
40
- "SearchMethodsMixin",
41
- "IndexLoaderMixin",
42
- "main",
43
- ]
44
-
45
- if __name__ == '__main__':
46
- main()