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
@@ -1,511 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """SuperLocalMemory V2 - Query Optimizer
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
- Query Optimizer - Query Enhancement and Rewriting
14
-
15
- Transforms user queries into optimized search queries through:
16
-
17
- 1. Spell Correction: Fix common typos using edit distance
18
- - "javscript" → "javascript"
19
- - Uses vocabulary from indexed documents
20
- - Levenshtein distance with max distance 2
21
-
22
- 2. Query Expansion: Add related terms to broaden search
23
- - "auth" → "auth authentication authorize"
24
- - Based on co-occurrence patterns in documents
25
- - Optional synonym expansion
26
-
27
- 3. Boolean Operators: Parse structured queries
28
- - "python AND (web OR api)" → structured query
29
- - Supports: AND, OR, NOT, phrase queries "exact match"
30
- - Converts to search engine-compatible format
31
-
32
- 4. Stopword Handling: Remove low-value terms
33
- - Configurable stopword list
34
- - Preserves important technical terms
35
-
36
- Performance: Query optimization should add <5ms overhead
37
-
38
- Usage:
39
- optimizer = QueryOptimizer(vocabulary)
40
- optimized = optimizer.optimize("javscript web devlopment")
41
- # Returns: "javascript web development"
42
- """
43
-
44
- import re
45
- from collections import defaultdict, Counter
46
- from typing import List, Dict, Set, Tuple, Optional, Any
47
- import difflib
48
-
49
-
50
- class QueryOptimizer:
51
- """
52
- Query preprocessing and optimization for improved search quality.
53
-
54
- Handles spell correction, expansion, and boolean query parsing.
55
- """
56
-
57
- def __init__(self, vocabulary: Optional[Set[str]] = None):
58
- """
59
- Initialize query optimizer.
60
-
61
- Args:
62
- vocabulary: Set of known terms from indexed documents
63
- Used for spell correction
64
- """
65
- self.vocabulary = vocabulary or set()
66
-
67
- # Co-occurrence matrix for query expansion
68
- # term -> {related_term: co-occurrence_count}
69
- self.cooccurrence: Dict[str, Dict[str, int]] = defaultdict(lambda: defaultdict(int))
70
-
71
- # Expansion candidates: term -> [expanded_terms]
72
- self.expansions: Dict[str, List[str]] = {}
73
-
74
- # Technical term preservation (don't treat as typos)
75
- self.technical_terms = {
76
- 'api', 'sql', 'orm', 'jwt', 'http', 'https', 'ssl', 'tls',
77
- 'json', 'xml', 'yaml', 'csv', 'pdf', 'cli', 'gui', 'ide',
78
- 'git', 'npm', 'pip', 'cpu', 'gpu', 'ram', 'ssd', 'hdd',
79
- 'ml', 'ai', 'nlp', 'cv', 'dl', 'rl', 'gan', 'cnn', 'rnn',
80
- 'rest', 'soap', 'grpc', 'cors', 'csrf', 'xss', 'sql',
81
- 'aws', 'gcp', 'azure', 'k8s', 'ci', 'cd', 'devops'
82
- }
83
-
84
- def build_cooccurrence_matrix(self, documents: List[List[str]]) -> None:
85
- """
86
- Build term co-occurrence matrix from tokenized documents.
87
-
88
- Co-occurrence = terms appearing in same document
89
- Used for query expansion to find related terms.
90
-
91
- Args:
92
- documents: List of tokenized documents (each doc is list of tokens)
93
- """
94
- self.cooccurrence = defaultdict(lambda: defaultdict(int))
95
-
96
- for doc_tokens in documents:
97
- # Count unique terms per document
98
- unique_terms = set(doc_tokens)
99
-
100
- # Update co-occurrence for all term pairs in document
101
- for term1 in unique_terms:
102
- for term2 in unique_terms:
103
- if term1 != term2:
104
- self.cooccurrence[term1][term2] += 1
105
-
106
- def _edit_distance(self, s1: str, s2: str, max_distance: int = 2) -> int:
107
- """
108
- Calculate Levenshtein edit distance between two strings.
109
-
110
- Edit distance = minimum number of single-character edits (insertions,
111
- deletions, substitutions) required to change s1 into s2.
112
-
113
- Early termination if distance exceeds max_distance for performance.
114
-
115
- Args:
116
- s1: First string
117
- s2: Second string
118
- max_distance: Maximum distance to calculate (for early termination)
119
-
120
- Returns:
121
- Edit distance, or max_distance+1 if exceeds threshold
122
- """
123
- len1, len2 = len(s1), len(s2)
124
-
125
- # Early termination - length difference too large
126
- if abs(len1 - len2) > max_distance:
127
- return max_distance + 1
128
-
129
- # Initialize DP matrix (only need current and previous row)
130
- prev_row = list(range(len2 + 1))
131
- curr_row = [0] * (len2 + 1)
132
-
133
- for i in range(1, len1 + 1):
134
- curr_row[0] = i
135
- min_in_row = i # Track minimum value in current row
136
-
137
- for j in range(1, len2 + 1):
138
- # Cost of substitution (0 if characters match, 1 otherwise)
139
- cost = 0 if s1[i - 1] == s2[j - 1] else 1
140
-
141
- curr_row[j] = min(
142
- prev_row[j] + 1, # Deletion
143
- curr_row[j - 1] + 1, # Insertion
144
- prev_row[j - 1] + cost # Substitution
145
- )
146
-
147
- min_in_row = min(min_in_row, curr_row[j])
148
-
149
- # Early termination - minimum in row exceeds threshold
150
- if min_in_row > max_distance:
151
- return max_distance + 1
152
-
153
- # Swap rows
154
- prev_row, curr_row = curr_row, prev_row
155
-
156
- return prev_row[len2]
157
-
158
- def spell_correct(self, term: str, max_distance: int = 2) -> str:
159
- """
160
- Correct spelling using vocabulary and edit distance.
161
-
162
- Algorithm:
163
- 1. If term in vocabulary, return as-is
164
- 2. If term is technical term (<=3 chars or in whitelist), return as-is
165
- 3. Find closest vocabulary term within max_distance edits
166
- 4. Return correction if found, otherwise original term
167
-
168
- Args:
169
- term: Term to correct
170
- max_distance: Maximum edit distance to consider (default: 2)
171
-
172
- Returns:
173
- Corrected term or original if no correction found
174
- """
175
- # Already correct or technical term
176
- if term in self.vocabulary or term in self.technical_terms:
177
- return term
178
-
179
- # Don't correct very short terms (likely abbreviations)
180
- if len(term) <= 3:
181
- return term
182
-
183
- # Find closest match in vocabulary
184
- best_match = term
185
- best_distance = max_distance + 1
186
-
187
- # Use difflib for efficient approximate matching
188
- # This is faster than checking full vocabulary for large sets
189
- close_matches = difflib.get_close_matches(
190
- term, self.vocabulary, n=5, cutoff=0.7
191
- )
192
-
193
- for candidate in close_matches:
194
- distance = self._edit_distance(term, candidate, max_distance)
195
- if distance < best_distance:
196
- best_distance = distance
197
- best_match = candidate
198
-
199
- # If no close match found by difflib, check high-frequency terms
200
- # This handles cases where difflib's cutoff is too strict
201
- if best_distance > max_distance and len(self.vocabulary) < 10000:
202
- # Only do full scan for smaller vocabularies
203
- for vocab_term in self.vocabulary:
204
- # Quick filter by length difference
205
- if abs(len(term) - len(vocab_term)) > max_distance:
206
- continue
207
-
208
- distance = self._edit_distance(term, vocab_term, max_distance)
209
- if distance < best_distance:
210
- best_distance = distance
211
- best_match = vocab_term
212
-
213
- # Return correction only if found
214
- return best_match if best_distance <= max_distance else term
215
-
216
- def expand_query(
217
- self,
218
- query_terms: List[str],
219
- max_expansions: int = 2,
220
- min_cooccurrence: int = 2
221
- ) -> List[str]:
222
- """
223
- Expand query with related terms based on co-occurrence.
224
-
225
- Adds terms that frequently co-occur with query terms to broaden search.
226
-
227
- Args:
228
- query_terms: Original query terms
229
- max_expansions: Maximum number of expansion terms to add
230
- min_cooccurrence: Minimum co-occurrence count threshold
231
-
232
- Returns:
233
- Expanded query terms (original + expansions)
234
- """
235
- if not self.cooccurrence:
236
- return query_terms
237
-
238
- # Collect expansion candidates
239
- expansion_candidates = defaultdict(int)
240
-
241
- for term in query_terms:
242
- if term in self.cooccurrence:
243
- for related_term, count in self.cooccurrence[term].items():
244
- # Don't re-add terms already in query
245
- if related_term not in query_terms:
246
- expansion_candidates[related_term] += count
247
-
248
- # Filter by minimum co-occurrence and sort by frequency
249
- expansions = [
250
- term for term, count in expansion_candidates.items()
251
- if count >= min_cooccurrence
252
- ]
253
- expansions.sort(key=lambda t: expansion_candidates[t], reverse=True)
254
-
255
- # Add top expansions
256
- expanded_terms = query_terms + expansions[:max_expansions]
257
-
258
- return expanded_terms
259
-
260
- def parse_boolean_query(self, query: str) -> Dict[str, Any]:
261
- """
262
- Parse boolean query operators (AND, OR, NOT, phrase matching).
263
-
264
- Supports:
265
- - AND: term1 AND term2 (both required)
266
- - OR: term1 OR term2 (at least one required)
267
- - NOT: term1 NOT term2 (exclude term2)
268
- - Phrase: "exact phrase" (exact match)
269
- - Implicit AND: "term1 term2" treated as term1 AND term2
270
-
271
- Args:
272
- query: Query string with boolean operators
273
-
274
- Returns:
275
- Parsed query structure:
276
- {
277
- 'type': 'and' | 'or' | 'not' | 'phrase' | 'term',
278
- 'terms': [terms],
279
- 'operator': operator,
280
- 'children': [sub-queries]
281
- }
282
- """
283
- # Extract phrase queries first (enclosed in quotes)
284
- phrases = []
285
- phrase_pattern = r'"([^"]+)"'
286
- query_without_phrases = query
287
-
288
- for match in re.finditer(phrase_pattern, query):
289
- phrase = match.group(1)
290
- phrases.append(phrase)
291
- # Replace phrase with placeholder
292
- query_without_phrases = query_without_phrases.replace(
293
- f'"{phrase}"', f'__PHRASE_{len(phrases)-1}__'
294
- )
295
-
296
- # Split by boolean operators (case insensitive)
297
- # Priority: NOT > AND > OR
298
- query_upper = query_without_phrases.upper()
299
-
300
- # Parse NOT expressions
301
- if ' NOT ' in query_upper:
302
- parts = re.split(r'\s+NOT\s+', query_without_phrases, flags=re.IGNORECASE)
303
- return {
304
- 'type': 'not',
305
- 'required': self._parse_query_part(parts[0].strip(), phrases),
306
- 'excluded': [self._parse_query_part(p.strip(), phrases) for p in parts[1:]]
307
- }
308
-
309
- # Parse AND expressions
310
- if ' AND ' in query_upper:
311
- parts = re.split(r'\s+AND\s+', query_without_phrases, flags=re.IGNORECASE)
312
- return {
313
- 'type': 'and',
314
- 'children': [self._parse_query_part(p.strip(), phrases) for p in parts]
315
- }
316
-
317
- # Parse OR expressions
318
- if ' OR ' in query_upper:
319
- parts = re.split(r'\s+OR\s+', query_without_phrases, flags=re.IGNORECASE)
320
- return {
321
- 'type': 'or',
322
- 'children': [self._parse_query_part(p.strip(), phrases) for p in parts]
323
- }
324
-
325
- # Default: treat as implicit AND
326
- return self._parse_query_part(query_without_phrases.strip(), phrases)
327
-
328
- def _parse_query_part(self, part: str, phrases: List[str]) -> Dict[str, Any]:
329
- """
330
- Parse a single query part (no boolean operators).
331
-
332
- Args:
333
- part: Query part
334
- phrases: List of extracted phrases
335
-
336
- Returns:
337
- Query structure
338
- """
339
- # Check for phrase placeholder
340
- phrase_match = re.match(r'__PHRASE_(\d+)__', part)
341
- if phrase_match:
342
- phrase_idx = int(phrase_match.group(1))
343
- return {
344
- 'type': 'phrase',
345
- 'phrase': phrases[phrase_idx],
346
- 'terms': phrases[phrase_idx].split()
347
- }
348
-
349
- # Regular term(s)
350
- terms = part.split()
351
- if len(terms) == 1:
352
- return {
353
- 'type': 'term',
354
- 'term': terms[0]
355
- }
356
- else:
357
- # Multiple terms without operator = implicit AND
358
- return {
359
- 'type': 'and',
360
- 'children': [{'type': 'term', 'term': t} for t in terms]
361
- }
362
-
363
- def optimize(
364
- self,
365
- query: str,
366
- enable_spell_correction: bool = True,
367
- enable_expansion: bool = False,
368
- max_expansions: int = 2
369
- ) -> str:
370
- """
371
- Optimize query with spell correction and expansion.
372
-
373
- Args:
374
- query: Original query string
375
- enable_spell_correction: Apply spell correction
376
- enable_expansion: Apply query expansion
377
- max_expansions: Maximum expansion terms
378
-
379
- Returns:
380
- Optimized query string
381
- """
382
- # Tokenize query
383
- tokens = re.findall(r'\b[a-z0-9_-]+\b', query.lower())
384
-
385
- if not tokens:
386
- return query
387
-
388
- # Apply spell correction
389
- if enable_spell_correction and self.vocabulary:
390
- tokens = [self.spell_correct(term) for term in tokens]
391
-
392
- # Apply query expansion
393
- if enable_expansion and self.cooccurrence:
394
- tokens = self.expand_query(tokens, max_expansions)
395
-
396
- return ' '.join(tokens)
397
-
398
- def get_stats(self) -> Dict[str, Any]:
399
- """
400
- Get optimizer statistics.
401
-
402
- Returns:
403
- Dictionary with optimizer stats
404
- """
405
- return {
406
- 'vocabulary_size': len(self.vocabulary),
407
- 'cooccurrence_terms': len(self.cooccurrence),
408
- 'technical_terms': len(self.technical_terms),
409
- 'avg_related_terms': (
410
- sum(len(related) for related in self.cooccurrence.values()) / len(self.cooccurrence)
411
- if self.cooccurrence else 0
412
- )
413
- }
414
-
415
-
416
- # CLI interface for testing
417
- if __name__ == "__main__":
418
- print("Query Optimizer - Demo")
419
- print("=" * 60)
420
-
421
- # Sample vocabulary
422
- vocabulary = {
423
- 'python', 'javascript', 'programming', 'web', 'development',
424
- 'machine', 'learning', 'neural', 'network', 'api', 'rest',
425
- 'database', 'sql', 'authentication', 'authorization', 'jwt',
426
- 'framework', 'django', 'react', 'node', 'express'
427
- }
428
-
429
- # Sample documents for co-occurrence
430
- documents = [
431
- ['python', 'programming', 'web', 'development'],
432
- ['javascript', 'web', 'development', 'frontend'],
433
- ['machine', 'learning', 'python', 'neural', 'network'],
434
- ['api', 'rest', 'web', 'development'],
435
- ['authentication', 'authorization', 'jwt', 'security'],
436
- ]
437
-
438
- # Initialize optimizer
439
- optimizer = QueryOptimizer(vocabulary)
440
- optimizer.build_cooccurrence_matrix(documents)
441
-
442
- print("\nOptimizer Statistics:")
443
- stats = optimizer.get_stats()
444
- for key, value in stats.items():
445
- print(f" {key}: {value}")
446
-
447
- # Test spell correction
448
- print("\n" + "=" * 60)
449
- print("Spell Correction:")
450
- print("=" * 60)
451
-
452
- test_typos = [
453
- "pythno", # → python
454
- "javascirpt", # → javascript
455
- "machien", # → machine
456
- "athentication", # → authentication
457
- "developement" # → development
458
- ]
459
-
460
- for typo in test_typos:
461
- corrected = optimizer.spell_correct(typo)
462
- print(f" '{typo}' → '{corrected}'")
463
-
464
- # Test query expansion
465
- print("\n" + "=" * 60)
466
- print("Query Expansion:")
467
- print("=" * 60)
468
-
469
- test_queries = [
470
- ['python'],
471
- ['web'],
472
- ['machine', 'learning'],
473
- ]
474
-
475
- for query in test_queries:
476
- expanded = optimizer.expand_query(query, max_expansions=2)
477
- print(f" {query} → {expanded}")
478
-
479
- # Test boolean query parsing
480
- print("\n" + "=" * 60)
481
- print("Boolean Query Parsing:")
482
- print("=" * 60)
483
-
484
- boolean_queries = [
485
- 'python AND web',
486
- 'javascript OR typescript',
487
- 'python NOT django',
488
- '"machine learning" AND python',
489
- 'web development rest api'
490
- ]
491
-
492
- for query in boolean_queries:
493
- parsed = optimizer.parse_boolean_query(query)
494
- print(f"\n Query: '{query}'")
495
- print(f" Parsed: {parsed}")
496
-
497
- # Test full optimization
498
- print("\n" + "=" * 60)
499
- print("Full Query Optimization:")
500
- print("=" * 60)
501
-
502
- optimization_tests = [
503
- "pythno web devlopment",
504
- "machien lerning",
505
- "api athentication"
506
- ]
507
-
508
- for query in optimization_tests:
509
- optimized = optimizer.optimize(query, enable_spell_correction=True)
510
- print(f" '{query}'")
511
- print(f" → '{optimized}'")
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- Lightweight rate limiter using sliding window algorithm.
6
- Pure stdlib — no external dependencies.
7
-
8
- Defaults:
9
- Write endpoints: 100 req/min per IP
10
- Read endpoints: 300 req/min per IP
11
-
12
- Configurable via environment variables:
13
- SLM_RATE_LIMIT_WRITE=100
14
- SLM_RATE_LIMIT_READ=300
15
- SLM_RATE_LIMIT_WINDOW=60
16
- """
17
-
18
- import os
19
- import time
20
- import threading
21
- from collections import defaultdict
22
- from typing import Tuple
23
-
24
- import logging
25
- logger = logging.getLogger("superlocalmemory.ratelimit")
26
-
27
- # Configurable via env vars
28
- WRITE_LIMIT = int(os.environ.get('SLM_RATE_LIMIT_WRITE', '100'))
29
- READ_LIMIT = int(os.environ.get('SLM_RATE_LIMIT_READ', '300'))
30
- WINDOW_SECONDS = int(os.environ.get('SLM_RATE_LIMIT_WINDOW', '60'))
31
-
32
-
33
- class RateLimiter:
34
- """Thread-safe sliding window rate limiter."""
35
-
36
- def __init__(self, max_requests: int = 100, window_seconds: int = 60):
37
- self.max_requests = max_requests
38
- self.window = window_seconds
39
- self._requests: dict = defaultdict(list)
40
- self._lock = threading.Lock()
41
-
42
- def is_allowed(self, client_id: str) -> Tuple[bool, int]:
43
- """
44
- Check if request is allowed for this client.
45
-
46
- Returns:
47
- (allowed: bool, remaining: int) — whether request is allowed
48
- and how many requests remain in the window
49
- """
50
- now = time.time()
51
- cutoff = now - self.window
52
-
53
- with self._lock:
54
- # Remove expired entries
55
- self._requests[client_id] = [
56
- t for t in self._requests[client_id] if t > cutoff
57
- ]
58
-
59
- current = len(self._requests[client_id])
60
-
61
- if current >= self.max_requests:
62
- return False, 0
63
-
64
- self._requests[client_id].append(now)
65
- return True, self.max_requests - current - 1
66
-
67
- def cleanup(self):
68
- """Remove stale entries for clients that haven't made requests recently."""
69
- now = time.time()
70
- cutoff = now - self.window * 2 # Keep 2 windows of data
71
-
72
- with self._lock:
73
- stale_keys = [
74
- k for k, v in self._requests.items()
75
- if not v or max(v) < cutoff
76
- ]
77
- for k in stale_keys:
78
- del self._requests[k]
79
-
80
-
81
- # Singleton instances for write and read endpoints
82
- write_limiter = RateLimiter(max_requests=WRITE_LIMIT, window_seconds=WINDOW_SECONDS)
83
- read_limiter = RateLimiter(max_requests=READ_LIMIT, window_seconds=WINDOW_SECONDS)
@@ -1,20 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """search package - Hybrid Search System for SuperLocalMemory V2
4
-
5
- Re-exports all public classes so that
6
- ``from search import HybridSearchEngine`` works.
7
- """
8
- from search.engine import HybridSearchEngine
9
- from search.fusion import FusionMixin
10
- from search.methods import SearchMethodsMixin
11
- from search.index_loader import IndexLoaderMixin
12
- from search.cli import main
13
-
14
- __all__ = [
15
- "HybridSearchEngine",
16
- "FusionMixin",
17
- "SearchMethodsMixin",
18
- "IndexLoaderMixin",
19
- "main",
20
- ]
package/src/search/cli.py DELETED
@@ -1,77 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """CLI interface for testing the hybrid search engine.
5
- """
6
- import sys
7
- from pathlib import Path
8
-
9
- from search.engine import HybridSearchEngine
10
-
11
-
12
- def main():
13
- """Run the hybrid search CLI demo."""
14
- print("Hybrid Search Engine - Demo")
15
- print("=" * 60)
16
-
17
- # Use test database or default
18
- db_path = Path.home() / ".claude-memory" / "memory.db"
19
-
20
- if not db_path.exists():
21
- print(f"Error: Database not found at {db_path}")
22
- print("Please run memory_store_v2.py to create database first.")
23
- sys.exit(1)
24
-
25
- # Initialize hybrid search
26
- print(f"\nInitializing hybrid search engine...")
27
- print(f"Database: {db_path}")
28
-
29
- hybrid = HybridSearchEngine(db_path, enable_cache=True)
30
-
31
- stats = hybrid.get_stats()
32
- print(f"\nIndexed {stats['bm25']['num_documents']} memories")
33
- print(f" Vocabulary: {stats['bm25']['vocabulary_size']} terms")
34
- print(f" TF-IDF: {'Available' if stats['tfidf_available'] else 'Not available'}")
35
- print(f" Graph: {'Available' if stats['graph_available'] else 'Not available'}")
36
-
37
- # Test search
38
- if len(sys.argv) > 1:
39
- query = ' '.join(sys.argv[1:])
40
- else:
41
- query = "python web development"
42
-
43
- print("\n" + "=" * 60)
44
- print(f"Search Query: '{query}'")
45
- print("=" * 60)
46
-
47
- # Test different methods
48
- methods = ["bm25", "hybrid"]
49
-
50
- for method in methods:
51
- print(f"\nMethod: {method.upper()}")
52
- results = hybrid.search(query, limit=5, method=method)
53
-
54
- print(f" Found {len(results)} results in {hybrid.last_search_time*1000:.2f}ms")
55
-
56
- for i, mem in enumerate(results, 1):
57
- print(f"\n [{i}] Score: {mem['score']:.3f} | ID: {mem['id']}")
58
- if mem.get('category'):
59
- print(f" Category: {mem['category']}")
60
- if mem.get('tags'):
61
- print(f" Tags: {', '.join(mem['tags'][:3])}")
62
- print(f" Content: {mem['content'][:100]}...")
63
-
64
- # Display final stats
65
- print("\n" + "=" * 60)
66
- print("Performance Summary:")
67
- print("=" * 60)
68
-
69
- final_stats = hybrid.get_stats()
70
- print(f" Last search time: {final_stats['last_search_time_ms']:.2f}ms")
71
- print(f" Last fusion time: {final_stats['last_fusion_time_ms']:.2f}ms")
72
- print(f" Target: <50ms for 1K memories")
73
-
74
- if 'cache' in final_stats:
75
- cache_stats = final_stats['cache']
76
- print(f"\n Cache hit rate: {cache_stats['hit_rate']*100:.1f}%")
77
- print(f" Cache size: {cache_stats['current_size']}/{cache_stats['max_size']}")