superlocalmemory 2.8.6 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/LICENSE +9 -1
  2. package/NOTICE +63 -0
  3. package/README.md +165 -480
  4. package/bin/slm +17 -449
  5. package/bin/slm-npm +1 -1
  6. package/conftest.py +5 -0
  7. package/docs/api-reference.md +284 -0
  8. package/docs/architecture.md +149 -0
  9. package/docs/auto-memory.md +150 -0
  10. package/docs/cli-reference.md +276 -0
  11. package/docs/compliance.md +191 -0
  12. package/docs/configuration.md +182 -0
  13. package/docs/getting-started.md +102 -0
  14. package/docs/ide-setup.md +261 -0
  15. package/docs/mcp-tools.md +220 -0
  16. package/docs/migration-from-v2.md +170 -0
  17. package/docs/profiles.md +173 -0
  18. package/docs/troubleshooting.md +310 -0
  19. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  20. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  21. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  22. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  23. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  24. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  25. package/ide/configs/cursor-mcp.json +15 -0
  26. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  27. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  28. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  29. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  30. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  31. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  32. package/{configs → ide/configs}/zed-mcp.json +2 -2
  33. package/{hooks → ide/hooks}/context-hook.js +9 -20
  34. package/ide/hooks/memory-list-skill.js +70 -0
  35. package/ide/hooks/memory-profile-skill.js +101 -0
  36. package/ide/hooks/memory-recall-skill.js +62 -0
  37. package/ide/hooks/memory-remember-skill.js +68 -0
  38. package/ide/hooks/memory-reset-skill.js +160 -0
  39. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  40. package/ide/integrations/langchain/README.md +106 -0
  41. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  42. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  43. package/ide/integrations/langchain/pyproject.toml +38 -0
  44. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  45. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  46. package/ide/integrations/langchain/tests/test_security.py +117 -0
  47. package/ide/integrations/llamaindex/README.md +81 -0
  48. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  49. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  50. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  51. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  52. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  53. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  54. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  55. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  56. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  57. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  58. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  59. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  60. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  61. package/package.json +13 -22
  62. package/pyproject.toml +85 -0
  63. package/scripts/build-dmg.sh +417 -0
  64. package/scripts/install-skills.ps1 +334 -0
  65. package/scripts/postinstall.js +2 -2
  66. package/scripts/start-dashboard.ps1 +52 -0
  67. package/scripts/start-dashboard.sh +41 -0
  68. package/scripts/sync-wiki.ps1 +127 -0
  69. package/scripts/sync-wiki.sh +82 -0
  70. package/scripts/test-dmg.sh +161 -0
  71. package/scripts/test-npm-package.ps1 +252 -0
  72. package/scripts/test-npm-package.sh +207 -0
  73. package/scripts/verify-install.ps1 +294 -0
  74. package/scripts/verify-install.sh +266 -0
  75. package/src/superlocalmemory/__init__.py +0 -0
  76. package/src/superlocalmemory/attribution/__init__.py +9 -0
  77. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  78. package/src/superlocalmemory/attribution/signer.py +153 -0
  79. package/src/superlocalmemory/attribution/watermark.py +189 -0
  80. package/src/superlocalmemory/cli/__init__.py +5 -0
  81. package/src/superlocalmemory/cli/commands.py +245 -0
  82. package/src/superlocalmemory/cli/main.py +89 -0
  83. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  84. package/src/superlocalmemory/cli/post_install.py +99 -0
  85. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  86. package/src/superlocalmemory/compliance/__init__.py +0 -0
  87. package/src/superlocalmemory/compliance/abac.py +204 -0
  88. package/src/superlocalmemory/compliance/audit.py +314 -0
  89. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  90. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  91. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  92. package/src/superlocalmemory/compliance/retention.py +232 -0
  93. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  94. package/src/superlocalmemory/core/__init__.py +0 -0
  95. package/src/superlocalmemory/core/config.py +391 -0
  96. package/src/superlocalmemory/core/embeddings.py +293 -0
  97. package/src/superlocalmemory/core/engine.py +701 -0
  98. package/src/superlocalmemory/core/hooks.py +65 -0
  99. package/src/superlocalmemory/core/maintenance.py +172 -0
  100. package/src/superlocalmemory/core/modes.py +140 -0
  101. package/src/superlocalmemory/core/profiles.py +234 -0
  102. package/src/superlocalmemory/core/registry.py +117 -0
  103. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  104. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  105. package/src/superlocalmemory/encoding/__init__.py +0 -0
  106. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  107. package/src/superlocalmemory/encoding/emotional.py +125 -0
  108. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  109. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  110. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  111. package/src/superlocalmemory/encoding/foresight.py +91 -0
  112. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  113. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  114. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  115. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  116. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  117. package/src/superlocalmemory/encoding/type_router.py +235 -0
  118. package/src/superlocalmemory/hooks/__init__.py +3 -0
  119. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  120. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  121. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  122. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  123. package/src/superlocalmemory/infra/__init__.py +3 -0
  124. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  125. package/src/superlocalmemory/infra/backup.py +317 -0
  126. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  127. package/src/superlocalmemory/infra/event_bus.py +381 -0
  128. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  129. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  130. package/src/superlocalmemory/learning/__init__.py +0 -0
  131. package/src/superlocalmemory/learning/adaptive.py +172 -0
  132. package/src/superlocalmemory/learning/behavioral.py +490 -0
  133. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  134. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  135. package/src/superlocalmemory/learning/cross_project.py +399 -0
  136. package/src/superlocalmemory/learning/database.py +376 -0
  137. package/src/superlocalmemory/learning/engagement.py +323 -0
  138. package/src/superlocalmemory/learning/features.py +138 -0
  139. package/src/superlocalmemory/learning/feedback.py +316 -0
  140. package/src/superlocalmemory/learning/outcomes.py +255 -0
  141. package/src/superlocalmemory/learning/project_context.py +366 -0
  142. package/src/superlocalmemory/learning/ranker.py +155 -0
  143. package/src/superlocalmemory/learning/source_quality.py +303 -0
  144. package/src/superlocalmemory/learning/workflows.py +309 -0
  145. package/src/superlocalmemory/llm/__init__.py +0 -0
  146. package/src/superlocalmemory/llm/backbone.py +316 -0
  147. package/src/superlocalmemory/math/__init__.py +0 -0
  148. package/src/superlocalmemory/math/fisher.py +356 -0
  149. package/src/superlocalmemory/math/langevin.py +398 -0
  150. package/src/superlocalmemory/math/sheaf.py +257 -0
  151. package/src/superlocalmemory/mcp/__init__.py +0 -0
  152. package/src/superlocalmemory/mcp/resources.py +245 -0
  153. package/src/superlocalmemory/mcp/server.py +61 -0
  154. package/src/superlocalmemory/mcp/tools.py +18 -0
  155. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  156. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  157. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  158. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  159. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  160. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  161. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  162. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  163. package/src/superlocalmemory/retrieval/engine.py +390 -0
  164. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  165. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  166. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  167. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  168. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  169. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  170. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  171. package/src/superlocalmemory/server/__init__.py +1 -0
  172. package/src/superlocalmemory/server/api.py +248 -0
  173. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  174. package/src/superlocalmemory/server/routes/agents.py +107 -0
  175. package/src/superlocalmemory/server/routes/backup.py +91 -0
  176. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  177. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  178. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  179. package/src/superlocalmemory/server/routes/events.py +183 -0
  180. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  181. package/src/superlocalmemory/server/routes/learning.py +273 -0
  182. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  183. package/src/superlocalmemory/server/routes/memories.py +399 -0
  184. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  185. package/src/superlocalmemory/server/routes/stats.py +346 -0
  186. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  187. package/src/superlocalmemory/server/routes/ws.py +82 -0
  188. package/src/superlocalmemory/server/security_middleware.py +57 -0
  189. package/src/superlocalmemory/server/ui.py +245 -0
  190. package/src/superlocalmemory/storage/__init__.py +0 -0
  191. package/src/superlocalmemory/storage/access_control.py +182 -0
  192. package/src/superlocalmemory/storage/database.py +594 -0
  193. package/src/superlocalmemory/storage/migrations.py +303 -0
  194. package/src/superlocalmemory/storage/models.py +406 -0
  195. package/src/superlocalmemory/storage/schema.py +726 -0
  196. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  197. package/src/superlocalmemory/trust/__init__.py +0 -0
  198. package/src/superlocalmemory/trust/gate.py +130 -0
  199. package/src/superlocalmemory/trust/provenance.py +124 -0
  200. package/src/superlocalmemory/trust/scorer.py +347 -0
  201. package/src/superlocalmemory/trust/signals.py +153 -0
  202. package/ui/index.html +278 -5
  203. package/ui/js/auto-settings.js +70 -0
  204. package/ui/js/dashboard.js +90 -0
  205. package/ui/js/fact-detail.js +92 -0
  206. package/ui/js/feedback.js +2 -2
  207. package/ui/js/ide-status.js +102 -0
  208. package/ui/js/math-health.js +98 -0
  209. package/ui/js/recall-lab.js +127 -0
  210. package/ui/js/settings.js +2 -2
  211. package/ui/js/trust-dashboard.js +73 -0
  212. package/api_server.py +0 -724
  213. package/bin/aider-smart +0 -72
  214. package/bin/superlocalmemoryv2-learning +0 -4
  215. package/bin/superlocalmemoryv2-list +0 -3
  216. package/bin/superlocalmemoryv2-patterns +0 -4
  217. package/bin/superlocalmemoryv2-profile +0 -3
  218. package/bin/superlocalmemoryv2-recall +0 -3
  219. package/bin/superlocalmemoryv2-remember +0 -3
  220. package/bin/superlocalmemoryv2-reset +0 -3
  221. package/bin/superlocalmemoryv2-status +0 -3
  222. package/configs/chatgpt-desktop-mcp.json +0 -16
  223. package/configs/cursor-mcp.json +0 -15
  224. package/hooks/memory-list-skill.js +0 -139
  225. package/hooks/memory-profile-skill.js +0 -273
  226. package/hooks/memory-recall-skill.js +0 -114
  227. package/hooks/memory-remember-skill.js +0 -127
  228. package/hooks/memory-reset-skill.js +0 -274
  229. package/mcp_server.py +0 -1808
  230. package/requirements-core.txt +0 -22
  231. package/requirements-learning.txt +0 -12
  232. package/requirements.txt +0 -12
  233. package/src/agent_registry.py +0 -411
  234. package/src/auth_middleware.py +0 -61
  235. package/src/auto_backup.py +0 -459
  236. package/src/behavioral/__init__.py +0 -49
  237. package/src/behavioral/behavioral_listener.py +0 -203
  238. package/src/behavioral/behavioral_patterns.py +0 -275
  239. package/src/behavioral/cross_project_transfer.py +0 -206
  240. package/src/behavioral/outcome_inference.py +0 -194
  241. package/src/behavioral/outcome_tracker.py +0 -193
  242. package/src/behavioral/tests/__init__.py +0 -4
  243. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  244. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  245. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  246. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  247. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  248. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  249. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  250. package/src/cache_manager.py +0 -518
  251. package/src/compliance/__init__.py +0 -48
  252. package/src/compliance/abac_engine.py +0 -149
  253. package/src/compliance/abac_middleware.py +0 -116
  254. package/src/compliance/audit_db.py +0 -215
  255. package/src/compliance/audit_logger.py +0 -148
  256. package/src/compliance/retention_manager.py +0 -289
  257. package/src/compliance/retention_scheduler.py +0 -186
  258. package/src/compliance/tests/__init__.py +0 -4
  259. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  260. package/src/compliance/tests/test_abac_engine.py +0 -124
  261. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  262. package/src/compliance/tests/test_audit_db.py +0 -123
  263. package/src/compliance/tests/test_audit_logger.py +0 -98
  264. package/src/compliance/tests/test_mcp_audit.py +0 -128
  265. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  266. package/src/compliance/tests/test_retention_manager.py +0 -131
  267. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  268. package/src/compression/__init__.py +0 -25
  269. package/src/compression/cli.py +0 -150
  270. package/src/compression/cold_storage.py +0 -217
  271. package/src/compression/config.py +0 -72
  272. package/src/compression/orchestrator.py +0 -133
  273. package/src/compression/tier2_compressor.py +0 -228
  274. package/src/compression/tier3_compressor.py +0 -153
  275. package/src/compression/tier_classifier.py +0 -148
  276. package/src/db_connection_manager.py +0 -536
  277. package/src/embedding_engine.py +0 -63
  278. package/src/embeddings/__init__.py +0 -47
  279. package/src/embeddings/cache.py +0 -70
  280. package/src/embeddings/cli.py +0 -113
  281. package/src/embeddings/constants.py +0 -47
  282. package/src/embeddings/database.py +0 -91
  283. package/src/embeddings/engine.py +0 -247
  284. package/src/embeddings/model_loader.py +0 -145
  285. package/src/event_bus.py +0 -562
  286. package/src/graph/__init__.py +0 -36
  287. package/src/graph/build_helpers.py +0 -74
  288. package/src/graph/cli.py +0 -87
  289. package/src/graph/cluster_builder.py +0 -188
  290. package/src/graph/cluster_summary.py +0 -148
  291. package/src/graph/constants.py +0 -47
  292. package/src/graph/edge_builder.py +0 -162
  293. package/src/graph/entity_extractor.py +0 -95
  294. package/src/graph/graph_core.py +0 -226
  295. package/src/graph/graph_search.py +0 -231
  296. package/src/graph/hierarchical.py +0 -207
  297. package/src/graph/schema.py +0 -99
  298. package/src/graph_engine.py +0 -52
  299. package/src/hnsw_index.py +0 -628
  300. package/src/hybrid_search.py +0 -46
  301. package/src/learning/__init__.py +0 -217
  302. package/src/learning/adaptive_ranker.py +0 -682
  303. package/src/learning/bootstrap/__init__.py +0 -69
  304. package/src/learning/bootstrap/constants.py +0 -93
  305. package/src/learning/bootstrap/db_queries.py +0 -316
  306. package/src/learning/bootstrap/sampling.py +0 -82
  307. package/src/learning/bootstrap/text_utils.py +0 -71
  308. package/src/learning/cross_project_aggregator.py +0 -857
  309. package/src/learning/db/__init__.py +0 -40
  310. package/src/learning/db/constants.py +0 -44
  311. package/src/learning/db/schema.py +0 -279
  312. package/src/learning/engagement_tracker.py +0 -628
  313. package/src/learning/feature_extractor.py +0 -708
  314. package/src/learning/feedback_collector.py +0 -806
  315. package/src/learning/learning_db.py +0 -915
  316. package/src/learning/project_context_manager.py +0 -572
  317. package/src/learning/ranking/__init__.py +0 -33
  318. package/src/learning/ranking/constants.py +0 -84
  319. package/src/learning/ranking/helpers.py +0 -278
  320. package/src/learning/source_quality_scorer.py +0 -676
  321. package/src/learning/synthetic_bootstrap.py +0 -755
  322. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  323. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  324. package/src/learning/tests/test_aggregator.py +0 -306
  325. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  326. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  327. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  328. package/src/learning/tests/test_feedback_collector.py +0 -294
  329. package/src/learning/tests/test_learning_db.py +0 -602
  330. package/src/learning/tests/test_learning_db_v28.py +0 -110
  331. package/src/learning/tests/test_learning_init_v28.py +0 -48
  332. package/src/learning/tests/test_outcome_signals.py +0 -48
  333. package/src/learning/tests/test_project_context.py +0 -292
  334. package/src/learning/tests/test_schema_migration.py +0 -319
  335. package/src/learning/tests/test_signal_inference.py +0 -397
  336. package/src/learning/tests/test_source_quality.py +0 -351
  337. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  338. package/src/learning/tests/test_workflow_miner.py +0 -318
  339. package/src/learning/workflow_pattern_miner.py +0 -655
  340. package/src/lifecycle/__init__.py +0 -54
  341. package/src/lifecycle/bounded_growth.py +0 -239
  342. package/src/lifecycle/compaction_engine.py +0 -226
  343. package/src/lifecycle/lifecycle_engine.py +0 -355
  344. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  345. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  346. package/src/lifecycle/retention_policy.py +0 -285
  347. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  348. package/src/lifecycle/tests/test_compaction.py +0 -179
  349. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  350. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  351. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  352. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  353. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  354. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  355. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  356. package/src/mcp_tools_v28.py +0 -281
  357. package/src/memory/__init__.py +0 -36
  358. package/src/memory/cli.py +0 -205
  359. package/src/memory/constants.py +0 -39
  360. package/src/memory/helpers.py +0 -28
  361. package/src/memory/schema.py +0 -166
  362. package/src/memory-profiles.py +0 -595
  363. package/src/memory-reset.py +0 -491
  364. package/src/memory_compression.py +0 -989
  365. package/src/memory_store_v2.py +0 -1155
  366. package/src/migrate_v1_to_v2.py +0 -629
  367. package/src/pattern_learner.py +0 -34
  368. package/src/patterns/__init__.py +0 -24
  369. package/src/patterns/analyzers.py +0 -251
  370. package/src/patterns/learner.py +0 -271
  371. package/src/patterns/scoring.py +0 -171
  372. package/src/patterns/store.py +0 -225
  373. package/src/patterns/terminology.py +0 -140
  374. package/src/provenance_tracker.py +0 -312
  375. package/src/qualixar_attribution.py +0 -139
  376. package/src/qualixar_watermark.py +0 -78
  377. package/src/query_optimizer.py +0 -511
  378. package/src/rate_limiter.py +0 -83
  379. package/src/search/__init__.py +0 -20
  380. package/src/search/cli.py +0 -77
  381. package/src/search/constants.py +0 -26
  382. package/src/search/engine.py +0 -241
  383. package/src/search/fusion.py +0 -122
  384. package/src/search/index_loader.py +0 -114
  385. package/src/search/methods.py +0 -162
  386. package/src/search_engine_v2.py +0 -401
  387. package/src/setup_validator.py +0 -482
  388. package/src/subscription_manager.py +0 -391
  389. package/src/tree/__init__.py +0 -59
  390. package/src/tree/builder.py +0 -185
  391. package/src/tree/nodes.py +0 -202
  392. package/src/tree/queries.py +0 -257
  393. package/src/tree/schema.py +0 -80
  394. package/src/tree_manager.py +0 -19
  395. package/src/trust/__init__.py +0 -45
  396. package/src/trust/constants.py +0 -66
  397. package/src/trust/queries.py +0 -157
  398. package/src/trust/schema.py +0 -95
  399. package/src/trust/scorer.py +0 -299
  400. package/src/trust/signals.py +0 -95
  401. package/src/trust_scorer.py +0 -44
  402. package/ui/app.js +0 -1588
  403. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  404. package/ui/js/graph-cytoscape.js +0 -1168
  405. package/ui/js/graph-d3-backup.js +0 -32
  406. package/ui/js/graph.js +0 -32
  407. package/ui_server.py +0 -286
  408. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  409. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  410. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  411. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  412. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  413. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  414. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  415. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  416. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  417. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  418. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  419. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  420. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  421. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  422. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  423. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  424. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  425. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  426. /package/{completions → ide/completions}/slm.bash +0 -0
  427. /package/{completions → ide/completions}/slm.zsh +0 -0
  428. /package/{configs → ide/configs}/cody-commands.json +0 -0
  429. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
  430. /package/{install.ps1 → scripts/install.ps1} +0 -0
  431. /package/{install.sh → scripts/install.sh} +0 -0
