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,203 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """EventBus listener that bridges events to the behavioral learning engine.
4
-
5
- Listens for memory.recalled, memory.deleted, and usage events.
6
- Feeds recall events to OutcomeInference for implicit outcome detection.
7
- Triggers pattern extraction after configurable outcome count threshold.
8
-
9
- Part of SLM v2.8 Behavioral Learning Engine.
10
- """
11
- import logging
12
- import threading
13
- from datetime import datetime
14
- from pathlib import Path
15
- from typing import Optional, Dict, Any, List
16
-
17
- from .outcome_tracker import OutcomeTracker
18
- from .outcome_inference import OutcomeInference
19
-
20
- logger = logging.getLogger("superlocalmemory.behavioral.listener")
21
-
22
- # Default: extract patterns every 100 new outcomes
23
- DEFAULT_EXTRACTION_THRESHOLD = 100
24
-
25
-
26
- class BehavioralListener:
27
- """EventBus listener that feeds events to the behavioral learning engine.
28
-
29
- Processes:
30
- - memory.recalled -> feeds to OutcomeInference (implicit outcome detection)
31
- - memory.deleted -> records deletion for inference (Rule 1 signal)
32
- - Usage signals -> records for inference (Rule 2/3 signals)
33
-
34
- Thread-safe: handle_event can be called from any thread.
35
- Listener callbacks run on the emitter's thread -- must be fast.
36
- """
37
-
38
- # Event types this listener cares about
39
- _RECALL_EVENT = "memory.recalled"
40
- _DELETION_EVENT = "memory.deleted"
41
-
42
- def __init__(
43
- self,
44
- db_path: Optional[str] = None,
45
- extraction_threshold: int = DEFAULT_EXTRACTION_THRESHOLD,
46
- ):
47
- if db_path is None:
48
- db_path = str(Path.home() / ".claude-memory" / "learning.db")
49
- self._db_path = str(db_path)
50
- self.extraction_threshold = extraction_threshold
51
-
52
- # Core components
53
- self._tracker = OutcomeTracker(self._db_path)
54
- self._inference = OutcomeInference()
55
-
56
- # Thread safety
57
- self._lock = threading.Lock()
58
-
59
- # Counters
60
- self.events_processed = 0
61
- self.recall_events_processed = 0
62
- self.deletion_events_processed = 0
63
- self._outcome_count_since_extraction = 0
64
- self._registered = False
65
-
66
- # ------------------------------------------------------------------
67
- # Event handling (called on emitter's thread — must be fast)
68
- # ------------------------------------------------------------------
69
-
70
- def handle_event(self, event: Dict[str, Any]) -> None:
71
- """Process an EventBus event.
72
-
73
- Called on the emitter's thread — must be fast and non-blocking.
74
- Filters by event_type and dispatches to the appropriate handler.
75
- """
76
- event_type = event.get("event_type", "")
77
- payload = event.get("payload", {})
78
- memory_id = event.get("memory_id")
79
- timestamp_str = event.get("timestamp")
80
-
81
- try:
82
- timestamp = (
83
- datetime.fromisoformat(timestamp_str)
84
- if timestamp_str
85
- else datetime.now()
86
- )
87
- except (ValueError, TypeError):
88
- timestamp = datetime.now()
89
-
90
- with self._lock:
91
- self.events_processed += 1
92
-
93
- if event_type == self._RECALL_EVENT:
94
- self._handle_recall(payload, memory_id, timestamp)
95
-
96
- elif event_type == self._DELETION_EVENT:
97
- self._handle_deletion(memory_id, timestamp)
98
- # All other event types are silently ignored
99
-
100
- def _handle_recall(
101
- self,
102
- payload: Dict[str, Any],
103
- memory_id: Optional[int],
104
- timestamp: datetime,
105
- ) -> None:
106
- """Process a memory.recalled event. Must be called under self._lock."""
107
- query = payload.get("query", "")
108
- memory_ids = payload.get(
109
- "memory_ids", [memory_id] if memory_id else []
110
- )
111
- signal = payload.get("signal")
112
-
113
- self._inference.record_recall(query, memory_ids, timestamp)
114
- if signal:
115
- self._inference.record_usage(
116
- query, signal=signal, timestamp=timestamp
117
- )
118
- self.recall_events_processed += 1
119
-
120
- # Periodically run inference (every 10 recall events)
121
- if self.recall_events_processed % 10 == 0:
122
- self._run_inference_cycle()
123
-
124
- def _handle_deletion(
125
- self, memory_id: Optional[int], timestamp: datetime
126
- ) -> None:
127
- """Process a memory.deleted event. Must be called under self._lock."""
128
- if memory_id is not None:
129
- self._inference.record_deletion(memory_id, timestamp)
130
- self.deletion_events_processed += 1
131
-
132
- # ------------------------------------------------------------------
133
- # Inference + pattern extraction
134
- # ------------------------------------------------------------------
135
-
136
- def _run_inference_cycle(self) -> None:
137
- """Run outcome inference and optionally trigger pattern extraction."""
138
- inferences: List[Dict] = self._inference.infer_outcomes(
139
- datetime.now()
140
- )
141
- for inf in inferences:
142
- self._tracker.record_outcome(
143
- memory_ids=inf["memory_ids"],
144
- outcome=inf["outcome"],
145
- action_type="inferred",
146
- confidence=inf["confidence"],
147
- context={"reason": inf.get("reason", "")},
148
- )
149
- self._outcome_count_since_extraction += 1
150
-
151
- if self._outcome_count_since_extraction >= self.extraction_threshold:
152
- self._trigger_extraction()
153
-
154
- def _trigger_extraction(self) -> None:
155
- """Trigger behavioral pattern extraction. Best-effort."""
156
- try:
157
- from .behavioral_patterns import BehavioralPatternExtractor
158
-
159
- extractor = BehavioralPatternExtractor(self._db_path)
160
- extractor.extract_patterns()
161
- extractor.save_patterns()
162
- self._outcome_count_since_extraction = 0
163
- except Exception as exc:
164
- logger.warning("Pattern extraction failed: %s", exc)
165
-
166
- # ------------------------------------------------------------------
167
- # EventBus registration
168
- # ------------------------------------------------------------------
169
-
170
- def register_with_eventbus(self) -> bool:
171
- """Register this listener with the EventBus singleton.
172
-
173
- Returns True if registration succeeds, False otherwise.
174
- Graceful degradation: failure here does NOT break the engine.
175
- """
176
- try:
177
- from event_bus import EventBus
178
-
179
- bus = EventBus.get_instance(Path(self._db_path))
180
- bus.add_listener(self.handle_event)
181
- self._registered = True
182
- return True
183
- except Exception as exc:
184
- logger.info(
185
- "EventBus registration skipped (not available): %s", exc
186
- )
187
- self._registered = False
188
- return False
189
-
190
- # ------------------------------------------------------------------
191
- # Status / introspection
192
- # ------------------------------------------------------------------
193
-
194
- def get_status(self) -> Dict[str, Any]:
195
- """Return listener status for diagnostics."""
196
- return {
197
- "events_processed": self.events_processed,
198
- "recall_events_processed": self.recall_events_processed,
199
- "deletion_events_processed": self.deletion_events_processed,
200
- "registered": self._registered,
201
- "outcome_count_since_extraction": self._outcome_count_since_extraction,
202
- "extraction_threshold": self.extraction_threshold,
203
- }
@@ -1,275 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Pattern extraction from action outcome histories.
4
-
5
- Scans the action_outcomes table, groups by project and action_type,
6
- calculates success rates, and stores discovered patterns in the
7
- behavioral_patterns table. Self-contained: creates its own table via
8
- CREATE TABLE IF NOT EXISTS so no external migration is needed.
9
-
10
- Part of SLM v2.8 Behavioral Learning Engine.
11
- """
12
- import json
13
- import sqlite3
14
- import threading
15
- from datetime import datetime, timezone
16
- from typing import Dict, List, Optional, Any
17
-
18
-
19
- class BehavioralPatternExtractor:
20
- """Extracts success/failure patterns from outcome data.
21
-
22
- Analyzes action_outcomes rows to discover:
23
- - project_success: success rate per project
24
- - action_type_success: success rate per action_type
25
-
26
- Confidence formula:
27
- min(evidence_count / 10, 1.0) * abs(success_rate - 0.5) * 2
28
- This yields high confidence only when there is enough evidence AND the
29
- success rate is far from the 50/50 coin-flip baseline.
30
- """
31
-
32
- PATTERN_TYPES = ("project_success", "action_type_success")
33
-
34
- _CREATE_TABLE = """
35
- CREATE TABLE IF NOT EXISTS behavioral_patterns (
36
- id INTEGER PRIMARY KEY AUTOINCREMENT,
37
- pattern_type TEXT NOT NULL,
38
- pattern_key TEXT NOT NULL,
39
- success_rate REAL DEFAULT 0.0,
40
- evidence_count INTEGER DEFAULT 0,
41
- confidence REAL DEFAULT 0.0,
42
- metadata TEXT DEFAULT '{}',
43
- project TEXT,
44
- profile TEXT DEFAULT 'default',
45
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
46
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
47
- )
48
- """
49
-
50
- # Minimum outcomes required before we emit a pattern at all.
51
- MIN_EVIDENCE = 3
52
-
53
- def __init__(self, db_path: Optional[str] = None):
54
- self._db_path = db_path
55
- self._lock = threading.Lock()
56
- self._patterns: List[Dict[str, Any]] = []
57
- if db_path:
58
- self._ensure_table()
59
-
60
- # ------------------------------------------------------------------
61
- # Public API
62
- # ------------------------------------------------------------------
63
-
64
- def extract_patterns(self) -> List[Dict[str, Any]]:
65
- """Scan action_outcomes and extract success/failure patterns.
66
-
67
- Groups outcomes by project and by action_type, calculates
68
- success rates, and returns a list of pattern dicts. Also stores
69
- the result internally so a subsequent ``save_patterns()`` call
70
- can persist them.
71
-
72
- Returns:
73
- List of pattern dicts with keys: pattern_type, pattern_key,
74
- success_rate, evidence_count, confidence, metadata, project.
75
- """
76
- patterns: List[Dict[str, Any]] = []
77
- with self._lock:
78
- conn = self._connect()
79
- try:
80
- patterns.extend(self._extract_project_patterns(conn))
81
- patterns.extend(self._extract_action_type_patterns(conn))
82
- finally:
83
- conn.close()
84
- self._patterns = patterns
85
- return patterns
86
-
87
- def save_patterns(self) -> int:
88
- """Persist the most recently extracted patterns to the DB.
89
-
90
- Inserts (or replaces) rows in the behavioral_patterns table.
91
-
92
- Returns:
93
- Number of patterns saved.
94
- """
95
- if not self._patterns:
96
- return 0
97
-
98
- now = datetime.now(timezone.utc).isoformat()
99
- with self._lock:
100
- conn = self._connect()
101
- try:
102
- for p in self._patterns:
103
- # Upsert: delete any existing row for the same
104
- # (pattern_type, pattern_key, project) then insert.
105
- conn.execute(
106
- """DELETE FROM behavioral_patterns
107
- WHERE pattern_type = ? AND pattern_key = ?
108
- AND COALESCE(project, '') = COALESCE(?, '')""",
109
- (p["pattern_type"], p["pattern_key"], p.get("project")),
110
- )
111
- conn.execute(
112
- """INSERT INTO behavioral_patterns
113
- (pattern_type, pattern_key, success_rate,
114
- evidence_count, confidence, metadata,
115
- project, created_at, updated_at)
116
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
117
- (
118
- p["pattern_type"],
119
- p["pattern_key"],
120
- p["success_rate"],
121
- p["evidence_count"],
122
- p["confidence"],
123
- json.dumps(p.get("metadata", {})),
124
- p.get("project"),
125
- now,
126
- now,
127
- ),
128
- )
129
- conn.commit()
130
- return len(self._patterns)
131
- finally:
132
- conn.close()
133
-
134
- def get_patterns(
135
- self,
136
- min_confidence: float = 0.0,
137
- project: Optional[str] = None,
138
- ) -> List[Dict[str, Any]]:
139
- """Read stored patterns from the DB with optional filters.
140
-
141
- Args:
142
- min_confidence: Only return patterns with confidence >= this.
143
- project: If given, filter by project scope.
144
-
145
- Returns:
146
- List of pattern dicts read from the database.
147
- """
148
- with self._lock:
149
- conn = self._connect()
150
- try:
151
- query = (
152
- "SELECT * FROM behavioral_patterns "
153
- "WHERE confidence >= ?"
154
- )
155
- params: List[Any] = [min_confidence]
156
- if project is not None:
157
- query += " AND project = ?"
158
- params.append(project)
159
- query += " ORDER BY confidence DESC"
160
- rows = conn.execute(query, params).fetchall()
161
- return [self._row_to_dict(r) for r in rows]
162
- finally:
163
- conn.close()
164
-
165
- # ------------------------------------------------------------------
166
- # Internal extraction helpers
167
- # ------------------------------------------------------------------
168
-
169
- def _extract_project_patterns(
170
- self, conn: sqlite3.Connection
171
- ) -> List[Dict[str, Any]]:
172
- """Group outcomes by project and compute success rates."""
173
- rows = conn.execute(
174
- """SELECT project,
175
- COUNT(*) AS total,
176
- SUM(CASE WHEN outcome = 'success' THEN 1 ELSE 0 END) AS wins
177
- FROM action_outcomes
178
- WHERE project IS NOT NULL
179
- GROUP BY project
180
- HAVING total >= ?""",
181
- (self.MIN_EVIDENCE,),
182
- ).fetchall()
183
-
184
- patterns = []
185
- for row in rows:
186
- project = row[0]
187
- total = row[1]
188
- wins = row[2]
189
- rate = round(wins / total, 4) if total else 0.0
190
- confidence = self._compute_confidence(total, rate)
191
- patterns.append(
192
- {
193
- "pattern_type": "project_success",
194
- "pattern_key": project,
195
- "success_rate": rate,
196
- "evidence_count": total,
197
- "confidence": confidence,
198
- "metadata": {"wins": wins, "losses": total - wins},
199
- "project": project,
200
- }
201
- )
202
- return patterns
203
-
204
- def _extract_action_type_patterns(
205
- self, conn: sqlite3.Connection
206
- ) -> List[Dict[str, Any]]:
207
- """Group outcomes by action_type and compute success rates."""
208
- rows = conn.execute(
209
- """SELECT action_type,
210
- COUNT(*) AS total,
211
- SUM(CASE WHEN outcome = 'success' THEN 1 ELSE 0 END) AS wins
212
- FROM action_outcomes
213
- WHERE action_type IS NOT NULL
214
- GROUP BY action_type
215
- HAVING total >= ?""",
216
- (self.MIN_EVIDENCE,),
217
- ).fetchall()
218
-
219
- patterns = []
220
- for row in rows:
221
- action_type = row[0]
222
- total = row[1]
223
- wins = row[2]
224
- rate = round(wins / total, 4) if total else 0.0
225
- confidence = self._compute_confidence(total, rate)
226
- patterns.append(
227
- {
228
- "pattern_type": "action_type_success",
229
- "pattern_key": action_type,
230
- "success_rate": rate,
231
- "evidence_count": total,
232
- "confidence": confidence,
233
- "metadata": {"wins": wins, "losses": total - wins},
234
- "project": None,
235
- }
236
- )
237
- return patterns
238
-
239
- # ------------------------------------------------------------------
240
- # Internal helpers
241
- # ------------------------------------------------------------------
242
-
243
- @staticmethod
244
- def _compute_confidence(evidence_count: int, success_rate: float) -> float:
245
- """Confidence = min(evidence/10, 1.0) * abs(rate - 0.5) * 2.
246
-
247
- High confidence requires both sufficient evidence AND a success
248
- rate that deviates significantly from the 50% baseline.
249
- """
250
- evidence_factor = min(evidence_count / 10.0, 1.0)
251
- deviation_factor = abs(success_rate - 0.5) * 2.0
252
- return round(evidence_factor * deviation_factor, 4)
253
-
254
- def _connect(self) -> sqlite3.Connection:
255
- """Open a connection with row factory enabled."""
256
- conn = sqlite3.connect(self._db_path)
257
- conn.row_factory = sqlite3.Row
258
- return conn
259
-
260
- def _ensure_table(self) -> None:
261
- """Create the behavioral_patterns table if it doesn't exist."""
262
- conn = self._connect()
263
- try:
264
- conn.execute(self._CREATE_TABLE)
265
- conn.commit()
266
- finally:
267
- conn.close()
268
-
269
- @staticmethod
270
- def _row_to_dict(row: sqlite3.Row) -> Dict[str, Any]:
271
- """Convert a sqlite3.Row into a plain dict with parsed JSON."""
272
- d = dict(row)
273
- meta = d.get("metadata", "{}")
274
- d["metadata"] = json.loads(meta) if isinstance(meta, str) else meta
275
- return d
@@ -1,206 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Privacy-safe cross-project behavioral pattern transfer.
4
-
5
- Transfers behavioral patterns between projects using ONLY metadata
6
- (pattern type, success rate, confidence). Never transfers memory
7
- content or content hashes.
8
-
9
- Eligibility criteria:
10
- - confidence >= 0.7
11
- - evidence_count >= 5
12
- - source project != target project
13
-
14
- Part of SLM v2.8 Behavioral Learning Engine.
15
- """
16
- import sqlite3
17
- import threading
18
- from typing import Dict, List, Optional, Any
19
-
20
-
21
- # Thresholds for transfer eligibility
22
- MIN_CONFIDENCE = 0.7
23
- MIN_EVIDENCE = 5
24
-
25
-
26
- class CrossProjectTransfer:
27
- """Privacy-safe cross-project behavioral pattern transfer.
28
-
29
- Only metadata (pattern_type, pattern_key, success_rate,
30
- evidence_count, confidence) is transferred — never content
31
- or content hashes.
32
- """
33
-
34
- _CREATE_CROSS_TABLE = """
35
- CREATE TABLE IF NOT EXISTS cross_project_behaviors (
36
- id INTEGER PRIMARY KEY AUTOINCREMENT,
37
- source_project TEXT NOT NULL,
38
- target_project TEXT NOT NULL,
39
- pattern_id INTEGER NOT NULL,
40
- transfer_type TEXT DEFAULT 'metadata',
41
- confidence REAL DEFAULT 0.0,
42
- profile TEXT DEFAULT 'default',
43
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
44
- FOREIGN KEY (pattern_id) REFERENCES behavioral_patterns(id)
45
- )
46
- """
47
-
48
- def __init__(self, db_path: Optional[str] = None, enabled: bool = True):
49
- self._db_path = db_path
50
- self._enabled = enabled
51
- self._lock = threading.Lock()
52
- if db_path:
53
- self._ensure_tables()
54
-
55
- # ------------------------------------------------------------------
56
- # Public API
57
- # ------------------------------------------------------------------
58
-
59
- def evaluate_transfers(
60
- self, target_project: str
61
- ) -> List[Dict[str, Any]]:
62
- """Find patterns eligible for transfer to the target project.
63
-
64
- Eligibility: confidence >= 0.7 AND evidence_count >= 5
65
- AND source project != target project.
66
-
67
- Returns:
68
- List of dicts with metadata-only fields: pattern_id,
69
- pattern_type, pattern_key, success_rate, evidence_count,
70
- confidence, source_project, transfer_type.
71
- """
72
- if not self._enabled:
73
- return []
74
-
75
- with self._lock:
76
- conn = self._connect()
77
- try:
78
- rows = conn.execute(
79
- """SELECT id, pattern_type, pattern_key, success_rate,
80
- evidence_count, confidence, project
81
- FROM behavioral_patterns
82
- WHERE confidence >= ?
83
- AND evidence_count >= ?
84
- AND project IS NOT NULL
85
- AND project != ?
86
- ORDER BY confidence DESC""",
87
- (MIN_CONFIDENCE, MIN_EVIDENCE, target_project),
88
- ).fetchall()
89
-
90
- return [self._eligible_to_dict(row) for row in rows]
91
- finally:
92
- conn.close()
93
-
94
- def apply_transfer(
95
- self, pattern_id: int, target_project: str
96
- ) -> Dict[str, Any]:
97
- """Record a cross-project transfer in the database.
98
-
99
- Looks up the source pattern to get its project and confidence,
100
- then inserts a record into cross_project_behaviors.
101
-
102
- Returns:
103
- Dict with success status and transfer id.
104
- """
105
- with self._lock:
106
- conn = self._connect()
107
- try:
108
- # Look up the source pattern
109
- pattern = conn.execute(
110
- "SELECT project, confidence FROM behavioral_patterns WHERE id = ?",
111
- (pattern_id,),
112
- ).fetchone()
113
-
114
- if pattern is None:
115
- return {"success": False, "error": "pattern_not_found"}
116
-
117
- source_project = pattern["project"]
118
- confidence = pattern["confidence"]
119
-
120
- cur = conn.execute(
121
- """INSERT INTO cross_project_behaviors
122
- (source_project, target_project, pattern_id,
123
- transfer_type, confidence)
124
- VALUES (?, ?, ?, 'metadata', ?)""",
125
- (source_project, target_project, pattern_id, confidence),
126
- )
127
- conn.commit()
128
- return {
129
- "success": True,
130
- "transfer_id": cur.lastrowid,
131
- "source_project": source_project,
132
- "target_project": target_project,
133
- }
134
- finally:
135
- conn.close()
136
-
137
- def get_transfers(
138
- self,
139
- target_project: Optional[str] = None,
140
- source_project: Optional[str] = None,
141
- ) -> List[Dict[str, Any]]:
142
- """Query recorded cross-project transfers.
143
-
144
- Args:
145
- target_project: Filter by target project.
146
- source_project: Filter by source project.
147
-
148
- Returns:
149
- List of transfer record dicts.
150
- """
151
- with self._lock:
152
- conn = self._connect()
153
- try:
154
- query = "SELECT * FROM cross_project_behaviors WHERE 1=1"
155
- params: List[Any] = []
156
-
157
- if target_project is not None:
158
- query += " AND target_project = ?"
159
- params.append(target_project)
160
-
161
- if source_project is not None:
162
- query += " AND source_project = ?"
163
- params.append(source_project)
164
-
165
- query += " ORDER BY created_at DESC"
166
-
167
- rows = conn.execute(query, params).fetchall()
168
- return [dict(row) for row in rows]
169
- finally:
170
- conn.close()
171
-
172
- # ------------------------------------------------------------------
173
- # Internal helpers
174
- # ------------------------------------------------------------------
175
-
176
- def _connect(self) -> sqlite3.Connection:
177
- """Open a connection with row factory enabled."""
178
- conn = sqlite3.connect(self._db_path)
179
- conn.row_factory = sqlite3.Row
180
- return conn
181
-
182
- def _ensure_tables(self) -> None:
183
- """Create the cross_project_behaviors table if missing."""
184
- conn = self._connect()
185
- try:
186
- conn.execute(self._CREATE_CROSS_TABLE)
187
- conn.commit()
188
- finally:
189
- conn.close()
190
-
191
- @staticmethod
192
- def _eligible_to_dict(row: sqlite3.Row) -> Dict[str, Any]:
193
- """Convert a pattern row to a privacy-safe transfer dict.
194
-
195
- Only metadata fields are included. No content, no hashes.
196
- """
197
- return {
198
- "pattern_id": row["id"],
199
- "pattern_type": row["pattern_type"],
200
- "pattern_key": row["pattern_key"],
201
- "success_rate": row["success_rate"],
202
- "evidence_count": row["evidence_count"],
203
- "confidence": row["confidence"],
204
- "source_project": row["project"],
205
- "transfer_type": "metadata",
206
- }