superlocalmemory 2.8.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +9 -1
  3. package/NOTICE +63 -0
  4. package/README.md +165 -480
  5. package/bin/slm +17 -449
  6. package/bin/slm-npm +2 -2
  7. package/bin/slm.bat +4 -2
  8. package/conftest.py +5 -0
  9. package/docs/api-reference.md +284 -0
  10. package/docs/architecture.md +149 -0
  11. package/docs/auto-memory.md +150 -0
  12. package/docs/cli-reference.md +276 -0
  13. package/docs/compliance.md +191 -0
  14. package/docs/configuration.md +182 -0
  15. package/docs/getting-started.md +102 -0
  16. package/docs/ide-setup.md +261 -0
  17. package/docs/mcp-tools.md +220 -0
  18. package/docs/migration-from-v2.md +170 -0
  19. package/docs/profiles.md +173 -0
  20. package/docs/troubleshooting.md +310 -0
  21. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  22. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  23. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  24. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  25. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  26. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  27. package/ide/configs/cursor-mcp.json +15 -0
  28. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  29. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  30. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  31. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  32. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  33. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  34. package/{configs → ide/configs}/zed-mcp.json +2 -2
  35. package/{hooks → ide/hooks}/context-hook.js +9 -20
  36. package/ide/hooks/memory-list-skill.js +70 -0
  37. package/ide/hooks/memory-profile-skill.js +101 -0
  38. package/ide/hooks/memory-recall-skill.js +62 -0
  39. package/ide/hooks/memory-remember-skill.js +68 -0
  40. package/ide/hooks/memory-reset-skill.js +160 -0
  41. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  42. package/ide/integrations/langchain/README.md +106 -0
  43. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  44. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  45. package/ide/integrations/langchain/pyproject.toml +38 -0
  46. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  47. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  48. package/ide/integrations/langchain/tests/test_security.py +117 -0
  49. package/ide/integrations/llamaindex/README.md +81 -0
  50. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  51. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  52. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  53. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  54. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  55. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  56. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  57. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  58. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  59. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  60. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  61. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  62. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  63. package/package.json +13 -22
  64. package/pyproject.toml +85 -0
  65. package/scripts/build-dmg.sh +417 -0
  66. package/scripts/install-skills.ps1 +334 -0
  67. package/{install.ps1 → scripts/install.ps1} +36 -4
  68. package/{install.sh → scripts/install.sh} +14 -13
  69. package/scripts/postinstall.js +2 -2
  70. package/scripts/start-dashboard.ps1 +52 -0
  71. package/scripts/start-dashboard.sh +41 -0
  72. package/scripts/sync-wiki.ps1 +127 -0
  73. package/scripts/sync-wiki.sh +82 -0
  74. package/scripts/test-dmg.sh +161 -0
  75. package/scripts/test-npm-package.ps1 +252 -0
  76. package/scripts/test-npm-package.sh +207 -0
  77. package/scripts/verify-install.ps1 +294 -0
  78. package/scripts/verify-install.sh +266 -0
  79. package/src/superlocalmemory/__init__.py +0 -0
  80. package/src/superlocalmemory/attribution/__init__.py +9 -0
  81. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  82. package/src/superlocalmemory/attribution/signer.py +153 -0
  83. package/src/superlocalmemory/attribution/watermark.py +189 -0
  84. package/src/superlocalmemory/cli/__init__.py +5 -0
  85. package/src/superlocalmemory/cli/commands.py +245 -0
  86. package/src/superlocalmemory/cli/main.py +89 -0
  87. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  88. package/src/superlocalmemory/cli/post_install.py +99 -0
  89. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  90. package/src/superlocalmemory/compliance/__init__.py +0 -0
  91. package/src/superlocalmemory/compliance/abac.py +204 -0
  92. package/src/superlocalmemory/compliance/audit.py +314 -0
  93. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  94. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  95. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  96. package/src/superlocalmemory/compliance/retention.py +232 -0
  97. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  98. package/src/superlocalmemory/core/__init__.py +0 -0
  99. package/src/superlocalmemory/core/config.py +391 -0
  100. package/src/superlocalmemory/core/embeddings.py +293 -0
  101. package/src/superlocalmemory/core/engine.py +701 -0
  102. package/src/superlocalmemory/core/hooks.py +65 -0
  103. package/src/superlocalmemory/core/maintenance.py +172 -0
  104. package/src/superlocalmemory/core/modes.py +140 -0
  105. package/src/superlocalmemory/core/profiles.py +234 -0
  106. package/src/superlocalmemory/core/registry.py +117 -0
  107. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  108. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  109. package/src/superlocalmemory/encoding/__init__.py +0 -0
  110. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  111. package/src/superlocalmemory/encoding/emotional.py +125 -0
  112. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  113. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  114. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  115. package/src/superlocalmemory/encoding/foresight.py +91 -0
  116. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  117. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  118. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  119. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  120. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  121. package/src/superlocalmemory/encoding/type_router.py +235 -0
  122. package/src/superlocalmemory/hooks/__init__.py +3 -0
  123. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  124. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  125. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  126. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  127. package/src/superlocalmemory/infra/__init__.py +3 -0
  128. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  129. package/src/superlocalmemory/infra/backup.py +317 -0
  130. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  131. package/src/superlocalmemory/infra/event_bus.py +381 -0
  132. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  133. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  134. package/src/superlocalmemory/learning/__init__.py +0 -0
  135. package/src/superlocalmemory/learning/adaptive.py +172 -0
  136. package/src/superlocalmemory/learning/behavioral.py +490 -0
  137. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  138. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  139. package/src/superlocalmemory/learning/cross_project.py +399 -0
  140. package/src/superlocalmemory/learning/database.py +376 -0
  141. package/src/superlocalmemory/learning/engagement.py +323 -0
  142. package/src/superlocalmemory/learning/features.py +138 -0
  143. package/src/superlocalmemory/learning/feedback.py +316 -0
  144. package/src/superlocalmemory/learning/outcomes.py +255 -0
  145. package/src/superlocalmemory/learning/project_context.py +366 -0
  146. package/src/superlocalmemory/learning/ranker.py +155 -0
  147. package/src/superlocalmemory/learning/source_quality.py +303 -0
  148. package/src/superlocalmemory/learning/workflows.py +309 -0
  149. package/src/superlocalmemory/llm/__init__.py +0 -0
  150. package/src/superlocalmemory/llm/backbone.py +316 -0
  151. package/src/superlocalmemory/math/__init__.py +0 -0
  152. package/src/superlocalmemory/math/fisher.py +356 -0
  153. package/src/superlocalmemory/math/langevin.py +398 -0
  154. package/src/superlocalmemory/math/sheaf.py +257 -0
  155. package/src/superlocalmemory/mcp/__init__.py +0 -0
  156. package/src/superlocalmemory/mcp/resources.py +245 -0
  157. package/src/superlocalmemory/mcp/server.py +61 -0
  158. package/src/superlocalmemory/mcp/tools.py +18 -0
  159. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  160. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  161. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  162. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  163. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  164. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  165. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  166. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  167. package/src/superlocalmemory/retrieval/engine.py +390 -0
  168. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  169. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  170. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  171. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  172. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  173. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  174. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  175. package/src/superlocalmemory/server/__init__.py +1 -0
  176. package/src/superlocalmemory/server/api.py +248 -0
  177. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  178. package/src/superlocalmemory/server/routes/agents.py +107 -0
  179. package/src/superlocalmemory/server/routes/backup.py +91 -0
  180. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  181. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  182. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  183. package/src/superlocalmemory/server/routes/events.py +183 -0
  184. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  185. package/src/superlocalmemory/server/routes/learning.py +273 -0
  186. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  187. package/src/superlocalmemory/server/routes/memories.py +399 -0
  188. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  189. package/src/superlocalmemory/server/routes/stats.py +346 -0
  190. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  191. package/src/superlocalmemory/server/routes/ws.py +82 -0
  192. package/src/superlocalmemory/server/security_middleware.py +57 -0
  193. package/src/superlocalmemory/server/ui.py +245 -0
  194. package/src/superlocalmemory/storage/__init__.py +0 -0
  195. package/src/superlocalmemory/storage/access_control.py +182 -0
  196. package/src/superlocalmemory/storage/database.py +594 -0
  197. package/src/superlocalmemory/storage/migrations.py +303 -0
  198. package/src/superlocalmemory/storage/models.py +406 -0
  199. package/src/superlocalmemory/storage/schema.py +726 -0
  200. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  201. package/src/superlocalmemory/trust/__init__.py +0 -0
  202. package/src/superlocalmemory/trust/gate.py +130 -0
  203. package/src/superlocalmemory/trust/provenance.py +124 -0
  204. package/src/superlocalmemory/trust/scorer.py +347 -0
  205. package/src/superlocalmemory/trust/signals.py +153 -0
  206. package/ui/index.html +278 -5
  207. package/ui/js/auto-settings.js +70 -0
  208. package/ui/js/dashboard.js +90 -0
  209. package/ui/js/fact-detail.js +92 -0
  210. package/ui/js/feedback.js +2 -2
  211. package/ui/js/ide-status.js +102 -0
  212. package/ui/js/math-health.js +98 -0
  213. package/ui/js/recall-lab.js +127 -0
  214. package/ui/js/settings.js +2 -2
  215. package/ui/js/trust-dashboard.js +73 -0
  216. package/api_server.py +0 -724
  217. package/bin/aider-smart +0 -72
  218. package/bin/superlocalmemoryv2-learning +0 -4
  219. package/bin/superlocalmemoryv2-list +0 -3
  220. package/bin/superlocalmemoryv2-patterns +0 -4
  221. package/bin/superlocalmemoryv2-profile +0 -3
  222. package/bin/superlocalmemoryv2-recall +0 -3
  223. package/bin/superlocalmemoryv2-remember +0 -3
  224. package/bin/superlocalmemoryv2-reset +0 -3
  225. package/bin/superlocalmemoryv2-status +0 -3
  226. package/configs/chatgpt-desktop-mcp.json +0 -16
  227. package/configs/cursor-mcp.json +0 -15
  228. package/docs/SECURITY-QUICK-REFERENCE.md +0 -214
  229. package/hooks/memory-list-skill.js +0 -139
  230. package/hooks/memory-profile-skill.js +0 -273
  231. package/hooks/memory-recall-skill.js +0 -114
  232. package/hooks/memory-remember-skill.js +0 -127
  233. package/hooks/memory-reset-skill.js +0 -274
  234. package/mcp_server.py +0 -1800
  235. package/requirements-core.txt +0 -22
  236. package/requirements-learning.txt +0 -12
  237. package/requirements.txt +0 -12
  238. package/src/agent_registry.py +0 -411
  239. package/src/auth_middleware.py +0 -61
  240. package/src/auto_backup.py +0 -459
  241. package/src/behavioral/__init__.py +0 -49
  242. package/src/behavioral/behavioral_listener.py +0 -203
  243. package/src/behavioral/behavioral_patterns.py +0 -275
  244. package/src/behavioral/cross_project_transfer.py +0 -206
  245. package/src/behavioral/outcome_inference.py +0 -194
  246. package/src/behavioral/outcome_tracker.py +0 -193
  247. package/src/behavioral/tests/__init__.py +0 -4
  248. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  249. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  250. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  251. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  252. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  253. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  254. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  255. package/src/cache_manager.py +0 -518
  256. package/src/compliance/__init__.py +0 -48
  257. package/src/compliance/abac_engine.py +0 -149
  258. package/src/compliance/abac_middleware.py +0 -116
  259. package/src/compliance/audit_db.py +0 -215
  260. package/src/compliance/audit_logger.py +0 -148
  261. package/src/compliance/retention_manager.py +0 -289
  262. package/src/compliance/retention_scheduler.py +0 -186
  263. package/src/compliance/tests/__init__.py +0 -4
  264. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  265. package/src/compliance/tests/test_abac_engine.py +0 -124
  266. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  267. package/src/compliance/tests/test_audit_db.py +0 -123
  268. package/src/compliance/tests/test_audit_logger.py +0 -98
  269. package/src/compliance/tests/test_mcp_audit.py +0 -128
  270. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  271. package/src/compliance/tests/test_retention_manager.py +0 -131
  272. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  273. package/src/compression/__init__.py +0 -25
  274. package/src/compression/cli.py +0 -150
  275. package/src/compression/cold_storage.py +0 -217
  276. package/src/compression/config.py +0 -72
  277. package/src/compression/orchestrator.py +0 -133
  278. package/src/compression/tier2_compressor.py +0 -228
  279. package/src/compression/tier3_compressor.py +0 -153
  280. package/src/compression/tier_classifier.py +0 -148
  281. package/src/db_connection_manager.py +0 -536
  282. package/src/embedding_engine.py +0 -63
  283. package/src/embeddings/__init__.py +0 -47
  284. package/src/embeddings/cache.py +0 -70
  285. package/src/embeddings/cli.py +0 -113
  286. package/src/embeddings/constants.py +0 -47
  287. package/src/embeddings/database.py +0 -91
  288. package/src/embeddings/engine.py +0 -247
  289. package/src/embeddings/model_loader.py +0 -145
  290. package/src/event_bus.py +0 -562
  291. package/src/graph/__init__.py +0 -36
  292. package/src/graph/build_helpers.py +0 -74
  293. package/src/graph/cli.py +0 -87
  294. package/src/graph/cluster_builder.py +0 -188
  295. package/src/graph/cluster_summary.py +0 -148
  296. package/src/graph/constants.py +0 -47
  297. package/src/graph/edge_builder.py +0 -162
  298. package/src/graph/entity_extractor.py +0 -95
  299. package/src/graph/graph_core.py +0 -226
  300. package/src/graph/graph_search.py +0 -231
  301. package/src/graph/hierarchical.py +0 -207
  302. package/src/graph/schema.py +0 -99
  303. package/src/graph_engine.py +0 -52
  304. package/src/hnsw_index.py +0 -628
  305. package/src/hybrid_search.py +0 -46
  306. package/src/learning/__init__.py +0 -217
  307. package/src/learning/adaptive_ranker.py +0 -682
  308. package/src/learning/bootstrap/__init__.py +0 -69
  309. package/src/learning/bootstrap/constants.py +0 -93
  310. package/src/learning/bootstrap/db_queries.py +0 -316
  311. package/src/learning/bootstrap/sampling.py +0 -82
  312. package/src/learning/bootstrap/text_utils.py +0 -71
  313. package/src/learning/cross_project_aggregator.py +0 -857
  314. package/src/learning/db/__init__.py +0 -40
  315. package/src/learning/db/constants.py +0 -44
  316. package/src/learning/db/schema.py +0 -279
  317. package/src/learning/engagement_tracker.py +0 -628
  318. package/src/learning/feature_extractor.py +0 -708
  319. package/src/learning/feedback_collector.py +0 -806
  320. package/src/learning/learning_db.py +0 -915
  321. package/src/learning/project_context_manager.py +0 -572
  322. package/src/learning/ranking/__init__.py +0 -33
  323. package/src/learning/ranking/constants.py +0 -84
  324. package/src/learning/ranking/helpers.py +0 -278
  325. package/src/learning/source_quality_scorer.py +0 -676
  326. package/src/learning/synthetic_bootstrap.py +0 -755
  327. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  328. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  329. package/src/learning/tests/test_aggregator.py +0 -306
  330. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  331. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  332. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  333. package/src/learning/tests/test_feedback_collector.py +0 -294
  334. package/src/learning/tests/test_learning_db.py +0 -602
  335. package/src/learning/tests/test_learning_db_v28.py +0 -110
  336. package/src/learning/tests/test_learning_init_v28.py +0 -48
  337. package/src/learning/tests/test_outcome_signals.py +0 -48
  338. package/src/learning/tests/test_project_context.py +0 -292
  339. package/src/learning/tests/test_schema_migration.py +0 -319
  340. package/src/learning/tests/test_signal_inference.py +0 -397
  341. package/src/learning/tests/test_source_quality.py +0 -351
  342. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  343. package/src/learning/tests/test_workflow_miner.py +0 -318
  344. package/src/learning/workflow_pattern_miner.py +0 -655
  345. package/src/lifecycle/__init__.py +0 -54
  346. package/src/lifecycle/bounded_growth.py +0 -239
  347. package/src/lifecycle/compaction_engine.py +0 -226
  348. package/src/lifecycle/lifecycle_engine.py +0 -355
  349. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  350. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  351. package/src/lifecycle/retention_policy.py +0 -285
  352. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  353. package/src/lifecycle/tests/test_compaction.py +0 -179
  354. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  355. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  356. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  357. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  358. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  359. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  360. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  361. package/src/mcp_tools_v28.py +0 -281
  362. package/src/memory/__init__.py +0 -36
  363. package/src/memory/cli.py +0 -205
  364. package/src/memory/constants.py +0 -39
  365. package/src/memory/helpers.py +0 -28
  366. package/src/memory/schema.py +0 -166
  367. package/src/memory-profiles.py +0 -595
  368. package/src/memory-reset.py +0 -491
  369. package/src/memory_compression.py +0 -989
  370. package/src/memory_store_v2.py +0 -1155
  371. package/src/migrate_v1_to_v2.py +0 -629
  372. package/src/pattern_learner.py +0 -34
  373. package/src/patterns/__init__.py +0 -24
  374. package/src/patterns/analyzers.py +0 -251
  375. package/src/patterns/learner.py +0 -271
  376. package/src/patterns/scoring.py +0 -171
  377. package/src/patterns/store.py +0 -225
  378. package/src/patterns/terminology.py +0 -140
  379. package/src/provenance_tracker.py +0 -312
  380. package/src/qualixar_attribution.py +0 -139
  381. package/src/qualixar_watermark.py +0 -78
  382. package/src/query_optimizer.py +0 -511
  383. package/src/rate_limiter.py +0 -83
  384. package/src/search/__init__.py +0 -20
  385. package/src/search/cli.py +0 -77
  386. package/src/search/constants.py +0 -26
  387. package/src/search/engine.py +0 -241
  388. package/src/search/fusion.py +0 -122
  389. package/src/search/index_loader.py +0 -114
  390. package/src/search/methods.py +0 -162
  391. package/src/search_engine_v2.py +0 -401
  392. package/src/setup_validator.py +0 -482
  393. package/src/subscription_manager.py +0 -391
  394. package/src/tree/__init__.py +0 -59
  395. package/src/tree/builder.py +0 -185
  396. package/src/tree/nodes.py +0 -202
  397. package/src/tree/queries.py +0 -257
  398. package/src/tree/schema.py +0 -80
  399. package/src/tree_manager.py +0 -19
  400. package/src/trust/__init__.py +0 -45
  401. package/src/trust/constants.py +0 -66
  402. package/src/trust/queries.py +0 -157
  403. package/src/trust/schema.py +0 -95
  404. package/src/trust/scorer.py +0 -299
  405. package/src/trust/signals.py +0 -95
  406. package/src/trust_scorer.py +0 -44
  407. package/ui/app.js +0 -1588
  408. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  409. package/ui/js/graph-cytoscape.js +0 -1168
  410. package/ui/js/graph-d3-backup.js +0 -32
  411. package/ui/js/graph.js +0 -32
  412. package/ui_server.py +0 -266
  413. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  414. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  415. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  416. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  417. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  418. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  419. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  420. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  421. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  422. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  423. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  424. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  425. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  426. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  427. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  428. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  429. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  430. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  431. /package/{completions → ide/completions}/slm.bash +0 -0
  432. /package/{completions → ide/completions}/slm.zsh +0 -0
  433. /package/{configs → ide/configs}/cody-commands.json +0 -0
  434. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