@@ -1,355 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Memory lifecycle state machine with formal transition rules.
4
-
5
- State Machine:
6
- ACTIVE -> WARM -> COLD -> ARCHIVED -> TOMBSTONED
7
-
8
- Reactivation allowed from WARM, COLD, ARCHIVED back to ACTIVE.
9
- TOMBSTONED is terminal (deletion only).
10
-
11
- Each transition is recorded in lifecycle_history (JSON array) for auditability.
12
- Thread-safe via threading.Lock() around read-modify-write operations.
13
- """
14
- import sqlite3
15
- import json
16
- import threading
17
- from datetime import datetime
18
- from pathlib import Path
19
- from typing import Optional, Dict, Any, List
20
-
21
-
22
- class LifecycleEngine:
23
- """Manages memory lifecycle states: ACTIVE -> WARM -> COLD -> ARCHIVED -> TOMBSTONED."""
24
-
25
- STATES = ("active", "warm", "cold", "archived", "tombstoned")
26
-
27
- TRANSITIONS = {
28
- "active": ["warm"],
29
- "warm": ["active", "cold"],
30
- "cold": ["active", "archived"],
31
- "archived": ["active", "tombstoned"],
32
- "tombstoned": [], # Terminal state
33
- }
34
-
35
- def __init__(self, db_path: Optional[str] = None, config_path: Optional[str] = None):
36
- if db_path is None:
37
- db_path = Path.home() / ".claude-memory" / "memory.db"
38
- self._db_path = str(db_path)
39
- self._config_path = config_path
40
- self._lock = threading.Lock()
41
- self._ensure_columns()
42
-
43
- def _get_connection(self) -> sqlite3.Connection:
44
- """Get a SQLite connection to memory.db."""
45
- conn = sqlite3.connect(self._db_path)
46
- conn.row_factory = sqlite3.Row
47
- return conn
48
-
49
- def _ensure_columns(self) -> None:
50
- """Ensure v2.8 lifecycle columns exist in memories table."""
51
- try:
52
- conn = self._get_connection()
53
- try:
54
- cursor = conn.cursor()
55
- cursor.execute("PRAGMA table_info(memories)")
56
- existing = {row[1] for row in cursor.fetchall()}
57
- v28_cols = [
58
- ("lifecycle_state", "TEXT DEFAULT 'active'"),
59
- ("lifecycle_updated_at", "TIMESTAMP"),
60
- ("lifecycle_history", "TEXT DEFAULT '[]'"),
61
- ("access_level", "TEXT DEFAULT 'public'"),
62
- ]
63
- for col_name, col_type in v28_cols:
64
- if col_name not in existing:
65
- try:
66
- cursor.execute(
67
- f"ALTER TABLE memories ADD COLUMN {col_name} {col_type}"
68
- )
69
- except sqlite3.OperationalError:
70
- pass
71
- conn.commit()
72
- finally:
73
- conn.close()
74
- except Exception:
75
- pass # Graceful degradation — don't block engine init
76
-
77
- def is_valid_transition(self, from_state: str, to_state: str) -> bool:
78
- """Check if a state transition is valid per the state machine.
79
-
80
- Args:
81
- from_state: Current lifecycle state
82
- to_state: Target lifecycle state
83
-
84
- Returns:
85
- True if the transition is allowed, False otherwise
86
- """
87
- if from_state not in self.TRANSITIONS:
88
- return False
89
- return to_state in self.TRANSITIONS[from_state]
90
-
91
- def get_memory_state(self, memory_id: int) -> Optional[str]:
92
- """Get the current lifecycle state of a memory.
93
-
94
- Args:
95
- memory_id: The memory's database ID
96
-
97
- Returns:
98
- The lifecycle state string, or None if memory not found
99
- """
100
- conn = self._get_connection()
101
- try:
102
- try:
103
- row = conn.execute(
104
- "SELECT lifecycle_state FROM memories WHERE id = ?",
105
- (memory_id,),
106
- ).fetchone()
107
- except sqlite3.OperationalError as e:
108
- if "no such column" in str(e):
109
- conn.close()
110
- self._ensure_columns()
111
- conn = self._get_connection()
112
- row = conn.execute(
113
- "SELECT lifecycle_state FROM memories WHERE id = ?",
114
- (memory_id,),
115
- ).fetchone()
116
- else:
117
- raise
118
- if row is None:
119
- return None
120
- return row["lifecycle_state"] or "active"
121
- finally:
122
- conn.close()
123
-
124
- def transition_memory(
125
- self,
126
- memory_id: int,
127
- to_state: str,
128
- reason: str = "",
129
- ) -> Dict[str, Any]:
130
- """Transition a memory to a new lifecycle state.
131
-
132
- Validates the transition against the state machine, updates the database,
133
- and appends to the lifecycle_history JSON array.
134
-
135
- Args:
136
- memory_id: The memory's database ID
137
- to_state: Target lifecycle state
138
- reason: Human-readable reason for the transition
139
-
140
- Returns:
141
- Dict with success/failure status, from_state, to_state, etc.
142
- """
143
- with self._lock:
144
- conn = self._get_connection()
145
- try:
146
- row = conn.execute(
147
- "SELECT lifecycle_state, lifecycle_history FROM memories WHERE id = ?",
148
- (memory_id,),
149
- ).fetchone()
150
-
151
- if row is None:
152
- return {"success": False, "error": f"Memory {memory_id} not found"}
153
-
154
- from_state = row["lifecycle_state"] or "active"
155
-
156
- if not self.is_valid_transition(from_state, to_state):
157
- return {
158
- "success": False,
159
- "error": f"Invalid transition from '{from_state}' to '{to_state}'",
160
- }
161
-
162
- now = datetime.now().isoformat()
163
- history = json.loads(row["lifecycle_history"] or "[]")
164
- history.append({
165
- "from": from_state,
166
- "to": to_state,
167
- "reason": reason,
168
- "timestamp": now,
169
- })
170
-
171
- conn.execute(
172
- """UPDATE memories
173
- SET lifecycle_state = ?,
174
- lifecycle_updated_at = ?,
175
- lifecycle_history = ?
176
- WHERE id = ?""",
177
- (to_state, now, json.dumps(history), memory_id),
178
- )
179
- conn.commit()
180
-
181
- self._try_emit_event("lifecycle.transitioned", memory_id, {
182
- "from_state": from_state,
183
- "to_state": to_state,
184
- "reason": reason,
185
- })
186
-
187
- return {
188
- "success": True,
189
- "from_state": from_state,
190
- "to_state": to_state,
191
- "memory_id": memory_id,
192
- "reason": reason,
193
- "timestamp": now,
194
- }
195
- finally:
196
- conn.close()
197
-
198
- def batch_transition(
199
- self,
200
- memory_ids: List[int],
201
- to_state: str,
202
- reasons: Optional[List[str]] = None,
203
- ) -> Dict[str, Any]:
204
- """Transition multiple memories in a single connection + commit.
205
-
206
- Validates each transition individually, skips invalid ones.
207
- Much faster than calling transition_memory() in a loop because
208
- it opens only one connection and commits once.
209
-
210
- Args:
211
- memory_ids: List of memory IDs to transition
212
- to_state: Target lifecycle state for all
213
- reasons: Per-memory reasons (defaults to empty string)
214
-
215
- Returns:
216
- Dict with succeeded (list), failed (list), and counts
217
- """
218
- if reasons is None:
219
- reasons = [""] * len(memory_ids)
220
-
221
- succeeded: List[Dict[str, Any]] = []
222
- failed: List[Dict[str, Any]] = []
223
-
224
- with self._lock:
225
- conn = self._get_connection()
226
- try:
227
- now = datetime.now().isoformat()
228
-
229
- for mem_id, reason in zip(memory_ids, reasons):
230
- row = conn.execute(
231
- "SELECT lifecycle_state, lifecycle_history "
232
- "FROM memories WHERE id = ?",
233
- (mem_id,),
234
- ).fetchone()
235
-
236
- if row is None:
237
- failed.append({"memory_id": mem_id, "error": "not_found"})
238
- continue
239
-
240
- from_state = row["lifecycle_state"] or "active"
241
- if not self.is_valid_transition(from_state, to_state):
242
- failed.append({
243
- "memory_id": mem_id,
244
- "error": f"invalid_{from_state}_to_{to_state}",
245
- })
246
- continue
247
-
248
- history = json.loads(row["lifecycle_history"] or "[]")
249
- history.append({
250
- "from": from_state,
251
- "to": to_state,
252
- "reason": reason,
253
- "timestamp": now,
254
- })
255
-
256
- conn.execute(
257
- """UPDATE memories
258
- SET lifecycle_state = ?,
259
- lifecycle_updated_at = ?,
260
- lifecycle_history = ?
261
- WHERE id = ?""",
262
- (to_state, now, json.dumps(history), mem_id),
263
- )
264
- succeeded.append({
265
- "memory_id": mem_id,
266
- "from_state": from_state,
267
- "to_state": to_state,
268
- })
269
-
270
- conn.commit()
271
-
272
- # Best-effort event emission for each transitioned memory
273
- for entry in succeeded:
274
- self._try_emit_event(
275
- "lifecycle.transitioned", entry["memory_id"], {
276
- "from_state": entry["from_state"],
277
- "to_state": entry["to_state"],
278
- "reason": "batch",
279
- },
280
- )
281
-
282
- return {
283
- "succeeded": succeeded,
284
- "failed": failed,
285
- "total": len(memory_ids),
286
- "success_count": len(succeeded),
287
- "fail_count": len(failed),
288
- }
289
- finally:
290
- conn.close()
291
-
292
- def reactivate_memory(
293
- self,
294
- memory_id: int,
295
- trigger: str = "",
296
- ) -> Dict[str, Any]:
297
- """Reactivate a non-active memory back to ACTIVE state.
298
-
299
- Convenience wrapper around transition_memory for reactivation.
300
- Valid from WARM, COLD, or ARCHIVED states.
301
-
302
- Args:
303
- memory_id: The memory's database ID
304
- trigger: What triggered reactivation (e.g., "recall", "explicit")
305
-
306
- Returns:
307
- Dict with success/failure status
308
- """
309
- return self.transition_memory(
310
- memory_id, "active", reason=f"reactivated:{trigger}"
311
- )
312
-
313
- def get_state_distribution(self) -> Dict[str, int]:
314
- """Get count of memories in each lifecycle state.
315
-
316
- Returns:
317
- Dict mapping state names to counts (all STATES keys present)
318
- """
319
- conn = self._get_connection()
320
- try:
321
- dist = {state: 0 for state in self.STATES}
322
- try:
323
- rows = conn.execute(
324
- "SELECT lifecycle_state, COUNT(*) as cnt "
325
- "FROM memories GROUP BY lifecycle_state"
326
- ).fetchall()
327
- except sqlite3.OperationalError as e:
328
- if "no such column" in str(e):
329
- conn.close()
330
- self._ensure_columns()
331
- conn = self._get_connection()
332
- rows = conn.execute(
333
- "SELECT lifecycle_state, COUNT(*) as cnt "
334
- "FROM memories GROUP BY lifecycle_state"
335
- ).fetchall()
336
- else:
337
- raise
338
- for row in rows:
339
- state = row["lifecycle_state"] if row["lifecycle_state"] else "active"
340
- if state in dist:
341
- dist[state] = row["cnt"]
342
- return dist
343
- finally:
344
- conn.close()
345
-
346
- def _try_emit_event(
347
- self, event_type: str, memory_id: int, payload: dict
348
- ) -> None:
349
- """Best-effort EventBus emission. Fails silently if unavailable."""
350
- try:
351
- from event_bus import EventBus
352
- bus = EventBus.get_instance(Path(self._db_path))
353
- bus.emit(event_type, payload=payload, memory_id=memory_id)
354
- except Exception:
355
- pass
@@ -1,257 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Lifecycle evaluation rules — determines which memories should transition.
4
-
5
- Evaluates memories against configurable thresholds based on:
6
- - Time since last access (staleness)
7
- - Importance score
8
- - Current lifecycle state
9
-
10
- Default rules:
11
- ACTIVE -> WARM: no access >= 30 days AND importance <= 6
12
- WARM -> COLD: no access >= 90 days AND importance <= 4
13
- COLD -> ARCHIVED: no access >= 180 days (any importance)
14
-
15
- Thresholds configurable via lifecycle_config.json.
16
- """
17
- import sqlite3
18
- import json
19
- from datetime import datetime
20
- from pathlib import Path
21
- from typing import Optional, Dict, Any, List, Set
22
-
23
-
24
- # Default evaluation thresholds
25
- DEFAULT_EVAL_CONFIG: Dict[str, Dict[str, Any]] = {
26
- "active_to_warm": {
27
- "no_access_days": 30,
28
- "max_importance": 6,
29
- },
30
- "warm_to_cold": {
31
- "no_access_days": 90,
32
- "max_importance": 4,
33
- },
34
- "cold_to_archived": {
35
- "no_access_days": 180,
36
- },
37
- }
38
-
39
-
40
- class LifecycleEvaluator:
41
- """Evaluates memories for lifecycle state transitions.
42
-
43
- Scans memories and recommends transitions based on staleness and importance.
44
- Does NOT execute transitions — returns recommendations for the engine or
45
- scheduler to act on.
46
- """
47
-
48
- def __init__(
49
- self, db_path: Optional[str] = None, config_path: Optional[str] = None
50
- ):
51
- if db_path is None:
52
- db_path = str(Path.home() / ".claude-memory" / "memory.db")
53
- self._db_path = str(db_path)
54
- self._config_path = config_path
55
-
56
- def _get_connection(self) -> sqlite3.Connection:
57
- """Get a SQLite connection to memory.db."""
58
- conn = sqlite3.connect(self._db_path)
59
- conn.row_factory = sqlite3.Row
60
- return conn
61
-
62
- def _ensure_lifecycle_columns(self) -> None:
63
- """Ensure v2.8 lifecycle columns exist via LifecycleEngine."""
64
- try:
65
- from lifecycle.lifecycle_engine import LifecycleEngine
66
- engine = LifecycleEngine(db_path=self._db_path)
67
- engine._ensure_columns()
68
- except Exception:
69
- pass # Best effort — don't block evaluation
70
-
71
- def evaluate_memories(
72
- self,
73
- profile: Optional[str] = None,
74
- retention_overrides: Optional[Set[int]] = None,
75
- ) -> List[Dict[str, Any]]:
76
- """Scan all memories and return recommended transitions.
77
-
78
- Args:
79
- profile: Filter by profile (None = all profiles)
80
- retention_overrides: Set of memory IDs to skip (retention-protected)
81
-
82
- Returns:
83
- List of recommendation dicts with memory_id, from_state, to_state, reason
84
- """
85
- config = self._load_config()
86
- overrides = retention_overrides or set()
87
-
88
- conn = self._get_connection()
89
- try:
90
- query = (
91
- "SELECT id, lifecycle_state, importance, last_accessed, created_at "
92
- "FROM memories WHERE lifecycle_state IN ('active', 'warm', 'cold')"
93
- )
94
- params: list = []
95
- if profile:
96
- query += " AND profile = ?"
97
- params.append(profile)
98
-
99
- try:
100
- rows = conn.execute(query, params).fetchall()
101
- except sqlite3.OperationalError as e:
102
- if "no such column" in str(e):
103
- conn.close()
104
- self._ensure_lifecycle_columns()
105
- conn = self._get_connection()
106
- rows = conn.execute(query, params).fetchall()
107
- else:
108
- raise
109
-
110
- recommendations = []
111
- now = datetime.now()
112
-
113
- for row in rows:
114
- if row["id"] in overrides:
115
- continue
116
- rec = self._evaluate_row(row, config, now)
117
- if rec:
118
- recommendations.append(rec)
119
-
120
- return recommendations
121
- finally:
122
- conn.close()
123
-
124
- def evaluate_single(
125
- self,
126
- memory_id: int,
127
- retention_overrides: Optional[Set[int]] = None,
128
- ) -> Optional[Dict[str, Any]]:
129
- """Evaluate a single memory for potential transition.
130
-
131
- Args:
132
- memory_id: The memory's database ID
133
- retention_overrides: Set of memory IDs to skip
134
-
135
- Returns:
136
- Recommendation dict, or None if no transition recommended
137
- """
138
- overrides = retention_overrides or set()
139
- if memory_id in overrides:
140
- return None
141
-
142
- config = self._load_config()
143
- conn = self._get_connection()
144
- try:
145
- try:
146
- row = conn.execute(
147
- "SELECT id, lifecycle_state, importance, last_accessed, created_at "
148
- "FROM memories WHERE id = ?",
149
- (memory_id,),
150
- ).fetchone()
151
- except sqlite3.OperationalError as e:
152
- if "no such column" in str(e):
153
- conn.close()
154
- self._ensure_lifecycle_columns()
155
- conn = self._get_connection()
156
- row = conn.execute(
157
- "SELECT id, lifecycle_state, importance, last_accessed, created_at "
158
- "FROM memories WHERE id = ?",
159
- (memory_id,),
160
- ).fetchone()
161
- else:
162
- raise
163
- if row is None:
164
- return None
165
- return self._evaluate_row(row, config, datetime.now())
166
- finally:
167
- conn.close()
168
-
169
- def _evaluate_row(
170
- self, row: sqlite3.Row, config: Dict, now: datetime
171
- ) -> Optional[Dict[str, Any]]:
172
- """Evaluate a single memory row against transition rules."""
173
- state = row["lifecycle_state"] or "active"
174
- importance = row["importance"] or 5
175
-
176
- # Determine staleness: prefer last_accessed, fall back to created_at
177
- last_access_str = row["last_accessed"] or row["created_at"]
178
- if last_access_str:
179
- try:
180
- last_access = datetime.fromisoformat(str(last_access_str))
181
- except (ValueError, TypeError):
182
- last_access = now # Unparseable -> treat as recent (safe default)
183
- else:
184
- last_access = now
185
-
186
- days_stale = (now - last_access).days
187
-
188
- if state == "active":
189
- rules = config.get("active_to_warm", {})
190
- threshold_days = rules.get("no_access_days", 30)
191
- max_importance = rules.get("max_importance", 6)
192
- if days_stale >= threshold_days and importance <= max_importance:
193
- return self._build_recommendation(
194
- row["id"], "active", "warm", days_stale, importance
195
- )
196
- elif state == "warm":
197
- rules = config.get("warm_to_cold", {})
198
- threshold_days = rules.get("no_access_days", 90)
199
- max_importance = rules.get("max_importance", 4)
200
- if days_stale >= threshold_days and importance <= max_importance:
201
- return self._build_recommendation(
202
- row["id"], "warm", "cold", days_stale, importance
203
- )
204
- elif state == "cold":
205
- rules = config.get("cold_to_archived", {})
206
- threshold_days = rules.get("no_access_days", 180)
207
- if days_stale >= threshold_days:
208
- return self._build_recommendation(
209
- row["id"], "cold", "archived", days_stale, importance
210
- )
211
-
212
- return None
213
-
214
- def _build_recommendation(
215
- self,
216
- memory_id: int,
217
- from_state: str,
218
- to_state: str,
219
- days_stale: int,
220
- importance: int,
221
- ) -> Dict[str, Any]:
222
- """Build a standardized recommendation dict."""
223
- reason = f"no_access_{days_stale}d"
224
- if to_state != "archived":
225
- reason += f"_importance_{importance}"
226
- return {
227
- "memory_id": memory_id,
228
- "from_state": from_state,
229
- "to_state": to_state,
230
- "reason": reason,
231
- "days_stale": days_stale,
232
- "importance": importance,
233
- }
234
-
235
- def _load_config(self) -> Dict[str, Any]:
236
- """Load lifecycle evaluation config from JSON. Returns defaults if missing."""
237
- try:
238
- if self._config_path:
239
- config_path = Path(self._config_path)
240
- else:
241
- config_path = Path(self._db_path).parent / "lifecycle_config.json"
242
- if config_path.exists():
243
- with open(config_path) as f:
244
- user_config = json.load(f)
245
- merged: Dict[str, Any] = {}
246
- for key in DEFAULT_EVAL_CONFIG:
247
- if key in user_config and isinstance(user_config[key], dict):
248
- merged[key] = {**DEFAULT_EVAL_CONFIG[key], **user_config[key]}
249
- else:
250
- merged[key] = dict(DEFAULT_EVAL_CONFIG[key])
251
- for key in user_config:
252
- if key not in merged:
253
- merged[key] = user_config[key]
254
- return merged
255
- except Exception:
256
- pass
257
- return {k: dict(v) for k, v in DEFAULT_EVAL_CONFIG.items()}