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
@@ -1,397 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """SuperLocalMemory V2 - Signal Inference Engine Tests (v2.7.4)
5
-
6
- Tests for the implicit feedback signal inference system.
7
- """
8
- import time
9
- import threading
10
- import pytest
11
- import sys
12
- from pathlib import Path
13
-
14
- # Ensure mcp_server module is importable for RecallBuffer
15
- sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
16
-
17
-
18
- class TestRecallBuffer:
19
- """Test the _RecallBuffer class from mcp_server."""
20
-
21
- def _make_buffer(self):
22
- """Create a fresh RecallBuffer for testing."""
23
- # Import directly to avoid starting MCP server
24
- from importlib import import_module
25
- import types
26
-
27
- # Create a minimal RecallBuffer instance by duplicating the class logic
28
- # without importing the full mcp_server (which requires MCP deps)
29
- sys.path.insert(0, str(Path(__file__).parent.parent.parent))
30
-
31
- class RecallBuffer:
32
- def __init__(self):
33
- self._lock = threading.Lock()
34
- self._last_recall = {}
35
- self._global_last = None
36
- self._signal_timestamps = {}
37
- self._recent_result_ids = set()
38
- self._recall_count = 0
39
- self._positive_threshold = 300.0
40
- self._inter_recall_times = []
41
-
42
- def record_recall(self, query, result_ids, agent_id="mcp-client"):
43
- now = time.time()
44
- signals = []
45
- with self._lock:
46
- self._recall_count += 1
47
- result_id_set = set(result_ids)
48
- self._recent_result_ids = result_id_set
49
- current = {
50
- "query": query, "result_ids": result_ids,
51
- "result_id_set": result_id_set, "timestamp": now,
52
- "agent_id": agent_id,
53
- }
54
- prev = self._last_recall.get(agent_id)
55
- if prev:
56
- time_gap = now - prev["timestamp"]
57
- self._inter_recall_times.append(time_gap)
58
- if len(self._inter_recall_times) > 100:
59
- self._inter_recall_times = self._inter_recall_times[-100:]
60
- if len(self._inter_recall_times) >= 10:
61
- sorted_times = sorted(self._inter_recall_times)
62
- median = sorted_times[len(sorted_times) // 2]
63
- self._positive_threshold = max(60.0, min(median * 0.8, 1800.0))
64
- if time_gap < 30.0 and query != prev["query"]:
65
- for mid in prev["result_ids"][:5]:
66
- signals.append({
67
- "memory_id": mid,
68
- "signal_type": "implicit_negative_requick",
69
- "query": prev["query"],
70
- "rank_position": prev["result_ids"].index(mid) + 1,
71
- })
72
- elif time_gap > self._positive_threshold:
73
- for mid in prev["result_ids"][:3]:
74
- signals.append({
75
- "memory_id": mid,
76
- "signal_type": "implicit_positive_timegap",
77
- "query": prev["query"],
78
- "rank_position": prev["result_ids"].index(mid) + 1,
79
- })
80
- overlap = result_id_set & prev["result_id_set"]
81
- for mid in overlap:
82
- signals.append({
83
- "memory_id": mid,
84
- "signal_type": "implicit_positive_reaccess",
85
- "query": query,
86
- })
87
- global_prev = self._global_last
88
- if global_prev and global_prev["agent_id"] != agent_id:
89
- cross_overlap = result_id_set & global_prev["result_id_set"]
90
- for mid in cross_overlap:
91
- signals.append({
92
- "memory_id": mid,
93
- "signal_type": "implicit_positive_cross_tool",
94
- "query": query,
95
- })
96
- self._last_recall[agent_id] = current
97
- self._global_last = current
98
- return signals
99
-
100
- def check_post_action(self, memory_id, action):
101
- with self._lock:
102
- if memory_id not in self._recent_result_ids:
103
- return None
104
- if action == "update":
105
- return {"memory_id": memory_id, "signal_type": "implicit_positive_post_update",
106
- "query": self._global_last["query"] if self._global_last else ""}
107
- elif action == "delete":
108
- return {"memory_id": memory_id, "signal_type": "implicit_negative_post_delete",
109
- "query": self._global_last["query"] if self._global_last else ""}
110
- return None
111
-
112
- def check_rate_limit(self, agent_id, max_per_minute=5):
113
- now = time.time()
114
- with self._lock:
115
- if agent_id not in self._signal_timestamps:
116
- self._signal_timestamps[agent_id] = []
117
- self._signal_timestamps[agent_id] = [
118
- ts for ts in self._signal_timestamps[agent_id] if now - ts < 60.0
119
- ]
120
- if len(self._signal_timestamps[agent_id]) >= max_per_minute:
121
- return False
122
- self._signal_timestamps[agent_id].append(now)
123
- return True
124
-
125
- def get_recall_count(self):
126
- with self._lock:
127
- return self._recall_count
128
-
129
- def get_stats(self):
130
- with self._lock:
131
- return {
132
- "recall_count": self._recall_count,
133
- "tracked_agents": len(self._last_recall),
134
- "positive_threshold_s": round(self._positive_threshold, 1),
135
- "recent_results_count": len(self._recent_result_ids),
136
- }
137
-
138
- return RecallBuffer()
139
-
140
- def test_first_recall_no_signals(self):
141
- """First recall should produce no signals (nothing to compare with)."""
142
- buf = self._make_buffer()
143
- signals = buf.record_recall("test query", [1, 2, 3])
144
- assert signals == []
145
- assert buf.get_recall_count() == 1
146
-
147
- def test_quick_requery_negative_signals(self):
148
- """Quick re-query with different query should produce negative signals."""
149
- buf = self._make_buffer()
150
- buf.record_recall("first query", [10, 20, 30])
151
- # Simulate quick re-query (no sleep needed — time gap is ~0)
152
- signals = buf.record_recall("different query", [40, 50])
153
- negative_signals = [s for s in signals if s["signal_type"] == "implicit_negative_requick"]
154
- assert len(negative_signals) > 0
155
- # Should target previous results (10, 20, 30)
156
- neg_ids = {s["memory_id"] for s in negative_signals}
157
- assert neg_ids.issubset({10, 20, 30})
158
-
159
- def test_same_query_no_negative(self):
160
- """Same exact query repeated quickly should NOT produce negative signals."""
161
- buf = self._make_buffer()
162
- buf.record_recall("same query", [10, 20])
163
- signals = buf.record_recall("same query", [10, 20])
164
- negative_signals = [s for s in signals if s["signal_type"] == "implicit_negative_requick"]
165
- assert len(negative_signals) == 0
166
-
167
- def test_reaccess_positive_signals(self):
168
- """Same memory appearing in consecutive recalls = positive."""
169
- buf = self._make_buffer()
170
- buf.record_recall("query a", [10, 20, 30])
171
- signals = buf.record_recall("query b", [20, 40, 50])
172
- reaccess = [s for s in signals if s["signal_type"] == "implicit_positive_reaccess"]
173
- assert len(reaccess) == 1
174
- assert reaccess[0]["memory_id"] == 20
175
-
176
- def test_cross_tool_positive_signals(self):
177
- """Same memory recalled by different agents = cross-tool positive."""
178
- buf = self._make_buffer()
179
- buf.record_recall("query", [10, 20], agent_id="claude")
180
- signals = buf.record_recall("query", [20, 30], agent_id="cursor")
181
- cross_tool = [s for s in signals if s["signal_type"] == "implicit_positive_cross_tool"]
182
- assert len(cross_tool) == 1
183
- assert cross_tool[0]["memory_id"] == 20
184
-
185
- def test_post_action_update_tracked(self):
186
- """Update after recall should generate positive signal."""
187
- buf = self._make_buffer()
188
- buf.record_recall("query", [10, 20, 30])
189
- signal = buf.check_post_action(20, "update")
190
- assert signal is not None
191
- assert signal["signal_type"] == "implicit_positive_post_update"
192
- assert signal["memory_id"] == 20
193
-
194
- def test_post_action_delete_tracked(self):
195
- """Delete after recall should generate negative signal."""
196
- buf = self._make_buffer()
197
- buf.record_recall("query", [10, 20, 30])
198
- signal = buf.check_post_action(10, "delete")
199
- assert signal is not None
200
- assert signal["signal_type"] == "implicit_negative_post_delete"
201
-
202
- def test_post_action_unrelated_memory_ignored(self):
203
- """Action on memory NOT in recent results should be ignored."""
204
- buf = self._make_buffer()
205
- buf.record_recall("query", [10, 20, 30])
206
- signal = buf.check_post_action(999, "update")
207
- assert signal is None
208
-
209
- def test_rate_limiting(self):
210
- """Rate limiter should cap signals per agent per minute."""
211
- buf = self._make_buffer()
212
- agent = "test-agent"
213
- # First 5 should be allowed
214
- for i in range(5):
215
- assert buf.check_rate_limit(agent) is True
216
- # 6th should be blocked
217
- assert buf.check_rate_limit(agent) is False
218
-
219
- def test_rate_limiting_different_agents(self):
220
- """Different agents should have independent rate limits."""
221
- buf = self._make_buffer()
222
- for i in range(5):
223
- assert buf.check_rate_limit("agent1") is True
224
- assert buf.check_rate_limit("agent1") is False
225
- # Agent2 should still be allowed
226
- assert buf.check_rate_limit("agent2") is True
227
-
228
- def test_recall_count_increments(self):
229
- """Recall count should increment with each recall."""
230
- buf = self._make_buffer()
231
- assert buf.get_recall_count() == 0
232
- buf.record_recall("q1", [1])
233
- assert buf.get_recall_count() == 1
234
- buf.record_recall("q2", [2])
235
- assert buf.get_recall_count() == 2
236
-
237
- def test_negative_signals_cap_at_5(self):
238
- """Negative signals should only target top 5 results."""
239
- buf = self._make_buffer()
240
- buf.record_recall("first", list(range(1, 11))) # 10 results
241
- signals = buf.record_recall("different", [99])
242
- negative = [s for s in signals if s["signal_type"] == "implicit_negative_requick"]
243
- assert len(negative) <= 5
244
-
245
- def test_stats_output(self):
246
- """Stats should report correct values."""
247
- buf = self._make_buffer()
248
- buf.record_recall("q", [1, 2, 3])
249
- stats = buf.get_stats()
250
- assert stats["recall_count"] == 1
251
- assert stats["tracked_agents"] == 1
252
- assert stats["recent_results_count"] == 3
253
- assert stats["positive_threshold_s"] == 300.0
254
-
255
- def test_thread_safety(self):
256
- """Buffer should handle concurrent access without errors."""
257
- buf = self._make_buffer()
258
- errors = []
259
-
260
- def worker(agent_id):
261
- try:
262
- for i in range(20):
263
- buf.record_recall(f"query_{i}", [i, i+1], agent_id=agent_id)
264
- buf.check_rate_limit(agent_id)
265
- except Exception as e:
266
- errors.append(e)
267
-
268
- threads = [threading.Thread(target=worker, args=(f"agent_{i}",)) for i in range(5)]
269
- for t in threads:
270
- t.start()
271
- for t in threads:
272
- t.join(timeout=10)
273
-
274
- assert errors == [], f"Thread safety errors: {errors}"
275
- assert buf.get_recall_count() == 100 # 5 agents x 20 recalls
276
-
277
-
278
- class TestFeedbackCollectorImplicit:
279
- """Test the new implicit signal methods in FeedbackCollector."""
280
-
281
- def test_record_implicit_signal_valid(self):
282
- """Valid implicit signal should be stored."""
283
- sys.path.insert(0, str(Path(__file__).parent.parent))
284
- from feedback_collector import FeedbackCollector
285
- fc = FeedbackCollector()
286
- result = fc.record_implicit_signal(
287
- memory_id=42,
288
- query="test query",
289
- signal_type="implicit_positive_timegap",
290
- )
291
- # Should return row ID or None (depends on DB availability)
292
- # Just verify it doesn't crash
293
- assert result is None or isinstance(result, int)
294
-
295
- def test_record_implicit_signal_invalid_type(self):
296
- """Invalid signal type should return None."""
297
- sys.path.insert(0, str(Path(__file__).parent.parent))
298
- from feedback_collector import FeedbackCollector
299
- fc = FeedbackCollector()
300
- result = fc.record_implicit_signal(
301
- memory_id=42,
302
- query="test",
303
- signal_type="totally_fake_type",
304
- )
305
- assert result is None
306
-
307
- def test_record_dashboard_feedback_valid(self):
308
- """Valid dashboard feedback should be stored."""
309
- sys.path.insert(0, str(Path(__file__).parent.parent))
310
- from feedback_collector import FeedbackCollector
311
- fc = FeedbackCollector()
312
- result = fc.record_dashboard_feedback(
313
- memory_id=42,
314
- query="test query",
315
- feedback_type="thumbs_up",
316
- )
317
- assert result is None or isinstance(result, int)
318
-
319
- def test_record_dashboard_feedback_invalid_type(self):
320
- """Invalid feedback type should return None."""
321
- sys.path.insert(0, str(Path(__file__).parent.parent))
322
- from feedback_collector import FeedbackCollector
323
- fc = FeedbackCollector()
324
- result = fc.record_dashboard_feedback(
325
- memory_id=42,
326
- query="test",
327
- feedback_type="invalid_type",
328
- )
329
- assert result is None
330
-
331
- def test_signal_values_complete(self):
332
- """All declared signal types should have numeric values."""
333
- sys.path.insert(0, str(Path(__file__).parent.parent))
334
- from feedback_collector import FeedbackCollector
335
- fc = FeedbackCollector()
336
- for signal_type, value in fc.SIGNAL_VALUES.items():
337
- assert isinstance(value, (int, float)), f"{signal_type} has non-numeric value"
338
- assert 0.0 <= value <= 1.0, f"{signal_type} value {value} out of range"
339
-
340
-
341
- class TestFeatureExpansion:
342
- """Test the 10→12→20 feature vector expansion."""
343
-
344
- def test_feature_count_is_20(self):
345
- """Feature vector should have 20 dimensions (v2.8)."""
346
- sys.path.insert(0, str(Path(__file__).parent.parent))
347
- from feature_extractor import FEATURE_NAMES, NUM_FEATURES
348
- assert NUM_FEATURES == 20
349
- assert len(FEATURE_NAMES) == 20
350
-
351
- def test_new_features_present(self):
352
- """signal_count and avg_signal_value should be in feature names."""
353
- sys.path.insert(0, str(Path(__file__).parent.parent))
354
- from feature_extractor import FEATURE_NAMES
355
- assert 'signal_count' in FEATURE_NAMES
356
- assert 'avg_signal_value' in FEATURE_NAMES
357
- assert FEATURE_NAMES.index('signal_count') == 10
358
- assert FEATURE_NAMES.index('avg_signal_value') == 11
359
-
360
- def test_extract_features_returns_20(self):
361
- """Extract should return 20-element vector (v2.8)."""
362
- sys.path.insert(0, str(Path(__file__).parent.parent))
363
- from feature_extractor import FeatureExtractor
364
- fe = FeatureExtractor()
365
- features = fe.extract_features(
366
- {'id': 1, 'content': 'test', 'importance': 5},
367
- 'test'
368
- )
369
- assert len(features) == 20
370
-
371
- def test_signal_features_with_stats(self):
372
- """Signal features should use provided stats."""
373
- sys.path.insert(0, str(Path(__file__).parent.parent))
374
- from feature_extractor import FeatureExtractor
375
- fe = FeatureExtractor()
376
- fe.set_context(signal_stats={
377
- '42': {'count': 8, 'avg_value': 0.9},
378
- })
379
- features = fe.extract_features(
380
- {'id': 42, 'content': 'test', 'importance': 5},
381
- 'test'
382
- )
383
- assert features[10] == 0.8 # count=8, 8/10=0.8
384
- assert features[11] == 0.9 # avg_value=0.9
385
-
386
- def test_signal_features_without_stats(self):
387
- """Signal features should default safely without stats."""
388
- sys.path.insert(0, str(Path(__file__).parent.parent))
389
- from feature_extractor import FeatureExtractor
390
- fe = FeatureExtractor()
391
- # No set_context call — signal_stats empty
392
- features = fe.extract_features(
393
- {'id': 99, 'content': 'test', 'importance': 5},
394
- 'test'
395
- )
396
- assert features[10] == 0.0 # No stats → 0.0
397
- assert features[11] == 0.5 # No stats → neutral 0.5