@@ -0,0 +1,235 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """SuperLocalMemory V3 — Typed Memory Router.
6
+
7
+ Routes extracted facts to appropriate typed stores (ENGRAM pattern).
8
+ Typed separation gave +31 points on LoCoMo benchmark.
9
+
10
+ Mode A: all-MiniLM similarity against type templates.
11
+ Mode B/C: LLM classifies fact type.
12
+
13
+ Part of Qualixar | Author: Varun Pratap Bhardwaj
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import logging
19
+ import re
20
+ from typing import TYPE_CHECKING
21
+
22
+ from superlocalmemory.storage.models import AtomicFact, FactType, Mode
23
+
24
+ if TYPE_CHECKING:
25
+ from superlocalmemory.core.embeddings import EmbeddingService
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ # ---------------------------------------------------------------------------
30
+ # Type templates for Mode A (all-MiniLM classification)
31
+ # ---------------------------------------------------------------------------
32
+
33
+ _EPISODIC_TEMPLATES = [
34
+ "someone did something at a place",
35
+ "a person went somewhere or performed an action",
36
+ "an event happened on a specific date",
37
+ "someone traveled to a location",
38
+ "a meeting or gathering occurred",
39
+ ]
40
+
41
+ _SEMANTIC_TEMPLATES = [
42
+ "a person is a specific profession or role",
43
+ "something is a fact about the world",
44
+ "a place is located somewhere",
45
+ "an organization does something",
46
+ "a general knowledge statement",
47
+ ]
48
+
49
+ _OPINION_TEMPLATES = [
50
+ "someone thinks or believes something",
51
+ "a person likes or dislikes something",
52
+ "someone prefers one thing over another",
53
+ "a subjective judgment or evaluation",
54
+ "an emotional reaction to something",
55
+ ]
56
+
57
+ _TEMPORAL_TEMPLATES = [
58
+ "something will happen on a future date",
59
+ "an event is scheduled or planned",
60
+ "a deadline or due date for something",
61
+ "something started or will end at a time",
62
+ "a recurring event or appointment",
63
+ ]
64
+
65
+ # ---------------------------------------------------------------------------
66
+ # Keyword patterns for Mode A fallback
67
+ # ---------------------------------------------------------------------------
68
+
69
+ _OPINION_MARKERS = re.compile(
70
+ r"\b(think|believe|feel|prefer|like|love|hate|dislike|enjoy|"
71
+ r"opinion|seems?|probably|maybe|might|could be|i guess|"
72
+ r"personally|in my view|i'd say)\b",
73
+ re.IGNORECASE,
74
+ )
75
+
76
+ _TEMPORAL_MARKERS = re.compile(
77
+ r"\b(scheduled|deadline|appointment|planned|tomorrow|"
78
+ r"next week|next month|upcoming|due date|starts?|ends?|"
79
+ r"will happen|going to|plan to)\b",
80
+ re.IGNORECASE,
81
+ )
82
+
83
+ _EPISODIC_MARKERS = re.compile(
84
+ r"\b(went|visited|traveled|attended|met|saw|did|"
85
+ r"happened|occurred|took place|experienced)\b",
86
+ re.IGNORECASE,
87
+ )
88
+
89
+
90
+ class TypeRouter:
91
+ """Route facts to typed stores based on content classification.
92
+
93
+ Uses embedding similarity (Mode A) or LLM (Mode B/C) to classify
94
+ each fact as episodic, semantic, opinion, or temporal.
95
+ """
96
+
97
+ def __init__(
98
+ self,
99
+ mode: Mode = Mode.A,
100
+ embedder: EmbeddingService | None = None,
101
+ llm: object | None = None,
102
+ ) -> None:
103
+ self._mode = mode
104
+ self._embedder = embedder
105
+ self._llm = llm
106
+ self._template_embeddings: dict[FactType, list[list[float]]] | None = None
107
+
108
+ def classify(self, fact: AtomicFact) -> FactType:
109
+ """Classify a fact into a typed store category."""
110
+ if self._mode in (Mode.B, Mode.C) and self._llm is not None:
111
+ return self._classify_llm(fact)
112
+ if self._embedder is not None:
113
+ return self._classify_embedding(fact)
114
+ return self._classify_keywords(fact)
115
+
116
+ def route_facts(self, facts: list[AtomicFact]) -> list[AtomicFact]:
117
+ """Classify and update fact_type for a batch of facts."""
118
+ result = []
119
+ for fact in facts:
120
+ classified_type = self.classify(fact)
121
+ # Create new fact with updated type (immutability pattern)
122
+ updated = AtomicFact(
123
+ fact_id=fact.fact_id,
124
+ memory_id=fact.memory_id,
125
+ profile_id=fact.profile_id,
126
+ content=fact.content,
127
+ fact_type=classified_type,
128
+ entities=fact.entities,
129
+ canonical_entities=fact.canonical_entities,
130
+ observation_date=fact.observation_date,
131
+ referenced_date=fact.referenced_date,
132
+ interval_start=fact.interval_start,
133
+ interval_end=fact.interval_end,
134
+ confidence=fact.confidence,
135
+ importance=fact.importance,
136
+ evidence_count=fact.evidence_count,
137
+ source_turn_ids=fact.source_turn_ids,
138
+ session_id=fact.session_id,
139
+ embedding=fact.embedding,
140
+ fisher_mean=fact.fisher_mean,
141
+ fisher_variance=fact.fisher_variance,
142
+ emotional_valence=fact.emotional_valence,
143
+ emotional_arousal=fact.emotional_arousal,
144
+ signal_type=fact.signal_type,
145
+ created_at=fact.created_at,
146
+ )
147
+ result.append(updated)
148
+ return result
149
+
150
+ # -- Classification strategies -----------------------------------------
151
+
152
+ def _classify_keywords(self, fact: AtomicFact) -> FactType:
153
+ """Keyword-based classification (fastest, lowest quality)."""
154
+ text = fact.content
155
+
156
+ if _OPINION_MARKERS.search(text):
157
+ return FactType.OPINION
158
+ if _TEMPORAL_MARKERS.search(text):
159
+ return FactType.TEMPORAL
160
+ if _EPISODIC_MARKERS.search(text):
161
+ return FactType.EPISODIC
162
+ return FactType.SEMANTIC
163
+
164
+ def _classify_embedding(self, fact: AtomicFact) -> FactType:
165
+ """Embedding similarity against type templates (Mode A)."""
166
+ if self._embedder is None:
167
+ return self._classify_keywords(fact)
168
+
169
+ if self._template_embeddings is None:
170
+ self._build_template_embeddings()
171
+
172
+ assert self._template_embeddings is not None
173
+ fact_emb = self._embedder.embed(fact.content)
174
+
175
+ best_type = FactType.SEMANTIC
176
+ best_score = -1.0
177
+
178
+ for ftype, template_embs in self._template_embeddings.items():
179
+ avg_sim = sum(
180
+ _cosine(fact_emb, t) for t in template_embs
181
+ ) / max(len(template_embs), 1)
182
+ if avg_sim > best_score:
183
+ best_score = avg_sim
184
+ best_type = ftype
185
+
186
+ return best_type
187
+
188
+ def _classify_llm(self, fact: AtomicFact) -> FactType:
189
+ """LLM-based classification (Mode B/C, highest quality)."""
190
+ if self._llm is None:
191
+ return self._classify_embedding(fact)
192
+
193
+ prompt = (
194
+ f"Classify this fact into exactly one category.\n"
195
+ f"Fact: \"{fact.content}\"\n"
196
+ f"Categories:\n"
197
+ f"- episodic: An event that happened (who did what when)\n"
198
+ f"- semantic: A general fact about the world (X is Y)\n"
199
+ f"- opinion: A subjective belief or preference\n"
200
+ f"- temporal: A scheduled/planned future event\n"
201
+ f"Reply with ONLY the category name (one word)."
202
+ )
203
+ try:
204
+ response = self._llm.generate(prompt).strip().lower()
205
+ type_map = {
206
+ "episodic": FactType.EPISODIC,
207
+ "semantic": FactType.SEMANTIC,
208
+ "opinion": FactType.OPINION,
209
+ "temporal": FactType.TEMPORAL,
210
+ }
211
+ return type_map.get(response, FactType.SEMANTIC)
212
+ except Exception:
213
+ logger.warning("LLM classification failed, falling back to keywords")
214
+ return self._classify_keywords(fact)
215
+
216
+ def _build_template_embeddings(self) -> None:
217
+ """Pre-compute embeddings for type templates."""
218
+ if self._embedder is None:
219
+ return
220
+ self._template_embeddings = {
221
+ FactType.EPISODIC: self._embedder.embed_batch(_EPISODIC_TEMPLATES),
222
+ FactType.SEMANTIC: self._embedder.embed_batch(_SEMANTIC_TEMPLATES),
223
+ FactType.OPINION: self._embedder.embed_batch(_OPINION_TEMPLATES),
224
+ FactType.TEMPORAL: self._embedder.embed_batch(_TEMPORAL_TEMPLATES),
225
+ }
226
+
227
+
228
+ def _cosine(a: list[float], b: list[float]) -> float:
229
+ """Cosine similarity between two vectors."""
230
+ dot = sum(x * y for x, y in zip(a, b))
231
+ norm_a = sum(x * x for x in a) ** 0.5
232
+ norm_b = sum(x * x for x in b) ** 0.5
233
+ if norm_a == 0 or norm_b == 0:
234
+ return 0.0
235
+ return dot / (norm_a * norm_b)
@@ -0,0 +1,3 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
@@ -0,0 +1,111 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """Auto-capture — detect and store important information automatically."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ import re
11
+ from dataclasses import dataclass
12
+ from typing import Any
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Patterns that indicate capture-worthy content
17
+ _DECISION_PATTERNS = [
18
+ r"(?i)\b(decided|chose|picked|selected|went with|using|switched to)\b",
19
+ r"(?i)\b(because|reason|rationale|due to|since)\b.*\b(chose|use|prefer)\b",
20
+ ]
21
+
22
+ _BUG_PATTERNS = [
23
+ r"(?i)\b(fixed|resolved|solved|root cause|bug|issue|error)\b",
24
+ r"(?i)\b(the (?:fix|solution|problem) (?:was|is))\b",
25
+ ]
26
+
27
+ _PREFERENCE_PATTERNS = [
28
+ r"(?i)\b(prefer|always use|never use|I like|I hate|don't like)\b",
29
+ r"(?i)\b(convention|standard|style|pattern)\b.*\b(is|should be|must be)\b",
30
+ ]
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class CaptureDecision:
35
+ """Result of evaluating content for auto-capture."""
36
+
37
+ capture: bool
38
+ confidence: float
39
+ category: str # "decision", "bug", "preference", "session_summary", "none"
40
+ reason: str
41
+
42
+
43
+ class AutoCapture:
44
+ """Detect and classify content for automatic storage."""
45
+
46
+ def __init__(self, engine=None, config: dict | None = None):
47
+ self._engine = engine
48
+ self._config = config or {}
49
+ self._enabled = self._config.get("enabled", True)
50
+ self._min_confidence = self._config.get("min_confidence", 0.5)
51
+ self._capture_decisions = self._config.get("capture_decisions", True)
52
+ self._capture_bugs = self._config.get("capture_bugs", True)
53
+ self._capture_preferences = self._config.get("capture_preferences", True)
54
+
55
+ def evaluate(self, content: str) -> CaptureDecision:
56
+ """Evaluate whether content should be auto-captured.
57
+
58
+ Returns a CaptureDecision with capture=True/False,
59
+ confidence score, and category.
60
+ """
61
+ if not self._enabled:
62
+ return CaptureDecision(False, 0.0, "none", "auto-capture disabled")
63
+
64
+ if len(content.strip()) < 20:
65
+ return CaptureDecision(False, 0.0, "none", "content too short")
66
+
67
+ # Check for decisions
68
+ if self._capture_decisions:
69
+ score = self._match_patterns(content, _DECISION_PATTERNS)
70
+ if score >= self._min_confidence:
71
+ return CaptureDecision(True, score, "decision", "decision pattern detected")
72
+
73
+ # Check for bug fixes
74
+ if self._capture_bugs:
75
+ score = self._match_patterns(content, _BUG_PATTERNS)
76
+ if score >= self._min_confidence:
77
+ return CaptureDecision(True, score, "bug", "bug fix pattern detected")
78
+
79
+ # Check for preferences
80
+ if self._capture_preferences:
81
+ score = self._match_patterns(content, _PREFERENCE_PATTERNS)
82
+ if score >= self._min_confidence:
83
+ return CaptureDecision(True, score, "preference", "preference pattern detected")
84
+
85
+ return CaptureDecision(False, 0.0, "none", "no patterns matched")
86
+
87
+ def capture(self, content: str, category: str = "", metadata: dict | None = None) -> bool:
88
+ """Store content via engine if auto-capture decides to."""
89
+ if not self._engine:
90
+ return False
91
+
92
+ try:
93
+ meta = metadata or {}
94
+ meta["source"] = "auto-capture"
95
+ meta["category"] = category
96
+ fact_ids = self._engine.store(content, metadata=meta)
97
+ return len(fact_ids) > 0
98
+ except Exception as exc:
99
+ logger.debug("Auto-capture store failed: %s", exc)
100
+ return False
101
+
102
+ def _match_patterns(self, content: str, patterns: list[str]) -> float:
103
+ """Match content against regex patterns. Returns confidence 0.0-1.0."""
104
+ matches = sum(1 for p in patterns if re.search(p, content))
105
+ if matches == 0:
106
+ return 0.0
107
+ return min(1.0, 0.5 + (matches * 0.25))
108
+
109
+ @property
110
+ def enabled(self) -> bool:
111
+ return self._enabled
@@ -0,0 +1,93 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """Auto-recall — inject relevant memories into AI context automatically."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from typing import Any
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class AutoRecall:
16
+ """Automatically recalls relevant context for AI sessions.
17
+
18
+ Called at session start or before each prompt to inject
19
+ relevant memories without user intervention.
20
+ """
21
+
22
+ def __init__(self, engine=None, config: dict | None = None):
23
+ self._engine = engine
24
+ self._config = config or {}
25
+ self._enabled = self._config.get("enabled", True)
26
+ self._max_memories = self._config.get("max_memories_injected", 10)
27
+ self._threshold = self._config.get("relevance_threshold", 0.3)
28
+
29
+ def get_session_context(self, project_path: str = "", query: str = "") -> str:
30
+ """Get relevant context for a session or query.
31
+
32
+ Returns a formatted string of relevant memories suitable
33
+ for injection into an AI's system prompt.
34
+ """
35
+ if not self._enabled or not self._engine:
36
+ return ""
37
+
38
+ try:
39
+ # Build query from project path or explicit query
40
+ search_query = query or f"project context {project_path}"
41
+ response = self._engine.recall(search_query, limit=self._max_memories)
42
+
43
+ if not response.results:
44
+ return ""
45
+
46
+ # Filter by relevance threshold
47
+ relevant = [r for r in response.results if r.score >= self._threshold]
48
+
49
+ if not relevant:
50
+ return ""
51
+
52
+ # Format for injection
53
+ lines = ["# Relevant Memory Context", ""]
54
+ for r in relevant[:self._max_memories]:
55
+ lines.append(f"- {r.fact.content[:200]}")
56
+
57
+ return "\n".join(lines)
58
+ except Exception as exc:
59
+ logger.debug("Auto-recall failed: %s", exc)
60
+ return ""
61
+
62
+ def get_query_context(self, query: str) -> list[dict]:
63
+ """Get relevant memories for a specific query.
64
+
65
+ Returns structured data (not formatted string) for MCP tools.
66
+ """
67
+ if not self._enabled or not self._engine:
68
+ return []
69
+
70
+ try:
71
+ response = self._engine.recall(query, limit=self._max_memories)
72
+ results = []
73
+ for r in response.results:
74
+ if r.score >= self._threshold:
75
+ results.append({
76
+ "fact_id": r.fact.fact_id,
77
+ "content": r.fact.content[:300],
78
+ "score": round(r.score, 3),
79
+ })
80
+ return results
81
+ except Exception as exc:
82
+ logger.debug("Auto-recall query failed: %s", exc)
83
+ return []
84
+
85
+ @property
86
+ def enabled(self) -> bool:
87
+ return self._enabled
88
+
89
+ def enable(self) -> None:
90
+ self._enabled = True
91
+
92
+ def disable(self) -> None:
93
+ self._enabled = False
@@ -0,0 +1,204 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under the MIT License - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """IDE connector — detect installed IDEs and generate SLM integration configs.
6
+
7
+ Supports: Claude Code, Cursor, VS Code/Copilot, Windsurf, Gemini CLI,
8
+ JetBrains IDEs, Continue.dev, Zed, Aider.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import logging
15
+ from pathlib import Path
16
+ from typing import Any
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # SLM marker to detect our config sections (for idempotency)
21
+ SLM_MARKER = "## SuperLocalMemory"
22
+ SLM_MARKER_START = "<!-- SLM-START -->"
23
+ SLM_MARKER_END = "<!-- SLM-END -->"
24
+
25
+ # Known IDE config paths (relative to home directory)
26
+ IDE_CONFIGS: dict[str, dict[str, Any]] = {
27
+ "claude_code": {
28
+ "name": "Claude Code",
29
+ "detect_paths": [".claude"],
30
+ "config_files": [".claude/CLAUDE.md"],
31
+ "type": "markdown_append",
32
+ },
33
+ "cursor": {
34
+ "name": "Cursor",
35
+ "detect_paths": [".cursor"],
36
+ "config_files": [".cursorrules"],
37
+ "type": "markdown_append",
38
+ },
39
+ "vscode": {
40
+ "name": "VS Code / Copilot",
41
+ "detect_paths": [".vscode", "Library/Application Support/Code"],
42
+ "config_files": [".github/copilot-instructions.md"],
43
+ "type": "markdown_append",
44
+ },
45
+ "windsurf": {
46
+ "name": "Windsurf",
47
+ "detect_paths": [".codeium/windsurf"],
48
+ "config_files": [".windsurfrules"],
49
+ "type": "markdown_append",
50
+ },
51
+ "gemini": {
52
+ "name": "Gemini CLI",
53
+ "detect_paths": [".gemini"],
54
+ "config_files": ["GEMINI.md"],
55
+ "type": "markdown_append",
56
+ },
57
+ "continue_dev": {
58
+ "name": "Continue.dev",
59
+ "detect_paths": [".continue"],
60
+ "config_files": [".continue/config.json"],
61
+ "type": "json_merge",
62
+ },
63
+ "zed": {
64
+ "name": "Zed Editor",
65
+ "detect_paths": [".config/zed"],
66
+ "config_files": [".config/zed/settings.json"],
67
+ "type": "json_merge",
68
+ },
69
+ }
70
+
71
+ # Template for markdown-based IDE rules
72
+ MARKDOWN_TEMPLATE = """
73
+ {marker_start}
74
+ {marker}
75
+ - Before responding to questions, check SuperLocalMemory for relevant context using the `recall` tool
76
+ - After making decisions, fixing bugs, or learning preferences, store them using the `remember` tool
77
+ - On session start, load project context from SuperLocalMemory
78
+ - Available tools: remember, recall, search, fetch, get_status, set_mode, health
79
+ - Documentation: https://superlocalmemory.com
80
+ {marker_end}
81
+ """
82
+
83
+
84
+ class IDEConnector:
85
+ """Detect installed IDEs and generate SLM integration configs."""
86
+
87
+ def __init__(self, home: Path | None = None) -> None:
88
+ self._home = home or Path.home()
89
+
90
+ def detect_ides(self) -> dict[str, bool]:
91
+ """Detect which IDEs are installed.
92
+
93
+ Returns a dict mapping IDE id to whether it was detected.
94
+ """
95
+ result: dict[str, bool] = {}
96
+ for ide_id, config in IDE_CONFIGS.items():
97
+ detected = any(
98
+ (self._home / p).exists() for p in config["detect_paths"]
99
+ )
100
+ result[ide_id] = detected
101
+ return result
102
+
103
+ def connect(self, ide_id: str) -> bool:
104
+ """Configure a specific IDE for SLM integration.
105
+
106
+ Returns True if configuration was written successfully.
107
+ Idempotent — safe to run multiple times.
108
+ Does NOT overwrite existing user rules.
109
+ """
110
+ if ide_id not in IDE_CONFIGS:
111
+ logger.warning("Unknown IDE: %s", ide_id)
112
+ return False
113
+
114
+ config = IDE_CONFIGS[ide_id]
115
+ config_type = config["type"]
116
+
117
+ for config_file in config["config_files"]:
118
+ path = self._home / config_file
119
+
120
+ if config_type == "markdown_append":
121
+ return self._append_markdown(path)
122
+ elif config_type == "json_merge":
123
+ return self._merge_json(path)
124
+
125
+ return False
126
+
127
+ def connect_all(self) -> dict[str, str]:
128
+ """Detect and configure all installed IDEs.
129
+
130
+ Returns dict of {ide_id: status} where status is
131
+ "connected", "not_installed", or "error".
132
+ """
133
+ detected = self.detect_ides()
134
+ results: dict[str, str] = {}
135
+
136
+ for ide_id, is_installed in detected.items():
137
+ if not is_installed:
138
+ results[ide_id] = "not_installed"
139
+ continue
140
+ try:
141
+ success = self.connect(ide_id)
142
+ results[ide_id] = "connected" if success else "error"
143
+ except Exception as exc:
144
+ logger.debug("Failed to connect %s: %s", ide_id, exc)
145
+ results[ide_id] = "error"
146
+
147
+ return results
148
+
149
+ def get_status(self) -> list[dict[str, Any]]:
150
+ """Get connection status for all known IDEs."""
151
+ detected = self.detect_ides()
152
+ status: list[dict[str, Any]] = []
153
+ for ide_id, config in IDE_CONFIGS.items():
154
+ status.append({
155
+ "id": ide_id,
156
+ "name": config["name"],
157
+ "installed": detected.get(ide_id, False),
158
+ "config_path": str(self._home / config["config_files"][0]),
159
+ })
160
+ return status
161
+
162
+ def _append_markdown(self, path: Path) -> bool:
163
+ """Append SLM section to a markdown file. Idempotent."""
164
+ content = ""
165
+ if path.exists():
166
+ content = path.read_text()
167
+
168
+ # Check if already configured (idempotent)
169
+ if SLM_MARKER in content:
170
+ return True
171
+
172
+ # Append SLM section
173
+ section = MARKDOWN_TEMPLATE.format(
174
+ marker=SLM_MARKER,
175
+ marker_start=SLM_MARKER_START,
176
+ marker_end=SLM_MARKER_END,
177
+ )
178
+
179
+ path.parent.mkdir(parents=True, exist_ok=True)
180
+ path.write_text(content + "\n" + section)
181
+ return True
182
+
183
+ def _merge_json(self, path: Path) -> bool:
184
+ """Merge SLM config into a JSON config file."""
185
+ data: dict[str, Any] = {}
186
+ if path.exists():
187
+ try:
188
+ data = json.loads(path.read_text())
189
+ except json.JSONDecodeError:
190
+ data = {}
191
+
192
+ # Add MCP server config
193
+ if "mcpServers" not in data:
194
+ data["mcpServers"] = {}
195
+
196
+ data["mcpServers"]["superlocalmemory"] = {
197
+ "command": "python3",
198
+ "args": ["-m", "superlocalmemory.mcp.server"],
199
+ "enabled": True,
200
+ }
201
+
202
+ path.parent.mkdir(parents=True, exist_ok=True)
203
+ path.write_text(json.dumps(data, indent=2))
204
+ return True