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,572 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- ProjectContextManager — Layer 2: Multi-signal project detection.
6
-
7
- Detects the current active project using 4 weighted signals, not just
8
- the explicit project_name tag. This improves recall by boosting memories
9
- from the currently active project context.
10
-
11
- Signal architecture:
12
- 1. project_tag (weight 3) — Explicit project_name field in memories
13
- 2. project_path (weight 2) — File path analysis (extract project dir)
14
- 3. active_profile (weight 1) — Profile name (weak signal)
15
- 4. content_cluster (weight 1) — Cluster co-occurrence in recent memories
16
-
17
- Winner-take-all with 40% threshold: the candidate project must accumulate
18
- more than 40% of the total weighted signal to be declared the current
19
- project. If no candidate clears the threshold, returns None (ambiguous).
20
-
21
- Design principles:
22
- - Reads memory.db in READ-ONLY mode (never writes to memory.db)
23
- - Handles missing columns gracefully (older DBs lack project_name)
24
- - Thread-safe: each method opens/closes its own connection
25
- - Zero external dependencies (pure stdlib)
26
- """
27
-
28
- import json
29
- import logging
30
- import sqlite3
31
- import threading
32
- from collections import Counter
33
- from pathlib import Path
34
- from typing import Optional, List, Dict, Any
35
-
36
- logger = logging.getLogger("superlocalmemory.learning.project_context")
37
-
38
- MEMORY_DIR = Path.home() / ".claude-memory"
39
- MEMORY_DB_PATH = MEMORY_DIR / "memory.db"
40
- PROFILES_JSON = MEMORY_DIR / "profiles.json"
41
-
42
- # Directories commonly found as parents of project roots.
43
- # Used by _extract_project_from_path to identify where the
44
- # project directory begins in a file path.
45
- _PROJECT_PARENT_DIRS = frozenset({
46
- "projects", "repos", "repositories", "workspace", "workspaces",
47
- "code", "development", "github", "gitlab",
48
- "bitbucket", "Documents", "sites", "apps", "services",
49
- "AGENTIC_Official", # Varun's workspace convention
50
- })
51
-
52
- # Directories that are NOT project names (too generic / too deep).
53
- _SKIP_DIRS = frozenset({
54
- "src", "lib", "bin", "node_modules", "venv", ".venv", "env",
55
- ".git", "__pycache__", "dist", "build", "target", "out",
56
- ".cache", ".config", "tmp", "temp", "logs", "test", "tests",
57
- "vendor", "packages", "deps",
58
- })
59
-
60
-
61
- class ProjectContextManager:
62
- """
63
- Detects the currently active project using multi-signal analysis.
64
-
65
- Usage:
66
- pcm = ProjectContextManager()
67
- project = pcm.detect_current_project()
68
- if project:
69
- boost = pcm.get_project_boost(memory, project)
70
-
71
- Thread-safe: safe to call from multiple agents / MCP handlers.
72
- """
73
-
74
- SIGNAL_WEIGHTS: Dict[str, int] = {
75
- 'project_tag': 3, # Explicit project_name field
76
- 'project_path': 2, # File path analysis
77
- 'active_profile': 1, # Profile name (weak signal)
78
- 'content_cluster': 1, # Cluster co-occurrence
79
- }
80
-
81
- def __init__(self, memory_db_path: Optional[Path] = None):
82
- """
83
- Initialize ProjectContextManager.
84
-
85
- Args:
86
- memory_db_path: Path to memory.db. Defaults to
87
- ~/.claude-memory/memory.db. Opened read-only.
88
- """
89
- self._memory_db_path = Path(memory_db_path) if memory_db_path else MEMORY_DB_PATH
90
- self._lock = threading.Lock()
91
- # Cache available columns to avoid repeated PRAGMA calls
92
- self._available_columns: Optional[set] = None
93
- logger.info(
94
- "ProjectContextManager initialized: db=%s",
95
- self._memory_db_path,
96
- )
97
-
98
- # ------------------------------------------------------------------
99
- # Public API
100
- # ------------------------------------------------------------------
101
-
102
- def detect_current_project(
103
- self,
104
- recent_memories: Optional[List[Dict[str, Any]]] = None,
105
- ) -> Optional[str]:
106
- """
107
- Detect the currently active project from recent memory activity.
108
-
109
- Applies 4 weighted signals. The winner must accumulate >40% of the
110
- total weighted signal to be declared current. Returns None when
111
- ambiguous or insufficient data.
112
-
113
- Args:
114
- recent_memories: Pre-fetched list of memory dicts.
115
- If None, the last 20 memories are fetched from memory.db.
116
-
117
- Returns:
118
- Project name string or None if undetermined.
119
- """
120
- if recent_memories is None:
121
- recent_memories = self._get_recent_memories(limit=20)
122
-
123
- if not recent_memories:
124
- logger.debug("No recent memories — cannot detect project")
125
- return None
126
-
127
- # Accumulate weighted votes per candidate project
128
- votes: Counter = Counter()
129
-
130
- # --- Signal 1: project_tag (weight 3) ---
131
- for mem in recent_memories:
132
- pname = self._safe_get(mem, 'project_name')
133
- if pname:
134
- votes[pname] += self.SIGNAL_WEIGHTS['project_tag']
135
-
136
- # --- Signal 2: project_path (weight 2) ---
137
- for mem in recent_memories:
138
- ppath = self._safe_get(mem, 'project_path')
139
- if ppath:
140
- extracted = self._extract_project_from_path(ppath)
141
- if extracted:
142
- votes[extracted] += self.SIGNAL_WEIGHTS['project_path']
143
-
144
- # --- Signal 3: active_profile (weight 1) ---
145
- # Profile is a weak signal: only contributes if it matches a
146
- # project name that already has some votes.
147
- active_profile = self._get_active_profile()
148
- if active_profile and active_profile != 'default':
149
- # If profile name coincides with an existing candidate, boost it.
150
- # If not, add it as a weak standalone candidate.
151
- votes[active_profile] += self.SIGNAL_WEIGHTS['active_profile']
152
-
153
- # --- Signal 4: content_cluster (weight 1) ---
154
- cluster_project = self._match_content_to_clusters(recent_memories)
155
- if cluster_project:
156
- votes[cluster_project] += self.SIGNAL_WEIGHTS['content_cluster']
157
-
158
- if not votes:
159
- logger.debug("No project signals detected in recent memories")
160
- return None
161
-
162
- # Winner-take-all with 40% threshold
163
- total_weight = sum(votes.values())
164
- winner, winner_weight = votes.most_common(1)[0]
165
- winner_ratio = winner_weight / total_weight if total_weight > 0 else 0.0
166
-
167
- if winner_ratio > 0.4:
168
- logger.debug(
169
- "Project detected: '%s' (%.0f%% of signal, %d total weight)",
170
- winner, winner_ratio * 100, total_weight,
171
- )
172
- return winner
173
-
174
- logger.debug(
175
- "No clear project winner: top='%s' at %.0f%% (threshold 40%%)",
176
- winner, winner_ratio * 100,
177
- )
178
- return None
179
-
180
- def get_project_boost(
181
- self,
182
- memory: Dict[str, Any],
183
- current_project: Optional[str] = None,
184
- ) -> float:
185
- """
186
- Return a boost factor for ranking based on project match.
187
-
188
- Args:
189
- memory: A memory dict with at least 'project_name' or
190
- 'project_path' fields.
191
- current_project: The detected current project (from
192
- detect_current_project). If None, returns neutral.
193
-
194
- Returns:
195
- 1.0 — memory matches current project (boost)
196
- 0.6 — project unknown or memory has no project info (neutral)
197
- 0.3 — memory belongs to a different project (penalty)
198
- """
199
- if current_project is None:
200
- return 0.6 # Unknown project context — neutral
201
-
202
- # Check explicit project_name
203
- mem_project = self._safe_get(memory, 'project_name')
204
- if mem_project:
205
- if mem_project.lower() == current_project.lower():
206
- return 1.0
207
- return 0.3 # Definite mismatch
208
-
209
- # Check project_path
210
- mem_path = self._safe_get(memory, 'project_path')
211
- if mem_path:
212
- extracted = self._extract_project_from_path(mem_path)
213
- if extracted:
214
- if extracted.lower() == current_project.lower():
215
- return 1.0
216
- return 0.3 # Definite mismatch
217
-
218
- # Memory has no project info — neutral
219
- return 0.6
220
-
221
- # ------------------------------------------------------------------
222
- # Data fetching (memory.db — read-only)
223
- # ------------------------------------------------------------------
224
-
225
- def _get_recent_memories(self, limit: int = 20) -> List[Dict[str, Any]]:
226
- """
227
- Fetch the most recent memories from memory.db.
228
-
229
- Returns a list of dicts with available columns. Handles missing
230
- columns gracefully (older databases may lack project_name, etc.).
231
- """
232
- if not self._memory_db_path.exists():
233
- logger.debug("memory.db not found at %s", self._memory_db_path)
234
- return []
235
-
236
- available = self._get_available_columns()
237
-
238
- # Build SELECT with only available columns
239
- desired_cols = [
240
- 'id', 'project_name', 'project_path', 'profile',
241
- 'content', 'cluster_id', 'created_at',
242
- ]
243
- select_cols = [c for c in desired_cols if c in available]
244
-
245
- if not select_cols:
246
- logger.warning("memories table has none of the expected columns")
247
- return []
248
-
249
- # Always need at least 'id' — if missing, bail
250
- if 'id' not in available:
251
- return []
252
-
253
- col_list = ", ".join(select_cols)
254
-
255
- # Build ORDER BY using best available timestamp
256
- order_col = 'created_at' if 'created_at' in available else 'id'
257
-
258
- try:
259
- conn = self._open_memory_db()
260
- try:
261
- cursor = conn.cursor()
262
- cursor.execute(
263
- f"SELECT {col_list} FROM memories "
264
- f"ORDER BY {order_col} DESC LIMIT ?",
265
- (limit,),
266
- )
267
- rows = cursor.fetchall()
268
- # Convert to list of dicts
269
- result = []
270
- for row in rows:
271
- d = {}
272
- for i, col in enumerate(select_cols):
273
- d[col] = row[i]
274
- result.append(d)
275
- return result
276
- finally:
277
- conn.close()
278
- except sqlite3.Error as e:
279
- logger.warning("Failed to read recent memories: %s", e)
280
- return []
281
-
282
- def _get_available_columns(self) -> set:
283
- """
284
- Get the set of column names in the memories table.
285
-
286
- Cached after first call to avoid repeated PRAGMA queries.
287
- """
288
- if self._available_columns is not None:
289
- return self._available_columns
290
-
291
- if not self._memory_db_path.exists():
292
- return set()
293
-
294
- try:
295
- conn = self._open_memory_db()
296
- try:
297
- cursor = conn.cursor()
298
- cursor.execute("PRAGMA table_info(memories)")
299
- cols = {row[1] for row in cursor.fetchall()}
300
- self._available_columns = cols
301
- return cols
302
- finally:
303
- conn.close()
304
- except sqlite3.Error as e:
305
- logger.warning("Failed to read table schema: %s", e)
306
- return set()
307
-
308
- def _open_memory_db(self) -> sqlite3.Connection:
309
- """
310
- Open a read-only connection to memory.db.
311
-
312
- Uses uri=True with mode=ro to enforce read-only access.
313
- Falls back to regular connection if URI mode fails
314
- (some older Python builds do not support it).
315
- """
316
- db_str = str(self._memory_db_path)
317
- try:
318
- # Prefer URI-based read-only mode
319
- uri = f"file:{db_str}?mode=ro"
320
- conn = sqlite3.connect(uri, uri=True, timeout=5)
321
- except (sqlite3.OperationalError, sqlite3.NotSupportedError):
322
- # Fallback: regular connection (still only reads)
323
- conn = sqlite3.connect(db_str, timeout=5)
324
- conn.execute("PRAGMA busy_timeout=3000")
325
- return conn
326
-
327
- # ------------------------------------------------------------------
328
- # Signal extraction helpers
329
- # ------------------------------------------------------------------
330
-
331
- @staticmethod
332
- def _extract_project_from_path(path: str) -> Optional[str]:
333
- """
334
- Extract a project name from a file path.
335
-
336
- Strategy:
337
- 1. Walk path parts looking for a directory that follows a
338
- known parent directory (projects/, repos/, Documents/, etc.).
339
- 2. If found, the directory immediately after the parent is the
340
- project name.
341
- 3. Fallback: use the last non-skip directory component.
342
-
343
- Examples:
344
- /Users/x/projects/MY_PROJECT/src/main.py -> "MY_PROJECT"
345
- /home/x/repos/my-app/lib/util.js -> "my-app"
346
- /workspace/services/auth-service/index.ts -> "auth-service"
347
-
348
- Returns:
349
- Project name string or None if extraction fails.
350
- """
351
- if not path:
352
- return None
353
-
354
- try:
355
- parts = Path(path).parts
356
- except (ValueError, TypeError):
357
- return None
358
-
359
- if len(parts) < 2:
360
- return None
361
-
362
- # Strategy 1: find part after a known parent directory.
363
- # Skip consecutive parent dirs (e.g., workspace/services/ both
364
- # are parent dirs, so the project is the NEXT non-parent part).
365
- for i, part in enumerate(parts):
366
- if part in _PROJECT_PARENT_DIRS:
367
- # Walk forward past any chained parent dirs
368
- j = i + 1
369
- while j < len(parts) and parts[j] in _PROJECT_PARENT_DIRS:
370
- j += 1
371
- if j < len(parts):
372
- candidate = parts[j]
373
- if (
374
- candidate
375
- and candidate not in _SKIP_DIRS
376
- and not candidate.startswith('.')
377
- ):
378
- return candidate
379
-
380
- # Strategy 2: walk backwards to find last meaningful directory
381
- # Skip leaf (likely a filename) and known non-project dirs
382
- for part in reversed(parts[:-1]): # exclude the last component (filename)
383
- if (
384
- part
385
- and part not in _SKIP_DIRS
386
- and part not in _PROJECT_PARENT_DIRS
387
- and not part.startswith('.')
388
- and not part.startswith('/')
389
- and len(part) > 1
390
- ):
391
- return part
392
-
393
- return None
394
-
395
- @staticmethod
396
- def _get_active_profile() -> Optional[str]:
397
- """
398
- Read the active profile name from profiles.json.
399
-
400
- Returns:
401
- Profile name string (e.g., "work", "personal") or None.
402
- """
403
- if not PROFILES_JSON.exists():
404
- return None
405
-
406
- try:
407
- with open(PROFILES_JSON, 'r') as f:
408
- config = json.load(f)
409
- return config.get('active_profile', 'default')
410
- except (json.JSONDecodeError, OSError, KeyError) as e:
411
- logger.debug("Failed to read profiles.json: %s", e)
412
- return None
413
-
414
- def _match_content_to_clusters(
415
- self,
416
- recent_memories: List[Dict[str, Any]],
417
- ) -> Optional[str]:
418
- """
419
- Check if recent memories converge on a single cluster.
420
-
421
- If the most recent 10 memories share a dominant cluster_id, look
422
- up that cluster's name in graph_clusters and cross-reference with
423
- the most common project_name within that cluster.
424
-
425
- Returns:
426
- A project name inferred from cluster dominance, or None.
427
- """
428
- # Collect cluster_ids from the most recent 10 memories
429
- cluster_ids = []
430
- for mem in recent_memories[:10]:
431
- cid = self._safe_get(mem, 'cluster_id')
432
- if cid is not None:
433
- cluster_ids.append(cid)
434
-
435
- if not cluster_ids:
436
- return None
437
-
438
- # Find dominant cluster
439
- cluster_counts = Counter(cluster_ids)
440
- dominant_id, dominant_count = cluster_counts.most_common(1)[0]
441
-
442
- # Require at least 40% dominance (at least 4 out of 10)
443
- if dominant_count < max(2, len(cluster_ids) * 0.4):
444
- return None
445
-
446
- # Look up the dominant project_name within that cluster
447
- return self._get_cluster_dominant_project(dominant_id)
448
-
449
- def _get_cluster_dominant_project(self, cluster_id: int) -> Optional[str]:
450
- """
451
- Find the most common project_name among memories in a given cluster.
452
-
453
- Falls back to the cluster name from graph_clusters if no explicit
454
- project_name is found.
455
- """
456
- if not self._memory_db_path.exists():
457
- return None
458
-
459
- available = self._get_available_columns()
460
-
461
- try:
462
- conn = self._open_memory_db()
463
- try:
464
- cursor = conn.cursor()
465
-
466
- # Try to find the most common project_name in this cluster
467
- if 'project_name' in available and 'cluster_id' in available:
468
- cursor.execute(
469
- "SELECT project_name, COUNT(*) as cnt "
470
- "FROM memories "
471
- "WHERE cluster_id = ? AND project_name IS NOT NULL "
472
- "AND project_name != '' "
473
- "GROUP BY project_name "
474
- "ORDER BY cnt DESC LIMIT 1",
475
- (cluster_id,),
476
- )
477
- row = cursor.fetchone()
478
- if row and row[0]:
479
- return row[0]
480
-
481
- # Fallback: use the cluster name from graph_clusters
482
- try:
483
- cursor.execute(
484
- "SELECT name FROM graph_clusters WHERE id = ?",
485
- (cluster_id,),
486
- )
487
- row = cursor.fetchone()
488
- if row and row[0]:
489
- return row[0]
490
- except sqlite3.OperationalError:
491
- # graph_clusters table may not exist
492
- pass
493
-
494
- return None
495
- finally:
496
- conn.close()
497
- except sqlite3.Error as e:
498
- logger.debug(
499
- "Failed to query cluster %d project: %s", cluster_id, e
500
- )
501
- return None
502
-
503
- # ------------------------------------------------------------------
504
- # Utilities
505
- # ------------------------------------------------------------------
506
-
507
- @staticmethod
508
- def _safe_get(d: Dict[str, Any], key: str) -> Any:
509
- """
510
- Safely get a value from a dict, returning None for missing keys
511
- or empty/whitespace-only strings.
512
- """
513
- val = d.get(key)
514
- if val is None:
515
- return None
516
- if isinstance(val, str) and not val.strip():
517
- return None
518
- return val
519
-
520
- def invalidate_cache(self):
521
- """
522
- Clear the cached column set.
523
-
524
- Call this if the memory.db schema may have changed at runtime
525
- (e.g., after a migration adds new columns).
526
- """
527
- self._available_columns = None
528
-
529
-
530
- # ======================================================================
531
- # Standalone testing
532
- # ======================================================================
533
-
534
- if __name__ == "__main__":
535
- logging.basicConfig(
536
- level=logging.DEBUG,
537
- format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
538
- )
539
-
540
- pcm = ProjectContextManager()
541
-
542
- # Test path extraction
543
- test_paths = [
544
- "/Users/varun/projects/SuperLocalMemoryV2/src/main.py",
545
- "/home/dev/repos/my-app/lib/util.js",
546
- "/workspace/services/auth-service/index.ts",
547
- "/Users/varun/Documents/AGENTIC_Official/SuperLocalMemoryV2-repo/src/learning/foo.py",
548
- "",
549
- None,
550
- ]
551
- print("=== Path Extraction Tests ===")
552
- for p in test_paths:
553
- result = ProjectContextManager._extract_project_from_path(p)
554
- print(f" {p!r:60s} -> {result!r}")
555
-
556
- # Test full detection
557
- print("\n=== Project Detection ===")
558
- project = pcm.detect_current_project()
559
- print(f" Detected project: {project!r}")
560
-
561
- # Test boost
562
- print("\n=== Boost Tests ===")
563
- if project:
564
- test_mem_match = {'project_name': project}
565
- test_mem_miss = {'project_name': 'other-project'}
566
- test_mem_none = {'content': 'no project info'}
567
- print(f" Match boost: {pcm.get_project_boost(test_mem_match, project)}")
568
- print(f" Mismatch boost: {pcm.get_project_boost(test_mem_miss, project)}")
569
- print(f" Unknown boost: {pcm.get_project_boost(test_mem_none, project)}")
570
- else:
571
- print(" No project detected — all boosts return 0.6 (neutral)")
572
- print(f" Neutral boost: {pcm.get_project_boost({}, None)}")
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- Ranking utilities package for AdaptiveRanker.
6
-
7
- Provides constants, helpers, and feature utilities extracted from
8
- the main adaptive_ranker.py module for better maintainability.
9
- """
10
-
11
- from .constants import (
12
- MODELS_DIR,
13
- MODEL_PATH,
14
- PHASE_THRESHOLDS,
15
- MIN_UNIQUE_QUERIES_FOR_ML,
16
- RULE_BOOST,
17
- TRAINING_PARAMS,
18
- )
19
- from .helpers import (
20
- calculate_rule_boost,
21
- prepare_training_data_internal,
22
- )
23
-
24
- __all__ = [
25
- 'MODELS_DIR',
26
- 'MODEL_PATH',
27
- 'PHASE_THRESHOLDS',
28
- 'MIN_UNIQUE_QUERIES_FOR_ML',
29
- 'RULE_BOOST',
30
- 'TRAINING_PARAMS',
31
- 'calculate_rule_boost',
32
- 'prepare_training_data_internal',
33
- ]
@@ -1,84 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- Constants for AdaptiveRanker.
6
-
7
- Includes phase thresholds, rule-based boost multipliers, and LightGBM
8
- training parameters.
9
- """
10
-
11
- from pathlib import Path
12
-
13
- # ============================================================================
14
- # Paths
15
- # ============================================================================
16
-
17
- MODELS_DIR = Path.home() / ".claude-memory" / "models"
18
- MODEL_PATH = MODELS_DIR / "ranker.txt"
19
-
20
- # ============================================================================
21
- # Phase Thresholds
22
- # ============================================================================
23
-
24
- # Phase thresholds — how many feedback signals to trigger each phase
25
- PHASE_THRESHOLDS = {
26
- 'baseline': 0, # 0 feedback samples -> no re-ranking
27
- 'rule_based': 20, # 20+ feedback -> rule-based boosting
28
- 'ml_model': 200, # 200+ feedback across 50+ unique queries -> ML
29
- }
30
-
31
- # Minimum unique queries required for ML phase (prevents overfitting
32
- # to a small number of repeated queries)
33
- MIN_UNIQUE_QUERIES_FOR_ML = 50
34
-
35
- # ============================================================================
36
- # Rule-Based Boost Multipliers (Phase 1)
37
- # ============================================================================
38
-
39
- # These are conservative — they nudge the ranking without flipping order
40
- RULE_BOOST = {
41
- 'tech_match_strong': 1.3, # Memory matches 2+ preferred techs
42
- 'tech_match_weak': 1.1, # Memory matches 1 preferred tech
43
- 'project_match': 1.5, # Memory from current project
44
- 'project_unknown': 1.0, # No project context — no boost
45
- 'project_mismatch': 0.9, # Memory from different project
46
- 'source_quality_high': 1.2, # Source quality > 0.7
47
- 'source_quality_low': 0.85, # Source quality < 0.3
48
- 'recency_boost_max': 1.2, # Recent memory (< 7 days)
49
- 'recency_penalty_max': 0.8, # Old memory (> 365 days)
50
- 'high_importance': 1.15, # Importance >= 8
51
- 'high_access': 1.1, # Accessed 5+ times
52
- # v2.8: Lifecycle + behavioral boosts
53
- 'lifecycle_active': 1.0,
54
- 'lifecycle_warm': 0.85,
55
- 'lifecycle_cold': 0.6,
56
- 'outcome_success_high': 1.3,
57
- 'outcome_failure_high': 0.7,
58
- 'behavioral_match_strong': 1.25,
59
- 'cross_project_boost': 1.15,
60
- 'high_trust_creator': 1.1,
61
- 'low_trust_creator': 0.8,
62
- }
63
-
64
- # ============================================================================
65
- # LightGBM Training Parameters
66
- # ============================================================================
67
-
68
- # LightGBM training parameters — tuned for small, personal datasets
69
- # Aggressive regularization prevents overfitting on < 10K samples
70
- TRAINING_PARAMS = {
71
- 'objective': 'lambdarank',
72
- 'metric': 'ndcg',
73
- 'ndcg_eval_at': [5, 10],
74
- 'learning_rate': 0.05,
75
- 'num_leaves': 16,
76
- 'max_depth': 4,
77
- 'min_child_samples': 10,
78
- 'subsample': 0.8,
79
- 'reg_alpha': 0.1,
80
- 'reg_lambda': 1.0,
81
- 'boosting_type': 'dart',
82
- 'n_estimators': 50,
83
- 'verbose': -1,
84
- }