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
@@ -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()}