superlocalmemory 2.8.5 → 3.0.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.
Files changed (434) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +9 -1
  3. package/NOTICE +63 -0
  4. package/README.md +165 -480
  5. package/bin/slm +17 -449
  6. package/bin/slm-npm +2 -2
  7. package/bin/slm.bat +4 -2
  8. package/conftest.py +5 -0
  9. package/docs/api-reference.md +284 -0
  10. package/docs/architecture.md +149 -0
  11. package/docs/auto-memory.md +150 -0
  12. package/docs/cli-reference.md +276 -0
  13. package/docs/compliance.md +191 -0
  14. package/docs/configuration.md +182 -0
  15. package/docs/getting-started.md +102 -0
  16. package/docs/ide-setup.md +261 -0
  17. package/docs/mcp-tools.md +220 -0
  18. package/docs/migration-from-v2.md +170 -0
  19. package/docs/profiles.md +173 -0
  20. package/docs/troubleshooting.md +310 -0
  21. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  22. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  23. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  24. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  25. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  26. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  27. package/ide/configs/cursor-mcp.json +15 -0
  28. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  29. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  30. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  31. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  32. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  33. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  34. package/{configs → ide/configs}/zed-mcp.json +2 -2
  35. package/{hooks → ide/hooks}/context-hook.js +9 -20
  36. package/ide/hooks/memory-list-skill.js +70 -0
  37. package/ide/hooks/memory-profile-skill.js +101 -0
  38. package/ide/hooks/memory-recall-skill.js +62 -0
  39. package/ide/hooks/memory-remember-skill.js +68 -0
  40. package/ide/hooks/memory-reset-skill.js +160 -0
  41. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  42. package/ide/integrations/langchain/README.md +106 -0
  43. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  44. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  45. package/ide/integrations/langchain/pyproject.toml +38 -0
  46. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  47. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  48. package/ide/integrations/langchain/tests/test_security.py +117 -0
  49. package/ide/integrations/llamaindex/README.md +81 -0
  50. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  51. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  52. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  53. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  54. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  55. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  56. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  57. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  58. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  59. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  60. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  61. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  62. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  63. package/package.json +13 -22
  64. package/pyproject.toml +85 -0
  65. package/scripts/build-dmg.sh +417 -0
  66. package/scripts/install-skills.ps1 +334 -0
  67. package/{install.ps1 → scripts/install.ps1} +36 -4
  68. package/{install.sh → scripts/install.sh} +14 -13
  69. package/scripts/postinstall.js +2 -2
  70. package/scripts/start-dashboard.ps1 +52 -0
  71. package/scripts/start-dashboard.sh +41 -0
  72. package/scripts/sync-wiki.ps1 +127 -0
  73. package/scripts/sync-wiki.sh +82 -0
  74. package/scripts/test-dmg.sh +161 -0
  75. package/scripts/test-npm-package.ps1 +252 -0
  76. package/scripts/test-npm-package.sh +207 -0
  77. package/scripts/verify-install.ps1 +294 -0
  78. package/scripts/verify-install.sh +266 -0
  79. package/src/superlocalmemory/__init__.py +0 -0
  80. package/src/superlocalmemory/attribution/__init__.py +9 -0
  81. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  82. package/src/superlocalmemory/attribution/signer.py +153 -0
  83. package/src/superlocalmemory/attribution/watermark.py +189 -0
  84. package/src/superlocalmemory/cli/__init__.py +5 -0
  85. package/src/superlocalmemory/cli/commands.py +245 -0
  86. package/src/superlocalmemory/cli/main.py +89 -0
  87. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  88. package/src/superlocalmemory/cli/post_install.py +99 -0
  89. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  90. package/src/superlocalmemory/compliance/__init__.py +0 -0
  91. package/src/superlocalmemory/compliance/abac.py +204 -0
  92. package/src/superlocalmemory/compliance/audit.py +314 -0
  93. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  94. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  95. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  96. package/src/superlocalmemory/compliance/retention.py +232 -0
  97. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  98. package/src/superlocalmemory/core/__init__.py +0 -0
  99. package/src/superlocalmemory/core/config.py +391 -0
  100. package/src/superlocalmemory/core/embeddings.py +293 -0
  101. package/src/superlocalmemory/core/engine.py +701 -0
  102. package/src/superlocalmemory/core/hooks.py +65 -0
  103. package/src/superlocalmemory/core/maintenance.py +172 -0
  104. package/src/superlocalmemory/core/modes.py +140 -0
  105. package/src/superlocalmemory/core/profiles.py +234 -0
  106. package/src/superlocalmemory/core/registry.py +117 -0
  107. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  108. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  109. package/src/superlocalmemory/encoding/__init__.py +0 -0
  110. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  111. package/src/superlocalmemory/encoding/emotional.py +125 -0
  112. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  113. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  114. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  115. package/src/superlocalmemory/encoding/foresight.py +91 -0
  116. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  117. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  118. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  119. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  120. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  121. package/src/superlocalmemory/encoding/type_router.py +235 -0
  122. package/src/superlocalmemory/hooks/__init__.py +3 -0
  123. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  124. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  125. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  126. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  127. package/src/superlocalmemory/infra/__init__.py +3 -0
  128. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  129. package/src/superlocalmemory/infra/backup.py +317 -0
  130. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  131. package/src/superlocalmemory/infra/event_bus.py +381 -0
  132. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  133. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  134. package/src/superlocalmemory/learning/__init__.py +0 -0
  135. package/src/superlocalmemory/learning/adaptive.py +172 -0
  136. package/src/superlocalmemory/learning/behavioral.py +490 -0
  137. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  138. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  139. package/src/superlocalmemory/learning/cross_project.py +399 -0
  140. package/src/superlocalmemory/learning/database.py +376 -0
  141. package/src/superlocalmemory/learning/engagement.py +323 -0
  142. package/src/superlocalmemory/learning/features.py +138 -0
  143. package/src/superlocalmemory/learning/feedback.py +316 -0
  144. package/src/superlocalmemory/learning/outcomes.py +255 -0
  145. package/src/superlocalmemory/learning/project_context.py +366 -0
  146. package/src/superlocalmemory/learning/ranker.py +155 -0
  147. package/src/superlocalmemory/learning/source_quality.py +303 -0
  148. package/src/superlocalmemory/learning/workflows.py +309 -0
  149. package/src/superlocalmemory/llm/__init__.py +0 -0
  150. package/src/superlocalmemory/llm/backbone.py +316 -0
  151. package/src/superlocalmemory/math/__init__.py +0 -0
  152. package/src/superlocalmemory/math/fisher.py +356 -0
  153. package/src/superlocalmemory/math/langevin.py +398 -0
  154. package/src/superlocalmemory/math/sheaf.py +257 -0
  155. package/src/superlocalmemory/mcp/__init__.py +0 -0
  156. package/src/superlocalmemory/mcp/resources.py +245 -0
  157. package/src/superlocalmemory/mcp/server.py +61 -0
  158. package/src/superlocalmemory/mcp/tools.py +18 -0
  159. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  160. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  161. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  162. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  163. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  164. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  165. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  166. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  167. package/src/superlocalmemory/retrieval/engine.py +390 -0
  168. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  169. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  170. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  171. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  172. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  173. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  174. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  175. package/src/superlocalmemory/server/__init__.py +1 -0
  176. package/src/superlocalmemory/server/api.py +248 -0
  177. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  178. package/src/superlocalmemory/server/routes/agents.py +107 -0
  179. package/src/superlocalmemory/server/routes/backup.py +91 -0
  180. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  181. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  182. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  183. package/src/superlocalmemory/server/routes/events.py +183 -0
  184. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  185. package/src/superlocalmemory/server/routes/learning.py +273 -0
  186. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  187. package/src/superlocalmemory/server/routes/memories.py +399 -0
  188. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  189. package/src/superlocalmemory/server/routes/stats.py +346 -0
  190. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  191. package/src/superlocalmemory/server/routes/ws.py +82 -0
  192. package/src/superlocalmemory/server/security_middleware.py +57 -0
  193. package/src/superlocalmemory/server/ui.py +245 -0
  194. package/src/superlocalmemory/storage/__init__.py +0 -0
  195. package/src/superlocalmemory/storage/access_control.py +182 -0
  196. package/src/superlocalmemory/storage/database.py +594 -0
  197. package/src/superlocalmemory/storage/migrations.py +303 -0
  198. package/src/superlocalmemory/storage/models.py +406 -0
  199. package/src/superlocalmemory/storage/schema.py +726 -0
  200. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  201. package/src/superlocalmemory/trust/__init__.py +0 -0
  202. package/src/superlocalmemory/trust/gate.py +130 -0
  203. package/src/superlocalmemory/trust/provenance.py +124 -0
  204. package/src/superlocalmemory/trust/scorer.py +347 -0
  205. package/src/superlocalmemory/trust/signals.py +153 -0
  206. package/ui/index.html +278 -5
  207. package/ui/js/auto-settings.js +70 -0
  208. package/ui/js/dashboard.js +90 -0
  209. package/ui/js/fact-detail.js +92 -0
  210. package/ui/js/feedback.js +2 -2
  211. package/ui/js/ide-status.js +102 -0
  212. package/ui/js/math-health.js +98 -0
  213. package/ui/js/recall-lab.js +127 -0
  214. package/ui/js/settings.js +2 -2
  215. package/ui/js/trust-dashboard.js +73 -0
  216. package/api_server.py +0 -724
  217. package/bin/aider-smart +0 -72
  218. package/bin/superlocalmemoryv2-learning +0 -4
  219. package/bin/superlocalmemoryv2-list +0 -3
  220. package/bin/superlocalmemoryv2-patterns +0 -4
  221. package/bin/superlocalmemoryv2-profile +0 -3
  222. package/bin/superlocalmemoryv2-recall +0 -3
  223. package/bin/superlocalmemoryv2-remember +0 -3
  224. package/bin/superlocalmemoryv2-reset +0 -3
  225. package/bin/superlocalmemoryv2-status +0 -3
  226. package/configs/chatgpt-desktop-mcp.json +0 -16
  227. package/configs/cursor-mcp.json +0 -15
  228. package/docs/SECURITY-QUICK-REFERENCE.md +0 -214
  229. package/hooks/memory-list-skill.js +0 -139
  230. package/hooks/memory-profile-skill.js +0 -273
  231. package/hooks/memory-recall-skill.js +0 -114
  232. package/hooks/memory-remember-skill.js +0 -127
  233. package/hooks/memory-reset-skill.js +0 -274
  234. package/mcp_server.py +0 -1800
  235. package/requirements-core.txt +0 -22
  236. package/requirements-learning.txt +0 -12
  237. package/requirements.txt +0 -12
  238. package/src/agent_registry.py +0 -411
  239. package/src/auth_middleware.py +0 -61
  240. package/src/auto_backup.py +0 -459
  241. package/src/behavioral/__init__.py +0 -49
  242. package/src/behavioral/behavioral_listener.py +0 -203
  243. package/src/behavioral/behavioral_patterns.py +0 -275
  244. package/src/behavioral/cross_project_transfer.py +0 -206
  245. package/src/behavioral/outcome_inference.py +0 -194
  246. package/src/behavioral/outcome_tracker.py +0 -193
  247. package/src/behavioral/tests/__init__.py +0 -4
  248. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  249. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  250. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  251. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  252. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  253. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  254. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  255. package/src/cache_manager.py +0 -518
  256. package/src/compliance/__init__.py +0 -48
  257. package/src/compliance/abac_engine.py +0 -149
  258. package/src/compliance/abac_middleware.py +0 -116
  259. package/src/compliance/audit_db.py +0 -215
  260. package/src/compliance/audit_logger.py +0 -148
  261. package/src/compliance/retention_manager.py +0 -289
  262. package/src/compliance/retention_scheduler.py +0 -186
  263. package/src/compliance/tests/__init__.py +0 -4
  264. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  265. package/src/compliance/tests/test_abac_engine.py +0 -124
  266. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  267. package/src/compliance/tests/test_audit_db.py +0 -123
  268. package/src/compliance/tests/test_audit_logger.py +0 -98
  269. package/src/compliance/tests/test_mcp_audit.py +0 -128
  270. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  271. package/src/compliance/tests/test_retention_manager.py +0 -131
  272. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  273. package/src/compression/__init__.py +0 -25
  274. package/src/compression/cli.py +0 -150
  275. package/src/compression/cold_storage.py +0 -217
  276. package/src/compression/config.py +0 -72
  277. package/src/compression/orchestrator.py +0 -133
  278. package/src/compression/tier2_compressor.py +0 -228
  279. package/src/compression/tier3_compressor.py +0 -153
  280. package/src/compression/tier_classifier.py +0 -148
  281. package/src/db_connection_manager.py +0 -536
  282. package/src/embedding_engine.py +0 -63
  283. package/src/embeddings/__init__.py +0 -47
  284. package/src/embeddings/cache.py +0 -70
  285. package/src/embeddings/cli.py +0 -113
  286. package/src/embeddings/constants.py +0 -47
  287. package/src/embeddings/database.py +0 -91
  288. package/src/embeddings/engine.py +0 -247
  289. package/src/embeddings/model_loader.py +0 -145
  290. package/src/event_bus.py +0 -562
  291. package/src/graph/__init__.py +0 -36
  292. package/src/graph/build_helpers.py +0 -74
  293. package/src/graph/cli.py +0 -87
  294. package/src/graph/cluster_builder.py +0 -188
  295. package/src/graph/cluster_summary.py +0 -148
  296. package/src/graph/constants.py +0 -47
  297. package/src/graph/edge_builder.py +0 -162
  298. package/src/graph/entity_extractor.py +0 -95
  299. package/src/graph/graph_core.py +0 -226
  300. package/src/graph/graph_search.py +0 -231
  301. package/src/graph/hierarchical.py +0 -207
  302. package/src/graph/schema.py +0 -99
  303. package/src/graph_engine.py +0 -52
  304. package/src/hnsw_index.py +0 -628
  305. package/src/hybrid_search.py +0 -46
  306. package/src/learning/__init__.py +0 -217
  307. package/src/learning/adaptive_ranker.py +0 -682
  308. package/src/learning/bootstrap/__init__.py +0 -69
  309. package/src/learning/bootstrap/constants.py +0 -93
  310. package/src/learning/bootstrap/db_queries.py +0 -316
  311. package/src/learning/bootstrap/sampling.py +0 -82
  312. package/src/learning/bootstrap/text_utils.py +0 -71
  313. package/src/learning/cross_project_aggregator.py +0 -857
  314. package/src/learning/db/__init__.py +0 -40
  315. package/src/learning/db/constants.py +0 -44
  316. package/src/learning/db/schema.py +0 -279
  317. package/src/learning/engagement_tracker.py +0 -628
  318. package/src/learning/feature_extractor.py +0 -708
  319. package/src/learning/feedback_collector.py +0 -806
  320. package/src/learning/learning_db.py +0 -915
  321. package/src/learning/project_context_manager.py +0 -572
  322. package/src/learning/ranking/__init__.py +0 -33
  323. package/src/learning/ranking/constants.py +0 -84
  324. package/src/learning/ranking/helpers.py +0 -278
  325. package/src/learning/source_quality_scorer.py +0 -676
  326. package/src/learning/synthetic_bootstrap.py +0 -755
  327. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  328. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  329. package/src/learning/tests/test_aggregator.py +0 -306
  330. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  331. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  332. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  333. package/src/learning/tests/test_feedback_collector.py +0 -294
  334. package/src/learning/tests/test_learning_db.py +0 -602
  335. package/src/learning/tests/test_learning_db_v28.py +0 -110
  336. package/src/learning/tests/test_learning_init_v28.py +0 -48
  337. package/src/learning/tests/test_outcome_signals.py +0 -48
  338. package/src/learning/tests/test_project_context.py +0 -292
  339. package/src/learning/tests/test_schema_migration.py +0 -319
  340. package/src/learning/tests/test_signal_inference.py +0 -397
  341. package/src/learning/tests/test_source_quality.py +0 -351
  342. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  343. package/src/learning/tests/test_workflow_miner.py +0 -318
  344. package/src/learning/workflow_pattern_miner.py +0 -655
  345. package/src/lifecycle/__init__.py +0 -54
  346. package/src/lifecycle/bounded_growth.py +0 -239
  347. package/src/lifecycle/compaction_engine.py +0 -226
  348. package/src/lifecycle/lifecycle_engine.py +0 -355
  349. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  350. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  351. package/src/lifecycle/retention_policy.py +0 -285
  352. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  353. package/src/lifecycle/tests/test_compaction.py +0 -179
  354. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  355. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  356. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  357. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  358. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  359. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  360. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  361. package/src/mcp_tools_v28.py +0 -281
  362. package/src/memory/__init__.py +0 -36
  363. package/src/memory/cli.py +0 -205
  364. package/src/memory/constants.py +0 -39
  365. package/src/memory/helpers.py +0 -28
  366. package/src/memory/schema.py +0 -166
  367. package/src/memory-profiles.py +0 -595
  368. package/src/memory-reset.py +0 -491
  369. package/src/memory_compression.py +0 -989
  370. package/src/memory_store_v2.py +0 -1155
  371. package/src/migrate_v1_to_v2.py +0 -629
  372. package/src/pattern_learner.py +0 -34
  373. package/src/patterns/__init__.py +0 -24
  374. package/src/patterns/analyzers.py +0 -251
  375. package/src/patterns/learner.py +0 -271
  376. package/src/patterns/scoring.py +0 -171
  377. package/src/patterns/store.py +0 -225
  378. package/src/patterns/terminology.py +0 -140
  379. package/src/provenance_tracker.py +0 -312
  380. package/src/qualixar_attribution.py +0 -139
  381. package/src/qualixar_watermark.py +0 -78
  382. package/src/query_optimizer.py +0 -511
  383. package/src/rate_limiter.py +0 -83
  384. package/src/search/__init__.py +0 -20
  385. package/src/search/cli.py +0 -77
  386. package/src/search/constants.py +0 -26
  387. package/src/search/engine.py +0 -241
  388. package/src/search/fusion.py +0 -122
  389. package/src/search/index_loader.py +0 -114
  390. package/src/search/methods.py +0 -162
  391. package/src/search_engine_v2.py +0 -401
  392. package/src/setup_validator.py +0 -482
  393. package/src/subscription_manager.py +0 -391
  394. package/src/tree/__init__.py +0 -59
  395. package/src/tree/builder.py +0 -185
  396. package/src/tree/nodes.py +0 -202
  397. package/src/tree/queries.py +0 -257
  398. package/src/tree/schema.py +0 -80
  399. package/src/tree_manager.py +0 -19
  400. package/src/trust/__init__.py +0 -45
  401. package/src/trust/constants.py +0 -66
  402. package/src/trust/queries.py +0 -157
  403. package/src/trust/schema.py +0 -95
  404. package/src/trust/scorer.py +0 -299
  405. package/src/trust/signals.py +0 -95
  406. package/src/trust_scorer.py +0 -44
  407. package/ui/app.js +0 -1588
  408. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  409. package/ui/js/graph-cytoscape.js +0 -1168
  410. package/ui/js/graph-d3-backup.js +0 -32
  411. package/ui/js/graph.js +0 -32
  412. package/ui_server.py +0 -266
  413. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  414. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  415. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  416. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  417. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  418. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  419. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  420. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  421. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  422. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  423. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  424. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  425. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  426. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  427. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  428. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  429. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  430. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  431. /package/{completions → ide/completions}/slm.bash +0 -0
  432. /package/{completions → ide/completions}/slm.zsh +0 -0
  433. /package/{configs → ide/configs}/cody-commands.json +0 -0
  434. /package/{install-skills.sh → scripts/install-skills.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()