superlocalmemory 2.8.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +9 -1
  3. package/NOTICE +63 -0
  4. package/README.md +165 -480
  5. package/bin/slm +17 -449
  6. package/bin/slm-npm +2 -2
  7. package/bin/slm.bat +4 -2
  8. package/conftest.py +5 -0
  9. package/docs/api-reference.md +284 -0
  10. package/docs/architecture.md +149 -0
  11. package/docs/auto-memory.md +150 -0
  12. package/docs/cli-reference.md +276 -0
  13. package/docs/compliance.md +191 -0
  14. package/docs/configuration.md +182 -0
  15. package/docs/getting-started.md +102 -0
  16. package/docs/ide-setup.md +261 -0
  17. package/docs/mcp-tools.md +220 -0
  18. package/docs/migration-from-v2.md +170 -0
  19. package/docs/profiles.md +173 -0
  20. package/docs/troubleshooting.md +310 -0
  21. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  22. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  23. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  24. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  25. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  26. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  27. package/ide/configs/cursor-mcp.json +15 -0
  28. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  29. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  30. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  31. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  32. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  33. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  34. package/{configs → ide/configs}/zed-mcp.json +2 -2
  35. package/{hooks → ide/hooks}/context-hook.js +9 -20
  36. package/ide/hooks/memory-list-skill.js +70 -0
  37. package/ide/hooks/memory-profile-skill.js +101 -0
  38. package/ide/hooks/memory-recall-skill.js +62 -0
  39. package/ide/hooks/memory-remember-skill.js +68 -0
  40. package/ide/hooks/memory-reset-skill.js +160 -0
  41. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  42. package/ide/integrations/langchain/README.md +106 -0
  43. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  44. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  45. package/ide/integrations/langchain/pyproject.toml +38 -0
  46. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  47. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  48. package/ide/integrations/langchain/tests/test_security.py +117 -0
  49. package/ide/integrations/llamaindex/README.md +81 -0
  50. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  51. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  52. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  53. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  54. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  55. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  56. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  57. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  58. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  59. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  60. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  61. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  62. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  63. package/package.json +13 -22
  64. package/pyproject.toml +85 -0
  65. package/scripts/build-dmg.sh +417 -0
  66. package/scripts/install-skills.ps1 +334 -0
  67. package/{install.ps1 → scripts/install.ps1} +36 -4
  68. package/{install.sh → scripts/install.sh} +14 -13
  69. package/scripts/postinstall.js +2 -2
  70. package/scripts/start-dashboard.ps1 +52 -0
  71. package/scripts/start-dashboard.sh +41 -0
  72. package/scripts/sync-wiki.ps1 +127 -0
  73. package/scripts/sync-wiki.sh +82 -0
  74. package/scripts/test-dmg.sh +161 -0
  75. package/scripts/test-npm-package.ps1 +252 -0
  76. package/scripts/test-npm-package.sh +207 -0
  77. package/scripts/verify-install.ps1 +294 -0
  78. package/scripts/verify-install.sh +266 -0
  79. package/src/superlocalmemory/__init__.py +0 -0
  80. package/src/superlocalmemory/attribution/__init__.py +9 -0
  81. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  82. package/src/superlocalmemory/attribution/signer.py +153 -0
  83. package/src/superlocalmemory/attribution/watermark.py +189 -0
  84. package/src/superlocalmemory/cli/__init__.py +5 -0
  85. package/src/superlocalmemory/cli/commands.py +245 -0
  86. package/src/superlocalmemory/cli/main.py +89 -0
  87. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  88. package/src/superlocalmemory/cli/post_install.py +99 -0
  89. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  90. package/src/superlocalmemory/compliance/__init__.py +0 -0
  91. package/src/superlocalmemory/compliance/abac.py +204 -0
  92. package/src/superlocalmemory/compliance/audit.py +314 -0
  93. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  94. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  95. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  96. package/src/superlocalmemory/compliance/retention.py +232 -0
  97. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  98. package/src/superlocalmemory/core/__init__.py +0 -0
  99. package/src/superlocalmemory/core/config.py +391 -0
  100. package/src/superlocalmemory/core/embeddings.py +293 -0
  101. package/src/superlocalmemory/core/engine.py +701 -0
  102. package/src/superlocalmemory/core/hooks.py +65 -0
  103. package/src/superlocalmemory/core/maintenance.py +172 -0
  104. package/src/superlocalmemory/core/modes.py +140 -0
  105. package/src/superlocalmemory/core/profiles.py +234 -0
  106. package/src/superlocalmemory/core/registry.py +117 -0
  107. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  108. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  109. package/src/superlocalmemory/encoding/__init__.py +0 -0
  110. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  111. package/src/superlocalmemory/encoding/emotional.py +125 -0
  112. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  113. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  114. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  115. package/src/superlocalmemory/encoding/foresight.py +91 -0
  116. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  117. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  118. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  119. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  120. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  121. package/src/superlocalmemory/encoding/type_router.py +235 -0
  122. package/src/superlocalmemory/hooks/__init__.py +3 -0
  123. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  124. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  125. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  126. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  127. package/src/superlocalmemory/infra/__init__.py +3 -0
  128. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  129. package/src/superlocalmemory/infra/backup.py +317 -0
  130. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  131. package/src/superlocalmemory/infra/event_bus.py +381 -0
  132. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  133. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  134. package/src/superlocalmemory/learning/__init__.py +0 -0
  135. package/src/superlocalmemory/learning/adaptive.py +172 -0
  136. package/src/superlocalmemory/learning/behavioral.py +490 -0
  137. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  138. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  139. package/src/superlocalmemory/learning/cross_project.py +399 -0
  140. package/src/superlocalmemory/learning/database.py +376 -0
  141. package/src/superlocalmemory/learning/engagement.py +323 -0
  142. package/src/superlocalmemory/learning/features.py +138 -0
  143. package/src/superlocalmemory/learning/feedback.py +316 -0
  144. package/src/superlocalmemory/learning/outcomes.py +255 -0
  145. package/src/superlocalmemory/learning/project_context.py +366 -0
  146. package/src/superlocalmemory/learning/ranker.py +155 -0
  147. package/src/superlocalmemory/learning/source_quality.py +303 -0
  148. package/src/superlocalmemory/learning/workflows.py +309 -0
  149. package/src/superlocalmemory/llm/__init__.py +0 -0
  150. package/src/superlocalmemory/llm/backbone.py +316 -0
  151. package/src/superlocalmemory/math/__init__.py +0 -0
  152. package/src/superlocalmemory/math/fisher.py +356 -0
  153. package/src/superlocalmemory/math/langevin.py +398 -0
  154. package/src/superlocalmemory/math/sheaf.py +257 -0
  155. package/src/superlocalmemory/mcp/__init__.py +0 -0
  156. package/src/superlocalmemory/mcp/resources.py +245 -0
  157. package/src/superlocalmemory/mcp/server.py +61 -0
  158. package/src/superlocalmemory/mcp/tools.py +18 -0
  159. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  160. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  161. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  162. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  163. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  164. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  165. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  166. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  167. package/src/superlocalmemory/retrieval/engine.py +390 -0
  168. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  169. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  170. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  171. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  172. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  173. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  174. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  175. package/src/superlocalmemory/server/__init__.py +1 -0
  176. package/src/superlocalmemory/server/api.py +248 -0
  177. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  178. package/src/superlocalmemory/server/routes/agents.py +107 -0
  179. package/src/superlocalmemory/server/routes/backup.py +91 -0
  180. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  181. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  182. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  183. package/src/superlocalmemory/server/routes/events.py +183 -0
  184. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  185. package/src/superlocalmemory/server/routes/learning.py +273 -0
  186. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  187. package/src/superlocalmemory/server/routes/memories.py +399 -0
  188. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  189. package/src/superlocalmemory/server/routes/stats.py +346 -0
  190. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  191. package/src/superlocalmemory/server/routes/ws.py +82 -0
  192. package/src/superlocalmemory/server/security_middleware.py +57 -0
  193. package/src/superlocalmemory/server/ui.py +245 -0
  194. package/src/superlocalmemory/storage/__init__.py +0 -0
  195. package/src/superlocalmemory/storage/access_control.py +182 -0
  196. package/src/superlocalmemory/storage/database.py +594 -0
  197. package/src/superlocalmemory/storage/migrations.py +303 -0
  198. package/src/superlocalmemory/storage/models.py +406 -0
  199. package/src/superlocalmemory/storage/schema.py +726 -0
  200. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  201. package/src/superlocalmemory/trust/__init__.py +0 -0
  202. package/src/superlocalmemory/trust/gate.py +130 -0
  203. package/src/superlocalmemory/trust/provenance.py +124 -0
  204. package/src/superlocalmemory/trust/scorer.py +347 -0
  205. package/src/superlocalmemory/trust/signals.py +153 -0
  206. package/ui/index.html +278 -5
  207. package/ui/js/auto-settings.js +70 -0
  208. package/ui/js/dashboard.js +90 -0
  209. package/ui/js/fact-detail.js +92 -0
  210. package/ui/js/feedback.js +2 -2
  211. package/ui/js/ide-status.js +102 -0
  212. package/ui/js/math-health.js +98 -0
  213. package/ui/js/recall-lab.js +127 -0
  214. package/ui/js/settings.js +2 -2
  215. package/ui/js/trust-dashboard.js +73 -0
  216. package/api_server.py +0 -724
  217. package/bin/aider-smart +0 -72
  218. package/bin/superlocalmemoryv2-learning +0 -4
  219. package/bin/superlocalmemoryv2-list +0 -3
  220. package/bin/superlocalmemoryv2-patterns +0 -4
  221. package/bin/superlocalmemoryv2-profile +0 -3
  222. package/bin/superlocalmemoryv2-recall +0 -3
  223. package/bin/superlocalmemoryv2-remember +0 -3
  224. package/bin/superlocalmemoryv2-reset +0 -3
  225. package/bin/superlocalmemoryv2-status +0 -3
  226. package/configs/chatgpt-desktop-mcp.json +0 -16
  227. package/configs/cursor-mcp.json +0 -15
  228. package/docs/SECURITY-QUICK-REFERENCE.md +0 -214
  229. package/hooks/memory-list-skill.js +0 -139
  230. package/hooks/memory-profile-skill.js +0 -273
  231. package/hooks/memory-recall-skill.js +0 -114
  232. package/hooks/memory-remember-skill.js +0 -127
  233. package/hooks/memory-reset-skill.js +0 -274
  234. package/mcp_server.py +0 -1800
  235. package/requirements-core.txt +0 -22
  236. package/requirements-learning.txt +0 -12
  237. package/requirements.txt +0 -12
  238. package/src/agent_registry.py +0 -411
  239. package/src/auth_middleware.py +0 -61
  240. package/src/auto_backup.py +0 -459
  241. package/src/behavioral/__init__.py +0 -49
  242. package/src/behavioral/behavioral_listener.py +0 -203
  243. package/src/behavioral/behavioral_patterns.py +0 -275
  244. package/src/behavioral/cross_project_transfer.py +0 -206
  245. package/src/behavioral/outcome_inference.py +0 -194
  246. package/src/behavioral/outcome_tracker.py +0 -193
  247. package/src/behavioral/tests/__init__.py +0 -4
  248. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  249. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  250. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  251. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  252. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  253. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  254. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  255. package/src/cache_manager.py +0 -518
  256. package/src/compliance/__init__.py +0 -48
  257. package/src/compliance/abac_engine.py +0 -149
  258. package/src/compliance/abac_middleware.py +0 -116
  259. package/src/compliance/audit_db.py +0 -215
  260. package/src/compliance/audit_logger.py +0 -148
  261. package/src/compliance/retention_manager.py +0 -289
  262. package/src/compliance/retention_scheduler.py +0 -186
  263. package/src/compliance/tests/__init__.py +0 -4
  264. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  265. package/src/compliance/tests/test_abac_engine.py +0 -124
  266. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  267. package/src/compliance/tests/test_audit_db.py +0 -123
  268. package/src/compliance/tests/test_audit_logger.py +0 -98
  269. package/src/compliance/tests/test_mcp_audit.py +0 -128
  270. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  271. package/src/compliance/tests/test_retention_manager.py +0 -131
  272. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  273. package/src/compression/__init__.py +0 -25
  274. package/src/compression/cli.py +0 -150
  275. package/src/compression/cold_storage.py +0 -217
  276. package/src/compression/config.py +0 -72
  277. package/src/compression/orchestrator.py +0 -133
  278. package/src/compression/tier2_compressor.py +0 -228
  279. package/src/compression/tier3_compressor.py +0 -153
  280. package/src/compression/tier_classifier.py +0 -148
  281. package/src/db_connection_manager.py +0 -536
  282. package/src/embedding_engine.py +0 -63
  283. package/src/embeddings/__init__.py +0 -47
  284. package/src/embeddings/cache.py +0 -70
  285. package/src/embeddings/cli.py +0 -113
  286. package/src/embeddings/constants.py +0 -47
  287. package/src/embeddings/database.py +0 -91
  288. package/src/embeddings/engine.py +0 -247
  289. package/src/embeddings/model_loader.py +0 -145
  290. package/src/event_bus.py +0 -562
  291. package/src/graph/__init__.py +0 -36
  292. package/src/graph/build_helpers.py +0 -74
  293. package/src/graph/cli.py +0 -87
  294. package/src/graph/cluster_builder.py +0 -188
  295. package/src/graph/cluster_summary.py +0 -148
  296. package/src/graph/constants.py +0 -47
  297. package/src/graph/edge_builder.py +0 -162
  298. package/src/graph/entity_extractor.py +0 -95
  299. package/src/graph/graph_core.py +0 -226
  300. package/src/graph/graph_search.py +0 -231
  301. package/src/graph/hierarchical.py +0 -207
  302. package/src/graph/schema.py +0 -99
  303. package/src/graph_engine.py +0 -52
  304. package/src/hnsw_index.py +0 -628
  305. package/src/hybrid_search.py +0 -46
  306. package/src/learning/__init__.py +0 -217
  307. package/src/learning/adaptive_ranker.py +0 -682
  308. package/src/learning/bootstrap/__init__.py +0 -69
  309. package/src/learning/bootstrap/constants.py +0 -93
  310. package/src/learning/bootstrap/db_queries.py +0 -316
  311. package/src/learning/bootstrap/sampling.py +0 -82
  312. package/src/learning/bootstrap/text_utils.py +0 -71
  313. package/src/learning/cross_project_aggregator.py +0 -857
  314. package/src/learning/db/__init__.py +0 -40
  315. package/src/learning/db/constants.py +0 -44
  316. package/src/learning/db/schema.py +0 -279
  317. package/src/learning/engagement_tracker.py +0 -628
  318. package/src/learning/feature_extractor.py +0 -708
  319. package/src/learning/feedback_collector.py +0 -806
  320. package/src/learning/learning_db.py +0 -915
  321. package/src/learning/project_context_manager.py +0 -572
  322. package/src/learning/ranking/__init__.py +0 -33
  323. package/src/learning/ranking/constants.py +0 -84
  324. package/src/learning/ranking/helpers.py +0 -278
  325. package/src/learning/source_quality_scorer.py +0 -676
  326. package/src/learning/synthetic_bootstrap.py +0 -755
  327. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  328. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  329. package/src/learning/tests/test_aggregator.py +0 -306
  330. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  331. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  332. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  333. package/src/learning/tests/test_feedback_collector.py +0 -294
  334. package/src/learning/tests/test_learning_db.py +0 -602
  335. package/src/learning/tests/test_learning_db_v28.py +0 -110
  336. package/src/learning/tests/test_learning_init_v28.py +0 -48
  337. package/src/learning/tests/test_outcome_signals.py +0 -48
  338. package/src/learning/tests/test_project_context.py +0 -292
  339. package/src/learning/tests/test_schema_migration.py +0 -319
  340. package/src/learning/tests/test_signal_inference.py +0 -397
  341. package/src/learning/tests/test_source_quality.py +0 -351
  342. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  343. package/src/learning/tests/test_workflow_miner.py +0 -318
  344. package/src/learning/workflow_pattern_miner.py +0 -655
  345. package/src/lifecycle/__init__.py +0 -54
  346. package/src/lifecycle/bounded_growth.py +0 -239
  347. package/src/lifecycle/compaction_engine.py +0 -226
  348. package/src/lifecycle/lifecycle_engine.py +0 -355
  349. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  350. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  351. package/src/lifecycle/retention_policy.py +0 -285
  352. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  353. package/src/lifecycle/tests/test_compaction.py +0 -179
  354. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  355. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  356. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  357. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  358. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  359. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  360. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  361. package/src/mcp_tools_v28.py +0 -281
  362. package/src/memory/__init__.py +0 -36
  363. package/src/memory/cli.py +0 -205
  364. package/src/memory/constants.py +0 -39
  365. package/src/memory/helpers.py +0 -28
  366. package/src/memory/schema.py +0 -166
  367. package/src/memory-profiles.py +0 -595
  368. package/src/memory-reset.py +0 -491
  369. package/src/memory_compression.py +0 -989
  370. package/src/memory_store_v2.py +0 -1155
  371. package/src/migrate_v1_to_v2.py +0 -629
  372. package/src/pattern_learner.py +0 -34
  373. package/src/patterns/__init__.py +0 -24
  374. package/src/patterns/analyzers.py +0 -251
  375. package/src/patterns/learner.py +0 -271
  376. package/src/patterns/scoring.py +0 -171
  377. package/src/patterns/store.py +0 -225
  378. package/src/patterns/terminology.py +0 -140
  379. package/src/provenance_tracker.py +0 -312
  380. package/src/qualixar_attribution.py +0 -139
  381. package/src/qualixar_watermark.py +0 -78
  382. package/src/query_optimizer.py +0 -511
  383. package/src/rate_limiter.py +0 -83
  384. package/src/search/__init__.py +0 -20
  385. package/src/search/cli.py +0 -77
  386. package/src/search/constants.py +0 -26
  387. package/src/search/engine.py +0 -241
  388. package/src/search/fusion.py +0 -122
  389. package/src/search/index_loader.py +0 -114
  390. package/src/search/methods.py +0 -162
  391. package/src/search_engine_v2.py +0 -401
  392. package/src/setup_validator.py +0 -482
  393. package/src/subscription_manager.py +0 -391
  394. package/src/tree/__init__.py +0 -59
  395. package/src/tree/builder.py +0 -185
  396. package/src/tree/nodes.py +0 -202
  397. package/src/tree/queries.py +0 -257
  398. package/src/tree/schema.py +0 -80
  399. package/src/tree_manager.py +0 -19
  400. package/src/trust/__init__.py +0 -45
  401. package/src/trust/constants.py +0 -66
  402. package/src/trust/queries.py +0 -157
  403. package/src/trust/schema.py +0 -95
  404. package/src/trust/scorer.py +0 -299
  405. package/src/trust/signals.py +0 -95
  406. package/src/trust_scorer.py +0 -44
  407. package/ui/app.js +0 -1588
  408. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  409. package/ui/js/graph-cytoscape.js +0 -1168
  410. package/ui/js/graph-d3-backup.js +0 -32
  411. package/ui/js/graph.js +0 -32
  412. package/ui_server.py +0 -266
  413. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  414. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  415. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  416. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  417. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  418. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  419. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  420. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  421. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  422. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  423. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  424. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  425. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  426. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  427. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  428. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  429. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  430. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  431. /package/{completions → ide/completions}/slm.bash +0 -0
  432. /package/{completions → ide/completions}/slm.zsh +0 -0
  433. /package/{configs → ide/configs}/cody-commands.json +0 -0
  434. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
