superlocalmemory 2.8.6 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/LICENSE +9 -1
  2. package/NOTICE +63 -0
  3. package/README.md +165 -480
  4. package/bin/slm +17 -449
  5. package/bin/slm-npm +62 -48
  6. package/conftest.py +5 -0
  7. package/docs/api-reference.md +284 -0
  8. package/docs/architecture.md +149 -0
  9. package/docs/auto-memory.md +150 -0
  10. package/docs/cli-reference.md +276 -0
  11. package/docs/compliance.md +191 -0
  12. package/docs/configuration.md +182 -0
  13. package/docs/getting-started.md +102 -0
  14. package/docs/ide-setup.md +261 -0
  15. package/docs/mcp-tools.md +220 -0
  16. package/docs/migration-from-v2.md +170 -0
  17. package/docs/profiles.md +173 -0
  18. package/docs/troubleshooting.md +310 -0
  19. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  20. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  21. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  22. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  23. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  24. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  25. package/ide/configs/cursor-mcp.json +15 -0
  26. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  27. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  28. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  29. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  30. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  31. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  32. package/{configs → ide/configs}/zed-mcp.json +2 -2
  33. package/{hooks → ide/hooks}/context-hook.js +9 -20
  34. package/ide/hooks/memory-list-skill.js +70 -0
  35. package/ide/hooks/memory-profile-skill.js +101 -0
  36. package/ide/hooks/memory-recall-skill.js +62 -0
  37. package/ide/hooks/memory-remember-skill.js +68 -0
  38. package/ide/hooks/memory-reset-skill.js +160 -0
  39. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  40. package/ide/integrations/langchain/README.md +106 -0
  41. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  42. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  43. package/ide/integrations/langchain/pyproject.toml +38 -0
  44. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  45. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  46. package/ide/integrations/langchain/tests/test_security.py +117 -0
  47. package/ide/integrations/llamaindex/README.md +81 -0
  48. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  49. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  50. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  51. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  52. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  53. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  54. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  55. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  56. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  57. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  58. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  59. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  60. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  61. package/package.json +13 -22
  62. package/pyproject.toml +85 -0
  63. package/scripts/build-dmg.sh +417 -0
  64. package/scripts/install-skills.ps1 +334 -0
  65. package/scripts/postinstall.js +2 -2
  66. package/scripts/start-dashboard.ps1 +52 -0
  67. package/scripts/start-dashboard.sh +41 -0
  68. package/scripts/sync-wiki.ps1 +127 -0
  69. package/scripts/sync-wiki.sh +82 -0
  70. package/scripts/test-dmg.sh +161 -0
  71. package/scripts/test-npm-package.ps1 +252 -0
  72. package/scripts/test-npm-package.sh +207 -0
  73. package/scripts/verify-install.ps1 +294 -0
  74. package/scripts/verify-install.sh +266 -0
  75. package/src/superlocalmemory/__init__.py +0 -0
  76. package/src/superlocalmemory/attribution/__init__.py +9 -0
  77. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  78. package/src/superlocalmemory/attribution/signer.py +153 -0
  79. package/src/superlocalmemory/attribution/watermark.py +189 -0
  80. package/src/superlocalmemory/cli/__init__.py +5 -0
  81. package/src/superlocalmemory/cli/commands.py +245 -0
  82. package/src/superlocalmemory/cli/main.py +89 -0
  83. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  84. package/src/superlocalmemory/cli/post_install.py +99 -0
  85. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  86. package/src/superlocalmemory/compliance/__init__.py +0 -0
  87. package/src/superlocalmemory/compliance/abac.py +204 -0
  88. package/src/superlocalmemory/compliance/audit.py +314 -0
  89. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  90. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  91. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  92. package/src/superlocalmemory/compliance/retention.py +232 -0
  93. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  94. package/src/superlocalmemory/core/__init__.py +0 -0
  95. package/src/superlocalmemory/core/config.py +391 -0
  96. package/src/superlocalmemory/core/embeddings.py +293 -0
  97. package/src/superlocalmemory/core/engine.py +701 -0
  98. package/src/superlocalmemory/core/hooks.py +65 -0
  99. package/src/superlocalmemory/core/maintenance.py +172 -0
  100. package/src/superlocalmemory/core/modes.py +140 -0
  101. package/src/superlocalmemory/core/profiles.py +234 -0
  102. package/src/superlocalmemory/core/registry.py +117 -0
  103. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  104. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  105. package/src/superlocalmemory/encoding/__init__.py +0 -0
  106. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  107. package/src/superlocalmemory/encoding/emotional.py +125 -0
  108. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  109. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  110. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  111. package/src/superlocalmemory/encoding/foresight.py +91 -0
  112. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  113. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  114. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  115. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  116. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  117. package/src/superlocalmemory/encoding/type_router.py +235 -0
  118. package/src/superlocalmemory/hooks/__init__.py +3 -0
  119. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  120. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  121. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  122. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  123. package/src/superlocalmemory/infra/__init__.py +3 -0
  124. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  125. package/src/superlocalmemory/infra/backup.py +317 -0
  126. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  127. package/src/superlocalmemory/infra/event_bus.py +381 -0
  128. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  129. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  130. package/src/superlocalmemory/learning/__init__.py +0 -0
  131. package/src/superlocalmemory/learning/adaptive.py +172 -0
  132. package/src/superlocalmemory/learning/behavioral.py +490 -0
  133. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  134. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  135. package/src/superlocalmemory/learning/cross_project.py +399 -0
  136. package/src/superlocalmemory/learning/database.py +376 -0
  137. package/src/superlocalmemory/learning/engagement.py +323 -0
  138. package/src/superlocalmemory/learning/features.py +138 -0
  139. package/src/superlocalmemory/learning/feedback.py +316 -0
  140. package/src/superlocalmemory/learning/outcomes.py +255 -0
  141. package/src/superlocalmemory/learning/project_context.py +366 -0
  142. package/src/superlocalmemory/learning/ranker.py +155 -0
  143. package/src/superlocalmemory/learning/source_quality.py +303 -0
  144. package/src/superlocalmemory/learning/workflows.py +309 -0
  145. package/src/superlocalmemory/llm/__init__.py +0 -0
  146. package/src/superlocalmemory/llm/backbone.py +316 -0
  147. package/src/superlocalmemory/math/__init__.py +0 -0
  148. package/src/superlocalmemory/math/fisher.py +356 -0
  149. package/src/superlocalmemory/math/langevin.py +398 -0
  150. package/src/superlocalmemory/math/sheaf.py +257 -0
  151. package/src/superlocalmemory/mcp/__init__.py +0 -0
  152. package/src/superlocalmemory/mcp/resources.py +245 -0
  153. package/src/superlocalmemory/mcp/server.py +61 -0
  154. package/src/superlocalmemory/mcp/tools.py +18 -0
  155. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  156. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  157. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  158. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  159. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  160. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  161. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  162. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  163. package/src/superlocalmemory/retrieval/engine.py +390 -0
  164. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  165. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  166. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  167. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  168. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  169. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  170. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  171. package/src/superlocalmemory/server/__init__.py +1 -0
  172. package/src/superlocalmemory/server/api.py +248 -0
  173. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  174. package/src/superlocalmemory/server/routes/agents.py +107 -0
  175. package/src/superlocalmemory/server/routes/backup.py +91 -0
  176. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  177. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  178. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  179. package/src/superlocalmemory/server/routes/events.py +183 -0
  180. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  181. package/src/superlocalmemory/server/routes/learning.py +273 -0
  182. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  183. package/src/superlocalmemory/server/routes/memories.py +399 -0
  184. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  185. package/src/superlocalmemory/server/routes/stats.py +346 -0
  186. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  187. package/src/superlocalmemory/server/routes/ws.py +82 -0
  188. package/src/superlocalmemory/server/security_middleware.py +57 -0
  189. package/src/superlocalmemory/server/ui.py +245 -0
  190. package/src/superlocalmemory/storage/__init__.py +0 -0
  191. package/src/superlocalmemory/storage/access_control.py +182 -0
  192. package/src/superlocalmemory/storage/database.py +594 -0
  193. package/src/superlocalmemory/storage/migrations.py +303 -0
  194. package/src/superlocalmemory/storage/models.py +406 -0
  195. package/src/superlocalmemory/storage/schema.py +726 -0
  196. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  197. package/src/superlocalmemory/trust/__init__.py +0 -0
  198. package/src/superlocalmemory/trust/gate.py +130 -0
  199. package/src/superlocalmemory/trust/provenance.py +124 -0
  200. package/src/superlocalmemory/trust/scorer.py +347 -0
  201. package/src/superlocalmemory/trust/signals.py +153 -0
  202. package/ui/index.html +278 -5
  203. package/ui/js/auto-settings.js +70 -0
  204. package/ui/js/dashboard.js +90 -0
  205. package/ui/js/fact-detail.js +92 -0
  206. package/ui/js/feedback.js +2 -2
  207. package/ui/js/ide-status.js +102 -0
  208. package/ui/js/math-health.js +98 -0
  209. package/ui/js/recall-lab.js +127 -0
  210. package/ui/js/settings.js +2 -2
  211. package/ui/js/trust-dashboard.js +73 -0
  212. package/api_server.py +0 -724
  213. package/bin/aider-smart +0 -72
  214. package/bin/superlocalmemoryv2-learning +0 -4
  215. package/bin/superlocalmemoryv2-list +0 -3
  216. package/bin/superlocalmemoryv2-patterns +0 -4
  217. package/bin/superlocalmemoryv2-profile +0 -3
  218. package/bin/superlocalmemoryv2-recall +0 -3
  219. package/bin/superlocalmemoryv2-remember +0 -3
  220. package/bin/superlocalmemoryv2-reset +0 -3
  221. package/bin/superlocalmemoryv2-status +0 -3
  222. package/configs/chatgpt-desktop-mcp.json +0 -16
  223. package/configs/cursor-mcp.json +0 -15
  224. package/hooks/memory-list-skill.js +0 -139
  225. package/hooks/memory-profile-skill.js +0 -273
  226. package/hooks/memory-recall-skill.js +0 -114
  227. package/hooks/memory-remember-skill.js +0 -127
  228. package/hooks/memory-reset-skill.js +0 -274
  229. package/mcp_server.py +0 -1808
  230. package/requirements-core.txt +0 -22
  231. package/requirements-learning.txt +0 -12
  232. package/requirements.txt +0 -12
  233. package/src/agent_registry.py +0 -411
  234. package/src/auth_middleware.py +0 -61
  235. package/src/auto_backup.py +0 -459
  236. package/src/behavioral/__init__.py +0 -49
  237. package/src/behavioral/behavioral_listener.py +0 -203
  238. package/src/behavioral/behavioral_patterns.py +0 -275
  239. package/src/behavioral/cross_project_transfer.py +0 -206
  240. package/src/behavioral/outcome_inference.py +0 -194
  241. package/src/behavioral/outcome_tracker.py +0 -193
  242. package/src/behavioral/tests/__init__.py +0 -4
  243. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  244. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  245. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  246. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  247. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  248. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  249. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  250. package/src/cache_manager.py +0 -518
  251. package/src/compliance/__init__.py +0 -48
  252. package/src/compliance/abac_engine.py +0 -149
  253. package/src/compliance/abac_middleware.py +0 -116
  254. package/src/compliance/audit_db.py +0 -215
  255. package/src/compliance/audit_logger.py +0 -148
  256. package/src/compliance/retention_manager.py +0 -289
  257. package/src/compliance/retention_scheduler.py +0 -186
  258. package/src/compliance/tests/__init__.py +0 -4
  259. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  260. package/src/compliance/tests/test_abac_engine.py +0 -124
  261. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  262. package/src/compliance/tests/test_audit_db.py +0 -123
  263. package/src/compliance/tests/test_audit_logger.py +0 -98
  264. package/src/compliance/tests/test_mcp_audit.py +0 -128
  265. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  266. package/src/compliance/tests/test_retention_manager.py +0 -131
  267. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  268. package/src/compression/__init__.py +0 -25
  269. package/src/compression/cli.py +0 -150
  270. package/src/compression/cold_storage.py +0 -217
  271. package/src/compression/config.py +0 -72
  272. package/src/compression/orchestrator.py +0 -133
  273. package/src/compression/tier2_compressor.py +0 -228
  274. package/src/compression/tier3_compressor.py +0 -153
  275. package/src/compression/tier_classifier.py +0 -148
  276. package/src/db_connection_manager.py +0 -536
  277. package/src/embedding_engine.py +0 -63
  278. package/src/embeddings/__init__.py +0 -47
  279. package/src/embeddings/cache.py +0 -70
  280. package/src/embeddings/cli.py +0 -113
  281. package/src/embeddings/constants.py +0 -47
  282. package/src/embeddings/database.py +0 -91
  283. package/src/embeddings/engine.py +0 -247
  284. package/src/embeddings/model_loader.py +0 -145
  285. package/src/event_bus.py +0 -562
  286. package/src/graph/__init__.py +0 -36
  287. package/src/graph/build_helpers.py +0 -74
  288. package/src/graph/cli.py +0 -87
  289. package/src/graph/cluster_builder.py +0 -188
  290. package/src/graph/cluster_summary.py +0 -148
  291. package/src/graph/constants.py +0 -47
  292. package/src/graph/edge_builder.py +0 -162
  293. package/src/graph/entity_extractor.py +0 -95
  294. package/src/graph/graph_core.py +0 -226
  295. package/src/graph/graph_search.py +0 -231
  296. package/src/graph/hierarchical.py +0 -207
  297. package/src/graph/schema.py +0 -99
  298. package/src/graph_engine.py +0 -52
  299. package/src/hnsw_index.py +0 -628
  300. package/src/hybrid_search.py +0 -46
  301. package/src/learning/__init__.py +0 -217
  302. package/src/learning/adaptive_ranker.py +0 -682
  303. package/src/learning/bootstrap/__init__.py +0 -69
  304. package/src/learning/bootstrap/constants.py +0 -93
  305. package/src/learning/bootstrap/db_queries.py +0 -316
  306. package/src/learning/bootstrap/sampling.py +0 -82
  307. package/src/learning/bootstrap/text_utils.py +0 -71
  308. package/src/learning/cross_project_aggregator.py +0 -857
  309. package/src/learning/db/__init__.py +0 -40
  310. package/src/learning/db/constants.py +0 -44
  311. package/src/learning/db/schema.py +0 -279
  312. package/src/learning/engagement_tracker.py +0 -628
  313. package/src/learning/feature_extractor.py +0 -708
  314. package/src/learning/feedback_collector.py +0 -806
  315. package/src/learning/learning_db.py +0 -915
  316. package/src/learning/project_context_manager.py +0 -572
  317. package/src/learning/ranking/__init__.py +0 -33
  318. package/src/learning/ranking/constants.py +0 -84
  319. package/src/learning/ranking/helpers.py +0 -278
  320. package/src/learning/source_quality_scorer.py +0 -676
  321. package/src/learning/synthetic_bootstrap.py +0 -755
  322. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  323. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  324. package/src/learning/tests/test_aggregator.py +0 -306
  325. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  326. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  327. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  328. package/src/learning/tests/test_feedback_collector.py +0 -294
  329. package/src/learning/tests/test_learning_db.py +0 -602
  330. package/src/learning/tests/test_learning_db_v28.py +0 -110
  331. package/src/learning/tests/test_learning_init_v28.py +0 -48
  332. package/src/learning/tests/test_outcome_signals.py +0 -48
  333. package/src/learning/tests/test_project_context.py +0 -292
  334. package/src/learning/tests/test_schema_migration.py +0 -319
  335. package/src/learning/tests/test_signal_inference.py +0 -397
  336. package/src/learning/tests/test_source_quality.py +0 -351
  337. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  338. package/src/learning/tests/test_workflow_miner.py +0 -318
  339. package/src/learning/workflow_pattern_miner.py +0 -655
  340. package/src/lifecycle/__init__.py +0 -54
  341. package/src/lifecycle/bounded_growth.py +0 -239
  342. package/src/lifecycle/compaction_engine.py +0 -226
  343. package/src/lifecycle/lifecycle_engine.py +0 -355
  344. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  345. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  346. package/src/lifecycle/retention_policy.py +0 -285
  347. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  348. package/src/lifecycle/tests/test_compaction.py +0 -179
  349. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  350. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  351. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  352. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  353. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  354. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  355. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  356. package/src/mcp_tools_v28.py +0 -281
  357. package/src/memory/__init__.py +0 -36
  358. package/src/memory/cli.py +0 -205
  359. package/src/memory/constants.py +0 -39
  360. package/src/memory/helpers.py +0 -28
  361. package/src/memory/schema.py +0 -166
  362. package/src/memory-profiles.py +0 -595
  363. package/src/memory-reset.py +0 -491
  364. package/src/memory_compression.py +0 -989
  365. package/src/memory_store_v2.py +0 -1155
  366. package/src/migrate_v1_to_v2.py +0 -629
  367. package/src/pattern_learner.py +0 -34
  368. package/src/patterns/__init__.py +0 -24
  369. package/src/patterns/analyzers.py +0 -251
  370. package/src/patterns/learner.py +0 -271
  371. package/src/patterns/scoring.py +0 -171
  372. package/src/patterns/store.py +0 -225
  373. package/src/patterns/terminology.py +0 -140
  374. package/src/provenance_tracker.py +0 -312
  375. package/src/qualixar_attribution.py +0 -139
  376. package/src/qualixar_watermark.py +0 -78
  377. package/src/query_optimizer.py +0 -511
  378. package/src/rate_limiter.py +0 -83
  379. package/src/search/__init__.py +0 -20
  380. package/src/search/cli.py +0 -77
  381. package/src/search/constants.py +0 -26
  382. package/src/search/engine.py +0 -241
  383. package/src/search/fusion.py +0 -122
  384. package/src/search/index_loader.py +0 -114
  385. package/src/search/methods.py +0 -162
  386. package/src/search_engine_v2.py +0 -401
  387. package/src/setup_validator.py +0 -482
  388. package/src/subscription_manager.py +0 -391
  389. package/src/tree/__init__.py +0 -59
  390. package/src/tree/builder.py +0 -185
  391. package/src/tree/nodes.py +0 -202
  392. package/src/tree/queries.py +0 -257
  393. package/src/tree/schema.py +0 -80
  394. package/src/tree_manager.py +0 -19
  395. package/src/trust/__init__.py +0 -45
  396. package/src/trust/constants.py +0 -66
  397. package/src/trust/queries.py +0 -157
  398. package/src/trust/schema.py +0 -95
  399. package/src/trust/scorer.py +0 -299
  400. package/src/trust/signals.py +0 -95
  401. package/src/trust_scorer.py +0 -44
  402. package/ui/app.js +0 -1588
  403. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  404. package/ui/js/graph-cytoscape.js +0 -1168
  405. package/ui/js/graph-d3-backup.js +0 -32
  406. package/ui/js/graph.js +0 -32
  407. package/ui_server.py +0 -286
  408. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  409. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  410. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  411. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  412. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  413. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  414. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  415. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  416. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  417. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  418. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  419. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  420. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  421. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  422. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  423. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  424. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  425. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  426. /package/{completions → ide/completions}/slm.bash +0 -0
  427. /package/{completions → ide/completions}/slm.zsh +0 -0
  428. /package/{configs → ide/configs}/cody-commands.json +0 -0
  429. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
  430. /package/{install.ps1 → scripts/install.ps1} +0 -0
  431. /package/{install.sh → scripts/install.sh} +0 -0
@@ -1,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
- }