superlocalmemory 2.8.6 → 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 (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 +1 -1
  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
@@ -0,0 +1,490 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """SuperLocalMemory V3 — Behavioral Pattern Store.
6
+
7
+ Stores, retrieves, and transfers behavioral patterns per profile.
8
+ Ported from V2's _store_patterns.py + cross_project_transfer.py
9
+ into a single unified module with direct sqlite3 access.
10
+
11
+ Key features:
12
+ - Record detected patterns (refinement, interest, archival, etc.)
13
+ - Query patterns by profile and type
14
+ - Summarize pattern counts by type
15
+ - Transfer patterns across profiles (cross-project learning)
16
+ - Confidence scoring: min(evidence/10, 1.0) * abs(rate - 0.5) * 2
17
+
18
+ Part of Qualixar | Author: Varun Pratap Bhardwaj
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import logging
25
+ import sqlite3
26
+ import threading
27
+ from datetime import datetime, timezone
28
+ from pathlib import Path
29
+ from typing import Any, Dict, List, Optional
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+ # Minimum observations before emitting a pattern
34
+ MIN_EVIDENCE = 3
35
+
36
+ # Transfer eligibility thresholds
37
+ TRANSFER_MIN_CONFIDENCE = 0.3
38
+ TRANSFER_MIN_EVIDENCE = 2
39
+
40
+ _CREATE_TABLE = """
41
+ CREATE TABLE IF NOT EXISTS _store_patterns (
42
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
43
+ profile_id TEXT NOT NULL,
44
+ pattern_type TEXT NOT NULL,
45
+ pattern_key TEXT DEFAULT '',
46
+ success_rate REAL DEFAULT 0.0,
47
+ evidence_count INTEGER DEFAULT 1,
48
+ confidence REAL DEFAULT 0.0,
49
+ metadata TEXT DEFAULT '{}',
50
+ created_at TEXT NOT NULL,
51
+ updated_at TEXT NOT NULL
52
+ )
53
+ """
54
+
55
+ _CREATE_INDEX = """
56
+ CREATE INDEX IF NOT EXISTS idx_sp_profile_type
57
+ ON _store_patterns(profile_id, pattern_type)
58
+ """
59
+
60
+
61
+ class BehavioralPatternStore:
62
+ """Store and query behavioral patterns per profile.
63
+
64
+ Uses direct sqlite3 for storage. Thread-safe via a lock.
65
+ Creates the _store_patterns table on first use.
66
+
67
+ Ported from V2's BehavioralPatternExtractor + CrossProjectTransfer,
68
+ unified into a single class with profile-scoped operations.
69
+ """
70
+
71
+ def __init__(self, db_path: str | Path) -> None:
72
+ self._db_path = str(db_path)
73
+ self._lock = threading.Lock()
74
+ self._ensure_table()
75
+
76
+ # ------------------------------------------------------------------
77
+ # Public API
78
+ # ------------------------------------------------------------------
79
+
80
+ def record_pattern(
81
+ self,
82
+ profile_id: str,
83
+ pattern_type: str,
84
+ data: Optional[Dict[str, Any]] = None,
85
+ success_rate: float = 0.0,
86
+ confidence: float = 0.0,
87
+ ) -> int:
88
+ """Store a detected behavioral pattern.
89
+
90
+ Args:
91
+ profile_id: Profile scope for the pattern.
92
+ pattern_type: Category (e.g. "refinement", "interest", "archival").
93
+ data: Arbitrary metadata dict (stored as JSON).
94
+ success_rate: Success rate if applicable (0.0-1.0).
95
+ confidence: Confidence score (0.0-1.0).
96
+
97
+ Returns:
98
+ The row ID of the inserted pattern.
99
+ """
100
+ now = datetime.now(timezone.utc).isoformat()
101
+ metadata_json = json.dumps(data or {})
102
+ pattern_key = (data or {}).get("topic", (data or {}).get("pattern_key", ""))
103
+
104
+ with self._lock:
105
+ conn = self._connect()
106
+ try:
107
+ # Check for existing pattern of same type+key for this profile
108
+ existing = conn.execute(
109
+ "SELECT id, evidence_count FROM _store_patterns "
110
+ "WHERE profile_id = ? AND pattern_type = ? AND pattern_key = ?",
111
+ (profile_id, pattern_type, pattern_key),
112
+ ).fetchone()
113
+
114
+ if existing:
115
+ new_count = existing[1] + 1
116
+ new_confidence = self._compute_confidence(
117
+ new_count, success_rate
118
+ ) if success_rate > 0 else min(1.0, new_count / 100.0)
119
+ conn.execute(
120
+ "UPDATE _store_patterns "
121
+ "SET evidence_count = ?, confidence = ?, "
122
+ " success_rate = ?, metadata = ?, updated_at = ? "
123
+ "WHERE id = ?",
124
+ (new_count, new_confidence, success_rate,
125
+ metadata_json, now, existing[0]),
126
+ )
127
+ conn.commit()
128
+ return existing[0]
129
+
130
+ initial_confidence = confidence or 0.01
131
+ cur = conn.execute(
132
+ "INSERT INTO _store_patterns "
133
+ "(profile_id, pattern_type, pattern_key, success_rate, "
134
+ " evidence_count, confidence, metadata, created_at, updated_at) "
135
+ "VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?)",
136
+ (profile_id, pattern_type, pattern_key, success_rate,
137
+ initial_confidence, metadata_json, now, now),
138
+ )
139
+ conn.commit()
140
+ return cur.lastrowid
141
+ finally:
142
+ conn.close()
143
+
144
+ def get_patterns(
145
+ self,
146
+ profile_id: str,
147
+ pattern_type: Optional[str] = None,
148
+ limit: int = 50,
149
+ min_confidence: float = 0.0,
150
+ ) -> List[Dict[str, Any]]:
151
+ """Get stored patterns for a profile.
152
+
153
+ Args:
154
+ profile_id: Profile to query.
155
+ pattern_type: If given, filter by type.
156
+ limit: Max rows to return.
157
+ min_confidence: Minimum confidence threshold.
158
+
159
+ Returns:
160
+ List of pattern dicts with deserialized metadata.
161
+ """
162
+ with self._lock:
163
+ conn = self._connect()
164
+ try:
165
+ query = (
166
+ "SELECT * FROM _store_patterns "
167
+ "WHERE profile_id = ? AND confidence >= ?"
168
+ )
169
+ params: List[Any] = [profile_id, min_confidence]
170
+
171
+ if pattern_type is not None:
172
+ query += " AND pattern_type = ?"
173
+ params.append(pattern_type)
174
+
175
+ query += " ORDER BY confidence DESC, updated_at DESC LIMIT ?"
176
+ params.append(limit)
177
+
178
+ rows = conn.execute(query, params).fetchall()
179
+ return [self._row_to_dict(r) for r in rows]
180
+ finally:
181
+ conn.close()
182
+
183
+ def get_summary(self, profile_id: str) -> Dict[str, int]:
184
+ """Get pattern counts by type for a profile.
185
+
186
+ Returns:
187
+ Dict mapping pattern_type -> count.
188
+ """
189
+ with self._lock:
190
+ conn = self._connect()
191
+ try:
192
+ rows = conn.execute(
193
+ "SELECT pattern_type, COUNT(*) as cnt "
194
+ "FROM _store_patterns "
195
+ "WHERE profile_id = ? "
196
+ "GROUP BY pattern_type",
197
+ (profile_id,),
198
+ ).fetchall()
199
+ return {row[0]: row[1] for row in rows}
200
+ finally:
201
+ conn.close()
202
+
203
+ def transfer_patterns(
204
+ self,
205
+ source_profile: str,
206
+ target_profile: str,
207
+ min_confidence: float = 0.0,
208
+ ) -> int:
209
+ """Copy eligible patterns from source to target profile.
210
+
211
+ Only metadata (type, key, success_rate, confidence) is transferred.
212
+ Memory content is never transferred. Creates new rows in the target
213
+ profile scope.
214
+
215
+ Args:
216
+ source_profile: Profile to copy patterns from.
217
+ target_profile: Profile to copy patterns to.
218
+ min_confidence: Only transfer patterns above this threshold.
219
+
220
+ Returns:
221
+ Number of patterns transferred.
222
+ """
223
+ if source_profile == target_profile:
224
+ return 0
225
+
226
+ source_patterns = self.get_patterns(
227
+ source_profile, min_confidence=min_confidence
228
+ )
229
+
230
+ transferred = 0
231
+ for pattern in source_patterns:
232
+ # Skip if target already has this pattern
233
+ existing = self.get_patterns(
234
+ target_profile,
235
+ pattern_type=pattern["pattern_type"],
236
+ )
237
+ already_exists = any(
238
+ p["pattern_key"] == pattern.get("pattern_key", "")
239
+ for p in existing
240
+ )
241
+ if already_exists:
242
+ continue
243
+
244
+ self.record_pattern(
245
+ profile_id=target_profile,
246
+ pattern_type=pattern["pattern_type"],
247
+ data={
248
+ "topic": pattern.get("pattern_key", ""),
249
+ "transferred_from": source_profile,
250
+ "original_confidence": pattern.get("confidence", 0.0),
251
+ },
252
+ success_rate=pattern.get("success_rate", 0.0),
253
+ confidence=pattern.get("confidence", 0.0) * 0.8,
254
+ )
255
+ transferred += 1
256
+
257
+ return transferred
258
+
259
+ def delete_patterns(
260
+ self,
261
+ profile_id: str,
262
+ pattern_type: Optional[str] = None,
263
+ ) -> int:
264
+ """Delete patterns for a profile. Optionally filter by type.
265
+
266
+ Returns:
267
+ Number of patterns deleted.
268
+ """
269
+ with self._lock:
270
+ conn = self._connect()
271
+ try:
272
+ if pattern_type:
273
+ cur = conn.execute(
274
+ "DELETE FROM _store_patterns "
275
+ "WHERE profile_id = ? AND pattern_type = ?",
276
+ (profile_id, pattern_type),
277
+ )
278
+ else:
279
+ cur = conn.execute(
280
+ "DELETE FROM _store_patterns WHERE profile_id = ?",
281
+ (profile_id,),
282
+ )
283
+ conn.commit()
284
+ return cur.rowcount
285
+ finally:
286
+ conn.close()
287
+
288
+ # ------------------------------------------------------------------
289
+ # Internal helpers
290
+ # ------------------------------------------------------------------
291
+
292
+ @staticmethod
293
+ def _compute_confidence(evidence_count: int, success_rate: float) -> float:
294
+ """Confidence = min(evidence/10, 1.0) * abs(rate - 0.5) * 2.
295
+
296
+ High confidence requires both sufficient evidence AND a success
297
+ rate that deviates significantly from the 50% baseline.
298
+ """
299
+ evidence_factor = min(evidence_count / 10.0, 1.0)
300
+ deviation_factor = abs(success_rate - 0.5) * 2.0
301
+ return round(evidence_factor * deviation_factor, 4)
302
+
303
+ def _connect(self) -> sqlite3.Connection:
304
+ """Open a connection with row factory enabled."""
305
+ conn = sqlite3.connect(self._db_path)
306
+ conn.row_factory = sqlite3.Row
307
+ return conn
308
+
309
+ def _ensure_table(self) -> None:
310
+ """Create the _store_patterns table if it does not exist."""
311
+ conn = self._connect()
312
+ try:
313
+ conn.execute(_CREATE_TABLE)
314
+ conn.execute(_CREATE_INDEX)
315
+ conn.commit()
316
+ finally:
317
+ conn.close()
318
+
319
+ @staticmethod
320
+ def _row_to_dict(row: sqlite3.Row) -> Dict[str, Any]:
321
+ """Convert a sqlite3.Row into a plain dict with parsed JSON."""
322
+ d = dict(row)
323
+ meta = d.get("metadata", "{}")
324
+ d["metadata"] = json.loads(meta) if isinstance(meta, str) else meta
325
+ return d
326
+
327
+
328
+ # ---------------------------------------------------------------------------
329
+ # V3 API — BehavioralTracker (uses DatabaseManager + V3 schema)
330
+ # ---------------------------------------------------------------------------
331
+
332
+ from superlocalmemory.storage.models import BehavioralPattern # noqa: E402
333
+
334
+
335
+ class BehavioralTracker:
336
+ """V3 behavioral pattern tracker using DatabaseManager.
337
+
338
+ Records query patterns (time of day, query type, entity preferences)
339
+ and provides analytics (active hours, type distribution, preferences).
340
+
341
+ Uses the ``behavioral_patterns`` table from the V3 schema.
342
+ """
343
+
344
+ def __init__(self, db) -> None:
345
+ self._db = db
346
+
347
+ # ------------------------------------------------------------------
348
+ # Recording
349
+ # ------------------------------------------------------------------
350
+
351
+ def record_query(
352
+ self,
353
+ query: str,
354
+ query_type: str,
355
+ entities: list[str],
356
+ profile_id: str,
357
+ ) -> None:
358
+ """Record a query and extract behavioral patterns.
359
+
360
+ Creates up to 3 pattern types per call:
361
+ - ``time_of_day``: hour_N for current hour
362
+ - ``query_type``: keyed by the query_type string
363
+ - ``entity_pref``: one per entity (max 5, lowercased)
364
+ """
365
+ # 1. Time of day
366
+ hour = datetime.now(timezone.utc).hour
367
+ self._upsert_pattern(profile_id, "time_of_day", f"hour_{hour}")
368
+
369
+ # 2. Query type
370
+ if query_type:
371
+ self._upsert_pattern(profile_id, "query_type", query_type)
372
+
373
+ # 3. Entity preferences (max 5, lowercased)
374
+ for entity in entities[:5]:
375
+ self._upsert_pattern(profile_id, "entity_pref", entity.lower())
376
+
377
+ # ------------------------------------------------------------------
378
+ # Querying
379
+ # ------------------------------------------------------------------
380
+
381
+ def get_patterns(
382
+ self,
383
+ pattern_type: str,
384
+ profile_id: str,
385
+ min_confidence: float = 0.0,
386
+ ) -> list[BehavioralPattern]:
387
+ """Get patterns filtered by type, profile, and min confidence."""
388
+ rows = self._db.execute(
389
+ "SELECT * FROM behavioral_patterns "
390
+ "WHERE profile_id = ? AND pattern_type = ? AND confidence >= ? "
391
+ "ORDER BY confidence DESC",
392
+ (profile_id, pattern_type, min_confidence),
393
+ )
394
+ return [self._row_to_pattern(r) for r in rows]
395
+
396
+ def get_entity_preferences(
397
+ self, profile_id: str, top_k: int = 10
398
+ ) -> list[str]:
399
+ """Top-K preferred entities by confidence, highest first."""
400
+ rows = self._db.execute(
401
+ "SELECT pattern_key FROM behavioral_patterns "
402
+ "WHERE profile_id = ? AND pattern_type = 'entity_pref' "
403
+ "ORDER BY confidence DESC, observation_count DESC LIMIT ?",
404
+ (profile_id, top_k),
405
+ )
406
+ return [dict(r)["pattern_key"] for r in rows]
407
+
408
+ def get_active_hours(self, profile_id: str) -> list[int]:
409
+ """Top 5 active hours by observation count."""
410
+ rows = self._db.execute(
411
+ "SELECT pattern_key FROM behavioral_patterns "
412
+ "WHERE profile_id = ? AND pattern_type = 'time_of_day' "
413
+ "ORDER BY observation_count DESC LIMIT 5",
414
+ (profile_id,),
415
+ )
416
+ result: list[int] = []
417
+ for r in rows:
418
+ key = dict(r)["pattern_key"]
419
+ if key.startswith("hour_"):
420
+ try:
421
+ result.append(int(key[5:]))
422
+ except ValueError:
423
+ pass
424
+ return result
425
+
426
+ def get_query_type_distribution(self, profile_id: str) -> dict[str, float]:
427
+ """Proportional distribution of query types."""
428
+ rows = self._db.execute(
429
+ "SELECT pattern_key, observation_count FROM behavioral_patterns "
430
+ "WHERE profile_id = ? AND pattern_type = 'query_type'",
431
+ (profile_id,),
432
+ )
433
+ counts: dict[str, int] = {}
434
+ for r in rows:
435
+ d = dict(r)
436
+ counts[d["pattern_key"]] = d["observation_count"]
437
+
438
+ total = sum(counts.values())
439
+ if total == 0:
440
+ return {}
441
+ return {k: round(v / total, 4) for k, v in counts.items()}
442
+
443
+ # ------------------------------------------------------------------
444
+ # Internal
445
+ # ------------------------------------------------------------------
446
+
447
+ def _upsert_pattern(
448
+ self, profile_id: str, pattern_type: str, pattern_key: str
449
+ ) -> None:
450
+ """Insert or increment a pattern. Confidence = min(count/100, 1.0)."""
451
+ from superlocalmemory.storage.models import _new_id, _now
452
+
453
+ rows = self._db.execute(
454
+ "SELECT pattern_id, observation_count FROM behavioral_patterns "
455
+ "WHERE profile_id = ? AND pattern_type = ? AND pattern_key = ?",
456
+ (profile_id, pattern_type, pattern_key),
457
+ )
458
+ if rows:
459
+ d = dict(rows[0])
460
+ new_count = d["observation_count"] + 1
461
+ new_conf = min(new_count / 100.0, 1.0)
462
+ self._db.execute(
463
+ "UPDATE behavioral_patterns "
464
+ "SET observation_count = ?, confidence = ?, last_updated = ? "
465
+ "WHERE pattern_id = ?",
466
+ (new_count, new_conf, _now(), d["pattern_id"]),
467
+ )
468
+ else:
469
+ self._db.execute(
470
+ "INSERT INTO behavioral_patterns "
471
+ "(pattern_id, profile_id, pattern_type, pattern_key, "
472
+ " pattern_value, confidence, observation_count, last_updated) "
473
+ "VALUES (?, ?, ?, ?, '', ?, 1, ?)",
474
+ (_new_id(), profile_id, pattern_type, pattern_key, 0.01, _now()),
475
+ )
476
+
477
+ @staticmethod
478
+ def _row_to_pattern(row) -> BehavioralPattern:
479
+ """Convert a DB row to BehavioralPattern."""
480
+ d = dict(row)
481
+ return BehavioralPattern(
482
+ pattern_id=d["pattern_id"],
483
+ profile_id=d["profile_id"],
484
+ pattern_type=d.get("pattern_type", ""),
485
+ pattern_key=d.get("pattern_key", ""),
486
+ pattern_value=d.get("pattern_value", ""),
487
+ confidence=d.get("confidence", 0.0),
488
+ observation_count=d.get("observation_count", 0),
489
+ last_updated=d.get("last_updated", ""),
490
+ )
@@ -0,0 +1,94 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """Behavioral listener — subscribes to event bus, captures patterns.
6
+
7
+ Connects to the V3 event bus and records all memory operations
8
+ for behavioral pattern mining.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+ import time
15
+ from collections import deque
16
+ from typing import Any
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # Max events kept in memory for pattern mining
21
+ MAX_EVENT_BUFFER = 500
22
+
23
+
24
+ class BehavioralListener:
25
+ """Subscribes to event bus and records behavioral data."""
26
+
27
+ def __init__(self, event_bus=None, db_path=None):
28
+ self._events = deque(maxlen=MAX_EVENT_BUFFER)
29
+ self._event_count = 0
30
+ self._db_path = db_path
31
+
32
+ if event_bus:
33
+ event_bus.subscribe(self._on_event)
34
+
35
+ @property
36
+ def event_count(self) -> int:
37
+ return self._event_count
38
+
39
+ def _on_event(self, event: dict) -> None:
40
+ """Handle incoming event from bus."""
41
+ self._events.append({
42
+ "event_type": event.get("event_type", "unknown"),
43
+ "data": event.get("data", {}),
44
+ "timestamp": time.time(),
45
+ })
46
+ self._event_count += 1
47
+
48
+ def get_recent_events(self, limit: int = 50) -> list[dict]:
49
+ """Get most recent behavioral events."""
50
+ return list(self._events)[-limit:]
51
+
52
+ def mine_patterns(self) -> list[dict]:
53
+ """Mine behavioral patterns from recent events.
54
+
55
+ Detects:
56
+ - store->recall->store = refinement pattern
57
+ - repeated recall of same topic = interest pattern
58
+ - store without recall = archival pattern
59
+ """
60
+ patterns = []
61
+ events = list(self._events)
62
+
63
+ # Detect store->recall->store (refinement)
64
+ for i in range(len(events) - 2):
65
+ if (events[i]["event_type"] == "memory.stored" and
66
+ events[i+1]["event_type"] == "memory.recalled" and
67
+ events[i+2]["event_type"] == "memory.stored"):
68
+ patterns.append({
69
+ "pattern_type": "refinement",
70
+ "timestamp": events[i+2]["timestamp"],
71
+ "events": [events[i], events[i+1], events[i+2]],
72
+ })
73
+
74
+ # Detect repeated recall (interest)
75
+ recall_topics = {}
76
+ for e in events:
77
+ if e["event_type"] == "memory.recalled":
78
+ topic = e["data"].get("query_preview", "")[:50]
79
+ recall_topics[topic] = recall_topics.get(topic, 0) + 1
80
+
81
+ for topic, count in recall_topics.items():
82
+ if count >= 3:
83
+ patterns.append({
84
+ "pattern_type": "interest",
85
+ "topic": topic,
86
+ "count": count,
87
+ })
88
+
89
+ return patterns
90
+
91
+ def clear(self) -> None:
92
+ """Clear event buffer."""
93
+ self._events.clear()
94
+ self._event_count = 0