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,317 @@
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
+ """V2 to V3 database migration.
6
+
7
+ Detects V2 installations, backs up data, extends schema with V3 tables,
8
+ and creates backward-compatible symlinks.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+ import shutil
15
+ import sqlite3
16
+ from datetime import datetime, UTC
17
+ from pathlib import Path
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ V2_BASE = Path.home() / ".claude-memory"
22
+ V3_BASE = Path.home() / ".superlocalmemory"
23
+ V2_DB_NAME = "memory.db"
24
+ BACKUP_NAME = "memory-v2-backup.db"
25
+
26
+ # V3 tables to add during migration
27
+ V3_TABLES_SQL = [
28
+ """CREATE TABLE IF NOT EXISTS semantic_facts (
29
+ fact_id TEXT PRIMARY KEY,
30
+ memory_id TEXT,
31
+ profile_id TEXT NOT NULL DEFAULT 'default',
32
+ content TEXT NOT NULL,
33
+ fact_type TEXT DEFAULT 'world',
34
+ confidence REAL DEFAULT 0.7,
35
+ speaker TEXT DEFAULT '',
36
+ embedding BLOB,
37
+ fisher_mean BLOB,
38
+ fisher_variance BLOB,
39
+ access_count INTEGER DEFAULT 0,
40
+ observation_date TEXT,
41
+ referenced_date TEXT,
42
+ interval_start TEXT,
43
+ interval_end TEXT,
44
+ canonical_entities TEXT DEFAULT '[]',
45
+ created_at TEXT,
46
+ updated_at TEXT
47
+ )""",
48
+ """CREATE TABLE IF NOT EXISTS kg_nodes (
49
+ node_id TEXT PRIMARY KEY,
50
+ profile_id TEXT NOT NULL DEFAULT 'default',
51
+ entity_name TEXT NOT NULL,
52
+ entity_type TEXT DEFAULT 'unknown',
53
+ aliases TEXT DEFAULT '[]',
54
+ fact_count INTEGER DEFAULT 0,
55
+ created_at TEXT
56
+ )""",
57
+ """CREATE TABLE IF NOT EXISTS memory_edges (
58
+ edge_id TEXT PRIMARY KEY,
59
+ profile_id TEXT NOT NULL DEFAULT 'default',
60
+ source_id TEXT NOT NULL,
61
+ target_id TEXT NOT NULL,
62
+ edge_type TEXT DEFAULT 'semantic',
63
+ weight REAL DEFAULT 1.0,
64
+ created_at TEXT
65
+ )""",
66
+ """CREATE TABLE IF NOT EXISTS memory_scenes (
67
+ scene_id TEXT PRIMARY KEY,
68
+ profile_id TEXT NOT NULL DEFAULT 'default',
69
+ label TEXT DEFAULT '',
70
+ fact_ids TEXT DEFAULT '[]',
71
+ created_at TEXT
72
+ )""",
73
+ """CREATE TABLE IF NOT EXISTS bm25_tokens (
74
+ fact_id TEXT NOT NULL,
75
+ profile_id TEXT NOT NULL DEFAULT 'default',
76
+ tokens TEXT NOT NULL,
77
+ doc_length INTEGER DEFAULT 0,
78
+ PRIMARY KEY (fact_id, profile_id)
79
+ )""",
80
+ """CREATE TABLE IF NOT EXISTS temporal_events (
81
+ event_id TEXT PRIMARY KEY,
82
+ profile_id TEXT NOT NULL DEFAULT 'default',
83
+ entity_id TEXT,
84
+ fact_id TEXT,
85
+ observation_date TEXT,
86
+ referenced_date TEXT,
87
+ interval_start TEXT,
88
+ interval_end TEXT,
89
+ description TEXT DEFAULT ''
90
+ )""",
91
+ """CREATE TABLE IF NOT EXISTS memory_observations (
92
+ obs_id TEXT PRIMARY KEY,
93
+ profile_id TEXT NOT NULL DEFAULT 'default',
94
+ entity_id TEXT NOT NULL,
95
+ observation TEXT NOT NULL,
96
+ source_fact_id TEXT,
97
+ created_at TEXT
98
+ )""",
99
+ """CREATE TABLE IF NOT EXISTS contradictions (
100
+ contradiction_id TEXT PRIMARY KEY,
101
+ profile_id TEXT NOT NULL DEFAULT 'default',
102
+ fact_id_a TEXT NOT NULL,
103
+ fact_id_b TEXT NOT NULL,
104
+ severity REAL DEFAULT 0.5,
105
+ resolved INTEGER DEFAULT 0,
106
+ created_at TEXT
107
+ )""",
108
+ """CREATE TABLE IF NOT EXISTS langevin_state (
109
+ fact_id TEXT PRIMARY KEY,
110
+ profile_id TEXT NOT NULL DEFAULT 'default',
111
+ position REAL DEFAULT 0.5,
112
+ velocity REAL DEFAULT 0.0,
113
+ updated_at TEXT
114
+ )""",
115
+ """CREATE TABLE IF NOT EXISTS sheaf_sections (
116
+ section_id TEXT PRIMARY KEY,
117
+ profile_id TEXT NOT NULL DEFAULT 'default',
118
+ fact_id TEXT NOT NULL,
119
+ section_data BLOB,
120
+ created_at TEXT
121
+ )""",
122
+ """CREATE TABLE IF NOT EXISTS v3_config (
123
+ key TEXT PRIMARY KEY,
124
+ value TEXT NOT NULL,
125
+ updated_at TEXT
126
+ )""",
127
+ ]
128
+
129
+ # Indexes for V3 tables
130
+ V3_INDEXES_SQL = [
131
+ "CREATE INDEX IF NOT EXISTS idx_facts_profile ON semantic_facts(profile_id)",
132
+ "CREATE INDEX IF NOT EXISTS idx_facts_memory ON semantic_facts(memory_id)",
133
+ "CREATE INDEX IF NOT EXISTS idx_nodes_profile ON kg_nodes(profile_id)",
134
+ "CREATE INDEX IF NOT EXISTS idx_edges_source ON memory_edges(source_id)",
135
+ "CREATE INDEX IF NOT EXISTS idx_edges_target ON memory_edges(target_id)",
136
+ "CREATE INDEX IF NOT EXISTS idx_scenes_profile ON memory_scenes(profile_id)",
137
+ "CREATE INDEX IF NOT EXISTS idx_temporal_entity ON temporal_events(entity_id)",
138
+ "CREATE INDEX IF NOT EXISTS idx_observations_entity ON memory_observations(entity_id)",
139
+ ]
140
+
141
+
142
+ class V2Migrator:
143
+ """Migrate V2 database to V3 schema."""
144
+
145
+ def __init__(self, home: Path | None = None):
146
+ self._home = home or Path.home()
147
+ self._v2_base = self._home / ".claude-memory"
148
+ self._v3_base = self._home / ".superlocalmemory"
149
+ self._v2_db = self._v2_base / V2_DB_NAME
150
+ self._v3_db = self._v3_base / V2_DB_NAME
151
+ self._backup_db = self._v3_base / BACKUP_NAME
152
+
153
+ def detect_v2(self) -> bool:
154
+ """Check if a V2 installation exists."""
155
+ return self._v2_db.exists() and self._v2_db.is_file()
156
+
157
+ def is_already_migrated(self) -> bool:
158
+ """Check if migration has already been performed."""
159
+ if not self._v3_db.exists():
160
+ return False
161
+ try:
162
+ conn = sqlite3.connect(str(self._v3_db))
163
+ try:
164
+ tables = [r[0] for r in conn.execute(
165
+ "SELECT name FROM sqlite_master WHERE type='table'"
166
+ ).fetchall()]
167
+ return "semantic_facts" in tables and "v3_config" in tables
168
+ finally:
169
+ conn.close()
170
+ except Exception:
171
+ return False
172
+
173
+ def get_v2_stats(self) -> dict:
174
+ """Get statistics about the V2 database."""
175
+ if not self.detect_v2():
176
+ return {"exists": False}
177
+ conn = None
178
+ try:
179
+ conn = sqlite3.connect(str(self._v2_db))
180
+ memory_count = conn.execute("SELECT COUNT(*) FROM memories").fetchone()[0]
181
+ tables = [r[0] for r in conn.execute(
182
+ "SELECT name FROM sqlite_master WHERE type='table'"
183
+ ).fetchall()]
184
+ # Check for profiles
185
+ profile_count = 1
186
+ try:
187
+ profiles = conn.execute(
188
+ "SELECT DISTINCT profile FROM memories WHERE profile IS NOT NULL"
189
+ ).fetchall()
190
+ profile_count = max(len(profiles), 1)
191
+ except Exception:
192
+ pass
193
+ return {
194
+ "exists": True,
195
+ "memory_count": memory_count,
196
+ "profile_count": profile_count,
197
+ "table_count": len(tables),
198
+ "db_path": str(self._v2_db),
199
+ "db_size_mb": round(self._v2_db.stat().st_size / 1024 / 1024, 2),
200
+ }
201
+ except Exception as exc:
202
+ return {"exists": True, "error": str(exc)}
203
+ finally:
204
+ if conn is not None:
205
+ conn.close()
206
+
207
+ def migrate(self) -> dict:
208
+ """Run the full V2 to V3 migration.
209
+
210
+ Steps:
211
+ 1. Create V3 directory
212
+ 2. Backup V2 database
213
+ 3. Copy database to V3 location
214
+ 4. Extend schema with V3 tables
215
+ 5. Create symlink for backward compat
216
+ 6. Mark migration complete
217
+
218
+ Returns dict with migration stats.
219
+ """
220
+ if not self.detect_v2():
221
+ return {"success": False, "error": "No V2 installation found"}
222
+
223
+ if self.is_already_migrated():
224
+ return {"success": True, "message": "Already migrated"}
225
+
226
+ stats = {"steps": []}
227
+
228
+ try:
229
+ # Step 1: Create V3 directory
230
+ self._v3_base.mkdir(parents=True, exist_ok=True)
231
+ (self._v3_base / "embeddings").mkdir(exist_ok=True)
232
+ (self._v3_base / "models").mkdir(exist_ok=True)
233
+ stats["steps"].append("Created V3 directory")
234
+
235
+ # Step 2: Backup
236
+ shutil.copy2(str(self._v2_db), str(self._backup_db))
237
+ stats["steps"].append(f"Backed up to {self._backup_db}")
238
+
239
+ # Step 3: Copy to V3 location
240
+ shutil.copy2(str(self._v2_db), str(self._v3_db))
241
+ stats["steps"].append("Copied database to V3 location")
242
+
243
+ # Step 4: Extend schema
244
+ conn = sqlite3.connect(str(self._v3_db))
245
+ for sql in V3_TABLES_SQL:
246
+ conn.execute(sql)
247
+ for sql in V3_INDEXES_SQL:
248
+ conn.execute(sql)
249
+ # Mark migration
250
+ conn.execute(
251
+ "INSERT OR REPLACE INTO v3_config (key, value, updated_at) VALUES (?, ?, ?)",
252
+ ("migration_date", datetime.now(UTC).isoformat(), datetime.now(UTC).isoformat()),
253
+ )
254
+ conn.execute(
255
+ "INSERT OR REPLACE INTO v3_config (key, value, updated_at) VALUES (?, ?, ?)",
256
+ ("migration_version", "3.0.0", datetime.now(UTC).isoformat()),
257
+ )
258
+ conn.commit()
259
+ conn.close()
260
+ stats["steps"].append(f"Extended schema ({len(V3_TABLES_SQL)} tables, {len(V3_INDEXES_SQL)} indexes)")
261
+
262
+ # Step 5: Symlink (only if .claude-memory is not already a symlink)
263
+ if not self._v2_base.is_symlink():
264
+ # Rename original to .claude-memory-v2-original
265
+ original_backup = self._home / ".claude-memory-v2-original"
266
+ if not original_backup.exists():
267
+ self._v2_base.rename(original_backup)
268
+ self._v2_base.symlink_to(self._v3_base)
269
+ stats["steps"].append("Created symlink: .claude-memory -> .superlocalmemory")
270
+ else:
271
+ stats["steps"].append("Symlink skipped (backup dir already exists)")
272
+ else:
273
+ stats["steps"].append("Symlink already exists")
274
+
275
+ stats["success"] = True
276
+ stats["v3_db"] = str(self._v3_db)
277
+ stats["backup_db"] = str(self._backup_db)
278
+
279
+ except Exception as exc:
280
+ stats["success"] = False
281
+ stats["error"] = str(exc)
282
+ logger.error("Migration failed: %s", exc)
283
+
284
+ return stats
285
+
286
+ def rollback(self) -> dict:
287
+ """Rollback migration -- restore V2 state.
288
+
289
+ Returns dict with rollback stats.
290
+ """
291
+ stats = {"steps": []}
292
+
293
+ try:
294
+ # Remove symlink
295
+ if self._v2_base.is_symlink():
296
+ self._v2_base.unlink()
297
+ stats["steps"].append("Removed symlink")
298
+
299
+ # Restore original V2 directory
300
+ original_backup = self._home / ".claude-memory-v2-original"
301
+ if original_backup.exists():
302
+ if not self._v2_base.exists():
303
+ original_backup.rename(self._v2_base)
304
+ stats["steps"].append("Restored original .claude-memory")
305
+ elif self._backup_db.exists():
306
+ # Restore from backup
307
+ self._v2_base.mkdir(parents=True, exist_ok=True)
308
+ shutil.copy2(str(self._backup_db), str(self._v2_db))
309
+ stats["steps"].append("Restored database from backup")
310
+
311
+ stats["success"] = True
312
+
313
+ except Exception as exc:
314
+ stats["success"] = False
315
+ stats["error"] = str(exc)
316
+
317
+ return stats
File without changes
@@ -0,0 +1,130 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """SuperLocalMemory V3 — Trust Gate (Pre-Operation Checks).
6
+
7
+ Enforces minimum trust thresholds before allowing write/delete operations.
8
+ Read operations always pass but are logged for audit purposes.
9
+
10
+ Part of Qualixar | Author: Varun Pratap Bhardwaj
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ from typing import TYPE_CHECKING
17
+
18
+ if TYPE_CHECKING:
19
+ from superlocalmemory.trust.scorer import TrustScorer
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class TrustError(PermissionError):
25
+ """Raised when an agent fails a trust check.
26
+
27
+ Attributes:
28
+ agent_id: The agent that failed the check.
29
+ trust_score: The agent's current trust score.
30
+ threshold: The minimum required trust score.
31
+ operation: The operation that was attempted.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ agent_id: str,
37
+ trust_score: float,
38
+ threshold: float,
39
+ operation: str,
40
+ ) -> None:
41
+ self.agent_id = agent_id
42
+ self.trust_score = trust_score
43
+ self.threshold = threshold
44
+ self.operation = operation
45
+ super().__init__(
46
+ f"Agent '{agent_id}' trust {trust_score:.3f} below "
47
+ f"{operation} threshold {threshold:.3f}"
48
+ )
49
+
50
+
51
+ class TrustGate:
52
+ """Pre-operation trust checks.
53
+
54
+ Operations are gated by minimum trust thresholds:
55
+ - write: agent must have trust >= write_threshold (default 0.3)
56
+ - delete: agent must have trust >= delete_threshold (default 0.5)
57
+ - read: always passes (logged for audit trail)
58
+
59
+ Raises TrustError if the agent's trust is too low.
60
+ """
61
+
62
+ def __init__(
63
+ self,
64
+ scorer: TrustScorer,
65
+ write_threshold: float = 0.3,
66
+ delete_threshold: float = 0.5,
67
+ ) -> None:
68
+ if write_threshold < 0 or write_threshold > 1:
69
+ raise ValueError("write_threshold must be in [0, 1]")
70
+ if delete_threshold < 0 or delete_threshold > 1:
71
+ raise ValueError("delete_threshold must be in [0, 1]")
72
+
73
+ self._scorer = scorer
74
+ self._write_threshold = write_threshold
75
+ self._delete_threshold = delete_threshold
76
+
77
+ @property
78
+ def write_threshold(self) -> float:
79
+ return self._write_threshold
80
+
81
+ @property
82
+ def delete_threshold(self) -> float:
83
+ return self._delete_threshold
84
+
85
+ def check_write(self, agent_id: str, profile_id: str) -> None:
86
+ """Check if agent is trusted enough to write.
87
+
88
+ Raises:
89
+ TrustError: If agent trust is below write_threshold.
90
+ """
91
+ score = self._scorer.get_agent_trust(agent_id, profile_id)
92
+ logger.debug(
93
+ "trust gate write: agent=%s trust=%.3f threshold=%.3f",
94
+ agent_id, score, self._write_threshold,
95
+ )
96
+ if score < self._write_threshold:
97
+ raise TrustError(
98
+ agent_id, score, self._write_threshold, "write"
99
+ )
100
+
101
+ def check_delete(self, agent_id: str, profile_id: str) -> None:
102
+ """Check if agent is trusted enough to delete.
103
+
104
+ Delete requires higher trust than write because it is destructive.
105
+
106
+ Raises:
107
+ TrustError: If agent trust is below delete_threshold.
108
+ """
109
+ score = self._scorer.get_agent_trust(agent_id, profile_id)
110
+ logger.debug(
111
+ "trust gate delete: agent=%s trust=%.3f threshold=%.3f",
112
+ agent_id, score, self._delete_threshold,
113
+ )
114
+ if score < self._delete_threshold:
115
+ raise TrustError(
116
+ agent_id, score, self._delete_threshold, "delete"
117
+ )
118
+
119
+ def check_read(self, agent_id: str, profile_id: str) -> None:
120
+ """Read check — always passes. Logged for audit trail.
121
+
122
+ Reads are never blocked because denying read access could break
123
+ agent functionality. However, logging read access enables
124
+ anomaly detection and compliance auditing.
125
+ """
126
+ score = self._scorer.get_agent_trust(agent_id, profile_id)
127
+ logger.debug(
128
+ "trust gate read (always pass): agent=%s trust=%.3f",
129
+ agent_id, score,
130
+ )
@@ -0,0 +1,124 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """SuperLocalMemory V3 — Provenance Tracking.
6
+
7
+ Records who/what created each memory and how.
8
+ V1 had provenance as WRITE-ONLY (stored but never read).
9
+ Innovation wires reads into trust scoring and compliance audit.
10
+
11
+ Part of Qualixar | Author: Varun Pratap Bhardwaj
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import logging
17
+ from datetime import UTC, datetime
18
+
19
+ from superlocalmemory.storage.models import ProvenanceRecord
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class ProvenanceTracker:
25
+ """Track provenance of all stored facts.
26
+
27
+ Every fact gets a provenance record at creation time.
28
+ Provenance feeds into:
29
+ - Trust scoring (sources with high-quality provenance get trust boost)
30
+ - Compliance audit (GDPR right-to-know: who stored what data?)
31
+ - Debugging (which extraction pipeline created this fact?)
32
+ """
33
+
34
+ def __init__(self, db) -> None:
35
+ self._db = db
36
+
37
+ def record(
38
+ self,
39
+ fact_id: str,
40
+ profile_id: str,
41
+ source_type: str,
42
+ source_id: str = "",
43
+ created_by: str = "",
44
+ ) -> ProvenanceRecord:
45
+ """Record provenance for a newly stored fact.
46
+
47
+ Args:
48
+ fact_id: The fact being tracked.
49
+ profile_id: Active profile.
50
+ source_type: "conversation", "import", "consolidation", "migration".
51
+ source_id: Session ID, import batch ID, etc.
52
+ created_by: Agent ID or user identifier.
53
+ """
54
+ record = ProvenanceRecord(
55
+ profile_id=profile_id,
56
+ fact_id=fact_id,
57
+ source_type=source_type,
58
+ source_id=source_id,
59
+ created_by=created_by,
60
+ timestamp=datetime.now(UTC).isoformat(),
61
+ )
62
+ self._db.execute(
63
+ "INSERT INTO provenance "
64
+ "(provenance_id, profile_id, fact_id, source_type, source_id, "
65
+ "created_by, timestamp) VALUES (?,?,?,?,?,?,?)",
66
+ (record.provenance_id, record.profile_id, record.fact_id,
67
+ record.source_type, record.source_id, record.created_by,
68
+ record.timestamp),
69
+ )
70
+ return record
71
+
72
+ def get_provenance(self, fact_id: str, profile_id: str) -> ProvenanceRecord | None:
73
+ """Get provenance for a specific fact."""
74
+ rows = self._db.execute(
75
+ "SELECT * FROM provenance WHERE fact_id = ? AND profile_id = ?",
76
+ (fact_id, profile_id),
77
+ )
78
+ if not rows:
79
+ return None
80
+ d = dict(rows[0])
81
+ return ProvenanceRecord(
82
+ provenance_id=d["provenance_id"],
83
+ profile_id=d["profile_id"],
84
+ fact_id=d["fact_id"],
85
+ source_type=d["source_type"],
86
+ source_id=d.get("source_id", ""),
87
+ created_by=d.get("created_by", ""),
88
+ timestamp=d["timestamp"],
89
+ )
90
+
91
+ def get_facts_by_source(
92
+ self, source_type: str, profile_id: str, limit: int = 100
93
+ ) -> list[ProvenanceRecord]:
94
+ """Get all facts from a specific source type."""
95
+ rows = self._db.execute(
96
+ "SELECT * FROM provenance WHERE source_type = ? AND profile_id = ? "
97
+ "ORDER BY timestamp DESC LIMIT ?",
98
+ (source_type, profile_id, limit),
99
+ )
100
+ return [self._row_to_record(r) for r in rows]
101
+
102
+ def get_provenance_for_profile(
103
+ self, profile_id: str, limit: int = 100
104
+ ) -> list[ProvenanceRecord]:
105
+ """Get all provenance records for a profile (compliance audit)."""
106
+ rows = self._db.execute(
107
+ "SELECT * FROM provenance WHERE profile_id = ? "
108
+ "ORDER BY timestamp DESC LIMIT ?",
109
+ (profile_id, limit),
110
+ )
111
+ return [self._row_to_record(r) for r in rows]
112
+
113
+ @staticmethod
114
+ def _row_to_record(row) -> ProvenanceRecord:
115
+ d = dict(row)
116
+ return ProvenanceRecord(
117
+ provenance_id=d["provenance_id"],
118
+ profile_id=d["profile_id"],
119
+ fact_id=d["fact_id"],
120
+ source_type=d["source_type"],
121
+ source_id=d.get("source_id", ""),
122
+ created_by=d.get("created_by", ""),
123
+ timestamp=d["timestamp"],
124
+ )