@@ -0,0 +1,365 @@
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
+ """V3 API endpoints for the SuperLocalMemory dashboard."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ from pathlib import Path
12
+ from fastapi import APIRouter, Request
13
+ from fastapi.responses import JSONResponse
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ router = APIRouter(prefix="/api/v3", tags=["v3"])
18
+
19
+
20
+ # ── Dashboard ────────────────────────────────────────────────
21
+
22
+ @router.get("/dashboard")
23
+ async def dashboard(request: Request):
24
+ """Dashboard summary: mode, memory count, health score, recent activity."""
25
+ try:
26
+ from superlocalmemory.core.config import SLMConfig
27
+ config = SLMConfig.load()
28
+
29
+ # Get basic stats from engine if available
30
+ engine = getattr(request.app.state, "engine", None)
31
+ memory_count = 0
32
+ fact_count = 0
33
+ if engine and engine._db:
34
+ try:
35
+ rows = engine._db.execute("SELECT COUNT(*) FROM atomic_facts")
36
+ if rows:
37
+ fact_count = rows[0][0] if isinstance(rows[0], (list, tuple)) else dict(rows[0]).get("COUNT(*)", 0)
38
+ except Exception:
39
+ pass
40
+ try:
41
+ rows = engine._db.execute("SELECT COUNT(*) FROM memories")
42
+ if rows:
43
+ memory_count = rows[0][0] if isinstance(rows[0], (list, tuple)) else dict(rows[0]).get("COUNT(*)", 0)
44
+ except Exception:
45
+ pass
46
+
47
+ return {
48
+ "mode": config.mode.value,
49
+ "mode_name": {"a": "Local Guardian", "b": "Smart Local", "c": "Full Power"}.get(config.mode.value, "Unknown"),
50
+ "provider": config.llm.provider or "none",
51
+ "model": config.llm.model or "",
52
+ "memory_count": memory_count,
53
+ "fact_count": fact_count,
54
+ "profile": config.active_profile,
55
+ "base_dir": str(config.base_dir),
56
+ "version": "3.0.0",
57
+ }
58
+ except Exception as e:
59
+ return JSONResponse({"error": str(e)}, status_code=500)
60
+
61
+
62
+ # ── Mode ─────────────────────────────────────────────────────
63
+
64
+ @router.get("/mode")
65
+ async def get_mode():
66
+ """Get current operating mode."""
67
+ try:
68
+ from superlocalmemory.core.config import SLMConfig
69
+ config = SLMConfig.load()
70
+ modes = {
71
+ "a": {"name": "Local Guardian", "description": "Zero cloud. Your data never leaves your machine.", "llm": False, "eu_compliant": True},
72
+ "b": {"name": "Smart Local", "description": "Local LLM via Ollama. Still fully private.", "llm": "local", "eu_compliant": True},
73
+ "c": {"name": "Full Power", "description": "Cloud LLM for maximum accuracy.", "llm": "cloud", "eu_compliant": False},
74
+ }
75
+ current = config.mode.value
76
+ return {"current": current, "details": modes.get(current, {}), "all_modes": modes}
77
+ except Exception as e:
78
+ return JSONResponse({"error": str(e)}, status_code=500)
79
+
80
+
81
+ @router.put("/mode")
82
+ async def set_mode(request: Request):
83
+ """Switch operating mode. Body: {"mode": "a"|"b"|"c"}"""
84
+ try:
85
+ body = await request.json()
86
+ new_mode = body.get("mode", "").lower()
87
+ if new_mode not in ("a", "b", "c"):
88
+ return JSONResponse({"error": "Invalid mode. Use a, b, or c."}, status_code=400)
89
+
90
+ from superlocalmemory.core.config import SLMConfig
91
+ from superlocalmemory.storage.models import Mode
92
+ old_config = SLMConfig.load()
93
+ new_config = SLMConfig.for_mode(
94
+ Mode(new_mode),
95
+ llm_provider=old_config.llm.provider,
96
+ llm_model=old_config.llm.model,
97
+ llm_api_key=old_config.llm.api_key,
98
+ llm_api_base=old_config.llm.api_base,
99
+ )
100
+ new_config.active_profile = old_config.active_profile
101
+ new_config.save()
102
+
103
+ # Reset engine to pick up new config
104
+ if hasattr(request.app.state, "engine"):
105
+ request.app.state.engine = None
106
+
107
+ return {"success": True, "mode": new_mode}
108
+ except Exception as e:
109
+ return JSONResponse({"error": str(e)}, status_code=500)
110
+
111
+
112
+ # ── Provider ─────────────────────────────────────────────────
113
+
114
+ @router.get("/providers")
115
+ async def list_providers():
116
+ """List available LLM providers with presets."""
117
+ try:
118
+ from superlocalmemory.core.config import SLMConfig
119
+ return {"providers": SLMConfig.provider_presets()}
120
+ except Exception as exc:
121
+ return {"error": str(exc), "providers": []}
122
+
123
+
124
+ @router.get("/provider")
125
+ async def get_provider():
126
+ """Get current provider configuration (API key masked)."""
127
+ try:
128
+ from superlocalmemory.core.config import SLMConfig
129
+ config = SLMConfig.load()
130
+ key = config.llm.api_key
131
+ masked = f"****{key[-4:]}" if len(key) > 8 else "****" if key else ""
132
+ return {
133
+ "provider": config.llm.provider or "none",
134
+ "model": config.llm.model,
135
+ "base_url": config.llm.api_base,
136
+ "api_key_masked": masked,
137
+ "has_key": bool(key),
138
+ }
139
+ except Exception as exc:
140
+ return {"error": str(exc), "provider": "unknown"}
141
+
142
+
143
+ @router.put("/provider")
144
+ async def set_provider(request: Request):
145
+ """Set LLM provider. Body: {"provider": "openai", "api_key": "...", "model": "..."}"""
146
+ try:
147
+ body = await request.json()
148
+ provider = body.get("provider", "")
149
+ api_key = body.get("api_key", "")
150
+ model = body.get("model", "")
151
+ base_url = body.get("base_url", "")
152
+
153
+ from superlocalmemory.core.config import SLMConfig
154
+ from superlocalmemory.storage.models import Mode
155
+ config = SLMConfig.load()
156
+
157
+ # Use preset base_url if not provided
158
+ if not base_url:
159
+ presets = SLMConfig.provider_presets()
160
+ preset = presets.get(provider, {})
161
+ base_url = preset.get("base_url", "")
162
+ if not model:
163
+ model = preset.get("model", "")
164
+
165
+ new_config = SLMConfig.for_mode(
166
+ config.mode,
167
+ llm_provider=provider,
168
+ llm_model=model,
169
+ llm_api_key=api_key,
170
+ llm_api_base=base_url,
171
+ )
172
+ new_config.active_profile = config.active_profile
173
+ new_config.save()
174
+
175
+ return {"success": True, "provider": provider, "model": model}
176
+ except Exception as e:
177
+ return JSONResponse({"error": str(e)}, status_code=500)
178
+
179
+
180
+ # ── Recall Trace ─────────────────────────────────────────────
181
+
182
+ @router.post("/recall/trace")
183
+ async def recall_trace(request: Request):
184
+ """Recall with per-channel score breakdown."""
185
+ try:
186
+ body = await request.json()
187
+ query = body.get("query", "")
188
+ limit = body.get("limit", 10)
189
+
190
+ engine = getattr(request.app.state, "engine", None)
191
+ if not engine:
192
+ return JSONResponse({"error": "Engine not initialized"}, status_code=503)
193
+
194
+ response = engine.recall(query, limit=limit)
195
+ results = []
196
+ for r in response.results[:limit]:
197
+ results.append({
198
+ "fact_id": r.fact.fact_id,
199
+ "content": r.fact.content[:300],
200
+ "score": round(r.score, 4),
201
+ "confidence": round(r.confidence, 4),
202
+ "trust_score": round(r.trust_score, 4),
203
+ "channel_scores": {k: round(v, 4) for k, v in (r.channel_scores or {}).items()},
204
+ })
205
+
206
+ return {
207
+ "query": query,
208
+ "query_type": response.query_type,
209
+ "result_count": len(results),
210
+ "retrieval_time_ms": round(response.retrieval_time_ms, 1),
211
+ "results": results,
212
+ }
213
+ except Exception as e:
214
+ return JSONResponse({"error": str(e)}, status_code=500)
215
+
216
+
217
+ # ── Trust Dashboard ──────────────────────────────────────────
218
+
219
+ @router.get("/trust/dashboard")
220
+ async def trust_dashboard(request: Request):
221
+ """Trust overview: per-agent scores, alerts."""
222
+ try:
223
+ engine = getattr(request.app.state, "engine", None)
224
+ if not engine or not engine._trust_scorer:
225
+ return {"agents": [], "alerts": [], "message": "Trust scorer not available"}
226
+
227
+ from superlocalmemory.core.config import SLMConfig
228
+ config = SLMConfig.load()
229
+ scores = engine._trust_scorer.get_all_scores(config.active_profile)
230
+
231
+ agents = []
232
+ for s in scores:
233
+ if isinstance(s, dict):
234
+ agents.append(s)
235
+ else:
236
+ agents.append({
237
+ "target_id": s.target_id,
238
+ "target_type": s.target_type,
239
+ "trust_score": round(s.trust_score, 3),
240
+ "evidence_count": s.evidence_count,
241
+ })
242
+
243
+ return {"agents": agents, "alerts": [], "profile": config.active_profile}
244
+ except Exception as e:
245
+ return JSONResponse({"error": str(e)}, status_code=500)
246
+
247
+
248
+ # ── Math Health ──────────────────────────────────────────────
249
+
250
+ @router.get("/math/health")
251
+ async def math_health(request: Request):
252
+ """Mathematical layer health: Fisher, sheaf, Langevin status."""
253
+ try:
254
+ engine = getattr(request.app.state, "engine", None)
255
+
256
+ health = {
257
+ "fisher": {"status": "active", "description": "Fisher-Rao information geometry for similarity"},
258
+ "sheaf": {"status": "active", "description": "Sheaf cohomology for consistency detection"},
259
+ "langevin": {"status": "active", "description": "Riemannian Langevin dynamics for lifecycle"},
260
+ }
261
+
262
+ # Check if math layers are configured
263
+ if engine:
264
+ from superlocalmemory.core.config import SLMConfig
265
+ config = SLMConfig.load()
266
+ health["fisher"]["mode"] = config.math.fisher_mode
267
+ health["sheaf"]["threshold"] = config.math.sheaf_contradiction_threshold
268
+ health["langevin"]["temperature"] = config.math.langevin_temperature
269
+
270
+ return {"health": health, "overall": "healthy"}
271
+ except Exception as e:
272
+ return JSONResponse({"error": str(e)}, status_code=500)
273
+
274
+
275
+ # ── Auto-Capture / Auto-Recall Config ────────────────────────
276
+
277
+ @router.get("/auto-capture/config")
278
+ async def get_auto_capture_config():
279
+ """Get auto-capture configuration."""
280
+ try:
281
+ from superlocalmemory.hooks.rules_engine import RulesEngine
282
+ from superlocalmemory.core.config import DEFAULT_BASE_DIR
283
+ rules = RulesEngine(config_path=DEFAULT_BASE_DIR / "config.json")
284
+ return {"config": rules.get_capture_config()}
285
+ except Exception as exc:
286
+ return {"error": str(exc), "config": {}}
287
+
288
+
289
+ @router.put("/auto-capture/config")
290
+ async def set_auto_capture_config(request: Request):
291
+ """Update auto-capture config. Body: {"enabled": true, "capture_decisions": true, ...}"""
292
+ try:
293
+ body = await request.json()
294
+ from superlocalmemory.hooks.rules_engine import RulesEngine
295
+ from superlocalmemory.core.config import DEFAULT_BASE_DIR
296
+ config_path = DEFAULT_BASE_DIR / "config.json"
297
+ rules = RulesEngine(config_path=config_path)
298
+ for key, value in body.items():
299
+ rules.update_rule("auto_capture", key, value)
300
+ rules.save(config_path)
301
+ return {"success": True, "config": rules.get_capture_config()}
302
+ except Exception as e:
303
+ return JSONResponse({"error": str(e)}, status_code=500)
304
+
305
+
306
+ @router.get("/auto-recall/config")
307
+ async def get_auto_recall_config():
308
+ """Get auto-recall configuration."""
309
+ try:
310
+ from superlocalmemory.hooks.rules_engine import RulesEngine
311
+ from superlocalmemory.core.config import DEFAULT_BASE_DIR
312
+ rules = RulesEngine(config_path=DEFAULT_BASE_DIR / "config.json")
313
+ return {"config": rules.get_recall_config()}
314
+ except Exception as exc:
315
+ return {"error": str(exc), "config": {}}
316
+
317
+
318
+ @router.put("/auto-recall/config")
319
+ async def set_auto_recall_config(request: Request):
320
+ """Update auto-recall config."""
321
+ try:
322
+ body = await request.json()
323
+ from superlocalmemory.hooks.rules_engine import RulesEngine
324
+ from superlocalmemory.core.config import DEFAULT_BASE_DIR
325
+ config_path = DEFAULT_BASE_DIR / "config.json"
326
+ rules = RulesEngine(config_path=config_path)
327
+ for key, value in body.items():
328
+ rules.update_rule("auto_recall", key, value)
329
+ rules.save(config_path)
330
+ return {"success": True, "config": rules.get_recall_config()}
331
+ except Exception as e:
332
+ return JSONResponse({"error": str(e)}, status_code=500)
333
+
334
+
335
+ # ── IDE Status ───────────────────────────────────────────────
336
+
337
+ @router.get("/ide/status")
338
+ async def ide_status():
339
+ """Get IDE connection status."""
340
+ try:
341
+ from superlocalmemory.hooks.ide_connector import IDEConnector
342
+ connector = IDEConnector()
343
+ return {"ides": connector.get_status()}
344
+ except Exception as exc:
345
+ return {"error": str(exc), "ides": []}
346
+
347
+
348
+ @router.post("/ide/connect")
349
+ async def ide_connect(request: Request):
350
+ """Connect an IDE. Body: {"ide": "cursor"} or {} for all."""
351
+ try:
352
+ body = await request.json()
353
+ ide = body.get("ide", "")
354
+
355
+ from superlocalmemory.hooks.ide_connector import IDEConnector
356
+ connector = IDEConnector()
357
+
358
+ if ide:
359
+ success = connector.connect(ide)
360
+ return {"success": success, "ide": ide}
361
+ else:
362
+ results = connector.connect_all()
363
+ return {"results": results}
364
+ except Exception as e:
365
+ return JSONResponse({"error": str(e)}, status_code=500)
@@ -0,0 +1,82 @@
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
+ """SuperLocalMemory V3 - WebSocket Routes
5
+ - MIT License
6
+
7
+ Routes: /ws/updates
8
+ """
9
+ from typing import Set
10
+ from datetime import datetime
11
+
12
+ from fastapi import APIRouter, WebSocket, WebSocketDisconnect
13
+
14
+ router = APIRouter()
15
+
16
+
17
+ class ConnectionManager:
18
+ """Manages WebSocket connections for real-time updates."""
19
+
20
+ def __init__(self):
21
+ self.active_connections: Set[WebSocket] = set()
22
+
23
+ async def connect(self, websocket: WebSocket):
24
+ await websocket.accept()
25
+ self.active_connections.add(websocket)
26
+
27
+ def disconnect(self, websocket: WebSocket):
28
+ self.active_connections.discard(websocket)
29
+
30
+ async def broadcast(self, message: dict):
31
+ disconnected = set()
32
+ for connection in self.active_connections:
33
+ try:
34
+ await connection.send_json(message)
35
+ except Exception:
36
+ disconnected.add(connection)
37
+ self.active_connections -= disconnected
38
+
39
+
40
+ manager = ConnectionManager()
41
+
42
+
43
+ @router.websocket("/ws/updates")
44
+ async def websocket_updates(websocket: WebSocket):
45
+ """WebSocket endpoint for real-time memory updates."""
46
+ await manager.connect(websocket)
47
+
48
+ try:
49
+ await websocket.send_json({
50
+ "type": "connected",
51
+ "message": "WebSocket connection established",
52
+ "timestamp": datetime.now().isoformat(),
53
+ })
54
+
55
+ while True:
56
+ try:
57
+ data = await websocket.receive_json()
58
+
59
+ if data.get('type') == 'ping':
60
+ await websocket.send_json({
61
+ "type": "pong",
62
+ "timestamp": datetime.now().isoformat(),
63
+ })
64
+
65
+ elif data.get('type') == 'get_stats':
66
+ await websocket.send_json({
67
+ "type": "stats_update",
68
+ "message": "Use /api/stats endpoint for stats",
69
+ "timestamp": datetime.now().isoformat(),
70
+ })
71
+
72
+ except WebSocketDisconnect:
73
+ break
74
+ except Exception as e:
75
+ await websocket.send_json({
76
+ "type": "error",
77
+ "message": str(e),
78
+ "timestamp": datetime.now().isoformat(),
79
+ })
80
+
81
+ finally:
82
+ manager.disconnect(websocket)
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: MIT
3
+ # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
+ """Security headers middleware for FastAPI servers.
5
+
6
+ Adds comprehensive security headers to all HTTP responses:
7
+ - X-Content-Type-Options: Prevents MIME type sniffing
8
+ - X-Frame-Options: Prevents clickjacking attacks
9
+ - X-XSS-Protection: Enables browser XSS filters
10
+ - Content-Security-Policy: Restricts resource loading
11
+ - Referrer-Policy: Controls referrer information leakage
12
+ """
13
+
14
+ from starlette.middleware.base import BaseHTTPMiddleware
15
+ from starlette.requests import Request
16
+ from starlette.responses import Response
17
+
18
+
19
+ class SecurityHeadersMiddleware(BaseHTTPMiddleware):
20
+ """Add security headers to all HTTP responses."""
21
+
22
+ async def dispatch(self, request: Request, call_next) -> Response:
23
+ """Process request and add security headers to response."""
24
+ response = await call_next(request)
25
+
26
+ # Prevent MIME type sniffing
27
+ response.headers["X-Content-Type-Options"] = "nosniff"
28
+
29
+ # Prevent clickjacking attacks
30
+ response.headers["X-Frame-Options"] = "DENY"
31
+
32
+ # Enable browser XSS filter (legacy, but doesn't hurt)
33
+ response.headers["X-XSS-Protection"] = "1; mode=block"
34
+
35
+ # Content Security Policy
36
+ # Note: 'unsafe-inline' is needed for Bootstrap and inline scripts
37
+ # For production, consider moving inline scripts to separate files
38
+ csp_directives = [
39
+ "default-src 'self'",
40
+ "script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://unpkg.com https://d3js.org",
41
+ "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://unpkg.com",
42
+ "font-src 'self' https://cdn.jsdelivr.net",
43
+ "img-src 'self' data: https:",
44
+ "connect-src 'self' ws://localhost:* ws://127.0.0.1:*",
45
+ "frame-ancestors 'none'",
46
+ ]
47
+ response.headers["Content-Security-Policy"] = "; ".join(csp_directives)
48
+
49
+ # Control referrer information leakage
50
+ response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
51
+
52
+ # Prevent caching of sensitive data (for API endpoints)
53
+ if request.url.path.startswith("/api/"):
54
+ response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate"
55
+ response.headers["Pragma"] = "no-cache"
56
+
57
+ return response