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
package/api_server.py DELETED
@@ -1,724 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- SuperLocalMemory V2 - FastAPI UI Server
6
- Provides REST endpoints for memory visualization and exploration.
7
- """
8
-
9
- import sqlite3
10
- import json
11
- from pathlib import Path
12
- from typing import Optional, List, Dict, Any
13
- from datetime import datetime, timedelta
14
-
15
- from fastapi import FastAPI, HTTPException, Query
16
- from fastapi.staticfiles import StaticFiles
17
- from fastapi.responses import HTMLResponse, JSONResponse
18
- from pydantic import BaseModel
19
- import uvicorn
20
-
21
- from security_middleware import SecurityHeadersMiddleware
22
-
23
- # Import local modules
24
- import sys
25
- sys.path.insert(0, str(Path(__file__).parent / "src"))
26
-
27
- from memory_store_v2 import MemoryStoreV2
28
- from graph_engine import GraphEngine
29
- from pattern_learner import PatternLearner
30
-
31
- # Configuration
32
- MEMORY_DIR = Path.home() / ".claude-memory"
33
- DB_PATH = MEMORY_DIR / "memory.db"
34
- UI_DIR = Path(__file__).parent / "ui"
35
-
36
- app = FastAPI(
37
- title="SuperLocalMemory V2 UI",
38
- description="Knowledge Graph Visualization for Local Memory System",
39
- version="2.0.0"
40
- )
41
-
42
- # Security middleware (add first for proper header application)
43
- app.add_middleware(SecurityHeadersMiddleware)
44
-
45
- # Mount static files
46
- UI_DIR.mkdir(exist_ok=True)
47
- app.mount("/static", StaticFiles(directory=str(UI_DIR)), name="static")
48
-
49
- # Rate limiting (v2.6)
50
- try:
51
- from rate_limiter import write_limiter, read_limiter
52
-
53
- @app.middleware("http")
54
- async def rate_limit_middleware(request, call_next):
55
- client_ip = request.client.host if request.client else "unknown"
56
-
57
- # Determine if this is a write or read endpoint
58
- is_write = request.method in ("POST", "PUT", "DELETE", "PATCH")
59
- limiter = write_limiter if is_write else read_limiter
60
-
61
- allowed, remaining = limiter.is_allowed(client_ip)
62
- if not allowed:
63
- from fastapi.responses import JSONResponse
64
- return JSONResponse(
65
- status_code=429,
66
- content={"error": "Too many requests. Please slow down."},
67
- headers={"Retry-After": str(limiter.window)}
68
- )
69
-
70
- response = await call_next(request)
71
- response.headers["X-RateLimit-Remaining"] = str(remaining)
72
- return response
73
-
74
- except ImportError:
75
- pass # Rate limiter not available — continue without it
76
-
77
- # Optional API key authentication (v2.6)
78
- try:
79
- from auth_middleware import check_api_key
80
-
81
- @app.middleware("http")
82
- async def auth_middleware(request, call_next):
83
- is_write = request.method in ("POST", "PUT", "DELETE", "PATCH")
84
- headers = dict(request.headers)
85
- if not check_api_key(headers, is_write=is_write):
86
- from fastapi.responses import JSONResponse
87
- return JSONResponse(
88
- status_code=401,
89
- content={"error": "Invalid or missing API key. Set X-SLM-API-Key header."}
90
- )
91
- response = await call_next(request)
92
- return response
93
- except ImportError:
94
- pass # Auth middleware not available
95
-
96
-
97
- # ============================================================================
98
- # Request/Response Models
99
- # ============================================================================
100
-
101
- class SearchRequest(BaseModel):
102
- query: str
103
- limit: int = 10
104
- min_score: float = 0.3
105
-
106
-
107
- class MemoryFilter(BaseModel):
108
- category: Optional[str] = None
109
- project_name: Optional[str] = None
110
- cluster_id: Optional[int] = None
111
- min_importance: Optional[int] = None
112
-
113
-
114
- # ============================================================================
115
- # Database Helper Functions
116
- # ============================================================================
117
-
118
- def get_db_connection():
119
- """Get database connection."""
120
- if not DB_PATH.exists():
121
- raise HTTPException(status_code=500, detail="Memory database not found")
122
- return sqlite3.connect(DB_PATH)
123
-
124
-
125
- def dict_factory(cursor, row):
126
- """Convert SQLite row to dictionary."""
127
- fields = [column[0] for column in cursor.description]
128
- return {key: value for key, value in zip(fields, row)}
129
-
130
-
131
- # ============================================================================
132
- # API Endpoints
133
- # ============================================================================
134
-
135
- @app.get("/", response_class=HTMLResponse)
136
- async def root():
137
- """Serve main UI page."""
138
- index_path = UI_DIR / "index.html"
139
- if not index_path.exists():
140
- return """
141
- <html>
142
- <head><title>SuperLocalMemory V2</title></head>
143
- <body style="font-family: Arial; padding: 40px;">
144
- <h1>SuperLocalMemory V2 UI Server Running</h1>
145
- <p>UI not found. Please create ui/index.html</p>
146
- <h2>Available Endpoints:</h2>
147
- <ul>
148
- <li><a href="/docs">/docs - Interactive API Documentation</a></li>
149
- <li><a href="/api/stats">/api/stats - System Statistics</a></li>
150
- <li><a href="/api/memories">/api/memories - List Memories</a></li>
151
- <li><a href="/api/graph">/api/graph - Graph Data</a></li>
152
- <li><a href="/api/clusters">/api/clusters - Cluster Info</a></li>
153
- <li><a href="/api/patterns">/api/patterns - Learned Patterns</a></li>
154
- <li><a href="/api/timeline">/api/timeline - Timeline View</a></li>
155
- <li><a href="/api/tree">/api/tree - Tree Structure</a></li>
156
- </ul>
157
- </body>
158
- </html>
159
- """
160
- return index_path.read_text()
161
-
162
-
163
- @app.get("/api/memories")
164
- async def get_memories(
165
- category: Optional[str] = None,
166
- project_name: Optional[str] = None,
167
- cluster_id: Optional[int] = None,
168
- min_importance: Optional[int] = None,
169
- limit: int = Query(50, le=200),
170
- offset: int = 0
171
- ):
172
- """
173
- List memories with optional filtering.
174
-
175
- Query Parameters:
176
- - category: Filter by category
177
- - project_name: Filter by project
178
- - cluster_id: Filter by cluster
179
- - min_importance: Minimum importance score
180
- - limit: Maximum results (default 50, max 200)
181
- - offset: Pagination offset
182
- """
183
- conn = get_db_connection()
184
- conn.row_factory = dict_factory
185
- cursor = conn.cursor()
186
-
187
- # Build dynamic query
188
- query = """
189
- SELECT
190
- id, content, summary, category, project_name,
191
- importance, cluster_id, depth, access_count,
192
- created_at, updated_at, last_accessed, tags
193
- FROM memories
194
- WHERE 1=1
195
- """
196
- params = []
197
-
198
- if category:
199
- query += " AND category = ?"
200
- params.append(category)
201
-
202
- if project_name:
203
- query += " AND project_name = ?"
204
- params.append(project_name)
205
-
206
- if cluster_id is not None:
207
- query += " AND cluster_id = ?"
208
- params.append(cluster_id)
209
-
210
- if min_importance:
211
- query += " AND importance >= ?"
212
- params.append(min_importance)
213
-
214
- query += " ORDER BY updated_at DESC LIMIT ? OFFSET ?"
215
- params.extend([limit, offset])
216
-
217
- cursor.execute(query, params)
218
- memories = cursor.fetchall()
219
-
220
- # Get total count
221
- count_query = "SELECT COUNT(*) as total FROM memories WHERE 1=1"
222
- count_params = []
223
- if category:
224
- count_query += " AND category = ?"
225
- count_params.append(category)
226
- if project_name:
227
- count_query += " AND project_name = ?"
228
- count_params.append(project_name)
229
- if cluster_id is not None:
230
- count_query += " AND cluster_id = ?"
231
- count_params.append(cluster_id)
232
- if min_importance:
233
- count_query += " AND importance >= ?"
234
- count_params.append(min_importance)
235
-
236
- cursor.execute(count_query, count_params)
237
- total = cursor.fetchone()['total']
238
-
239
- conn.close()
240
-
241
- return {
242
- "memories": memories,
243
- "total": total,
244
- "limit": limit,
245
- "offset": offset
246
- }
247
-
248
-
249
- @app.get("/api/graph")
250
- async def get_graph(max_nodes: int = Query(100, le=500)):
251
- """
252
- Get graph data for D3.js force-directed visualization.
253
-
254
- Returns:
255
- - nodes: List of memory nodes with metadata
256
- - links: List of edges between memories
257
- """
258
- conn = get_db_connection()
259
- conn.row_factory = dict_factory
260
- cursor = conn.cursor()
261
-
262
- # Get nodes (memories with graph data)
263
- cursor.execute("""
264
- SELECT
265
- m.id, m.content, m.summary, m.category,
266
- m.cluster_id, m.importance, m.project_name,
267
- gn.entities
268
- FROM memories m
269
- LEFT JOIN graph_nodes gn ON m.id = gn.memory_id
270
- WHERE m.cluster_id IS NOT NULL
271
- ORDER BY m.importance DESC, m.updated_at DESC
272
- LIMIT ?
273
- """, (max_nodes,))
274
- nodes = cursor.fetchall()
275
-
276
- # Parse entities JSON
277
- for node in nodes:
278
- if node['entities']:
279
- try:
280
- node['entities'] = json.loads(node['entities'])
281
- except:
282
- node['entities'] = []
283
- else:
284
- node['entities'] = []
285
-
286
- # Truncate content for display
287
- if node['content'] and len(node['content']) > 100:
288
- node['content_preview'] = node['content'][:100] + "..."
289
- else:
290
- node['content_preview'] = node['content']
291
-
292
- # Get edges
293
- memory_ids = [n['id'] for n in nodes]
294
- if memory_ids:
295
- placeholders = ','.join('?' * len(memory_ids))
296
- cursor.execute(f"""
297
- SELECT
298
- source_memory_id as source,
299
- target_memory_id as target,
300
- weight,
301
- relationship_type,
302
- shared_entities
303
- FROM graph_edges
304
- WHERE source_memory_id IN ({placeholders})
305
- AND target_memory_id IN ({placeholders})
306
- ORDER BY weight DESC
307
- """, memory_ids + memory_ids)
308
- links = cursor.fetchall()
309
-
310
- # Parse shared entities
311
- for link in links:
312
- if link['shared_entities']:
313
- try:
314
- link['shared_entities'] = json.loads(link['shared_entities'])
315
- except:
316
- link['shared_entities'] = []
317
- else:
318
- links = []
319
-
320
- conn.close()
321
-
322
- return {
323
- "nodes": nodes,
324
- "links": links,
325
- "metadata": {
326
- "node_count": len(nodes),
327
- "edge_count": len(links)
328
- }
329
- }
330
-
331
-
332
- @app.get("/api/clusters")
333
- async def get_clusters():
334
- """
335
- Get cluster information with member counts and themes.
336
-
337
- Returns list of clusters with:
338
- - cluster_id
339
- - member_count
340
- - dominant_entities (most common concepts)
341
- - categories represented
342
- - importance_avg
343
- """
344
- conn = get_db_connection()
345
- conn.row_factory = dict_factory
346
- cursor = conn.cursor()
347
-
348
- # Get cluster statistics
349
- cursor.execute("""
350
- SELECT
351
- cluster_id,
352
- COUNT(*) as member_count,
353
- AVG(importance) as avg_importance,
354
- GROUP_CONCAT(DISTINCT category) as categories,
355
- GROUP_CONCAT(DISTINCT project_name) as projects
356
- FROM memories
357
- WHERE cluster_id IS NOT NULL
358
- GROUP BY cluster_id
359
- ORDER BY member_count DESC
360
- """)
361
- clusters = cursor.fetchall()
362
-
363
- # Get dominant entities per cluster
364
- for cluster in clusters:
365
- cluster_id = cluster['cluster_id']
366
-
367
- # Aggregate entities from all members
368
- cursor.execute("""
369
- SELECT gn.entities
370
- FROM graph_nodes gn
371
- JOIN memories m ON gn.memory_id = m.id
372
- WHERE m.cluster_id = ?
373
- """, (cluster_id,))
374
-
375
- all_entities = []
376
- for row in cursor.fetchall():
377
- if row['entities']:
378
- try:
379
- entities = json.loads(row['entities'])
380
- all_entities.extend(entities)
381
- except:
382
- pass
383
-
384
- # Count and get top 5
385
- from collections import Counter
386
- entity_counts = Counter(all_entities)
387
- cluster['top_entities'] = [
388
- {"entity": e, "count": c}
389
- for e, c in entity_counts.most_common(5)
390
- ]
391
-
392
- conn.close()
393
-
394
- return {
395
- "clusters": clusters,
396
- "total_clusters": len(clusters)
397
- }
398
-
399
-
400
- @app.get("/api/patterns")
401
- async def get_patterns():
402
- """
403
- Get learned patterns from Pattern Learner (Layer 4).
404
-
405
- Returns user preferences, coding style, and terminology patterns.
406
- """
407
- try:
408
- # Initialize pattern learner
409
- learner = PatternLearner(DB_PATH)
410
-
411
- # Get all active patterns
412
- conn = get_db_connection()
413
- conn.row_factory = dict_factory
414
- cursor = conn.cursor()
415
-
416
- cursor.execute("""
417
- SELECT
418
- pattern_type, key, value, confidence,
419
- evidence_count, last_updated
420
- FROM learned_patterns
421
- WHERE is_active = 1
422
- ORDER BY confidence DESC, evidence_count DESC
423
- """)
424
- patterns = cursor.fetchall()
425
-
426
- # Parse value JSON
427
- for pattern in patterns:
428
- if pattern['value']:
429
- try:
430
- pattern['value'] = json.loads(pattern['value'])
431
- except:
432
- pass
433
-
434
- # Group by type
435
- grouped = {}
436
- for pattern in patterns:
437
- ptype = pattern['pattern_type']
438
- if ptype not in grouped:
439
- grouped[ptype] = []
440
- grouped[ptype].append(pattern)
441
-
442
- conn.close()
443
-
444
- return {
445
- "patterns": grouped,
446
- "total_patterns": len(patterns),
447
- "pattern_types": list(grouped.keys())
448
- }
449
-
450
- except Exception as e:
451
- return {
452
- "patterns": {},
453
- "total_patterns": 0,
454
- "error": str(e)
455
- }
456
-
457
-
458
- @app.get("/api/stats")
459
- async def get_stats():
460
- """
461
- Get system statistics overview.
462
-
463
- Returns:
464
- - Total memories, sessions, clusters
465
- - Storage usage
466
- - Recent activity
467
- - Category breakdown
468
- """
469
- conn = get_db_connection()
470
- conn.row_factory = dict_factory
471
- cursor = conn.cursor()
472
-
473
- # Basic counts
474
- cursor.execute("SELECT COUNT(*) as total FROM memories")
475
- total_memories = cursor.fetchone()['total']
476
-
477
- cursor.execute("SELECT COUNT(*) as total FROM sessions")
478
- total_sessions = cursor.fetchone()['total']
479
-
480
- cursor.execute("SELECT COUNT(DISTINCT cluster_id) as total FROM memories WHERE cluster_id IS NOT NULL")
481
- total_clusters = cursor.fetchone()['total']
482
-
483
- cursor.execute("SELECT COUNT(*) as total FROM graph_nodes")
484
- total_graph_nodes = cursor.fetchone()['total']
485
-
486
- cursor.execute("SELECT COUNT(*) as total FROM graph_edges")
487
- total_graph_edges = cursor.fetchone()['total']
488
-
489
- # Category breakdown
490
- cursor.execute("""
491
- SELECT category, COUNT(*) as count
492
- FROM memories
493
- WHERE category IS NOT NULL
494
- GROUP BY category
495
- ORDER BY count DESC
496
- LIMIT 10
497
- """)
498
- categories = cursor.fetchall()
499
-
500
- # Project breakdown
501
- cursor.execute("""
502
- SELECT project_name, COUNT(*) as count
503
- FROM memories
504
- WHERE project_name IS NOT NULL
505
- GROUP BY project_name
506
- ORDER BY count DESC
507
- LIMIT 10
508
- """)
509
- projects = cursor.fetchall()
510
-
511
- # Recent activity (last 7 days)
512
- cursor.execute("""
513
- SELECT COUNT(*) as count
514
- FROM memories
515
- WHERE created_at >= datetime('now', '-7 days')
516
- """)
517
- recent_memories = cursor.fetchone()['count']
518
-
519
- # Importance distribution
520
- cursor.execute("""
521
- SELECT importance, COUNT(*) as count
522
- FROM memories
523
- GROUP BY importance
524
- ORDER BY importance DESC
525
- """)
526
- importance_dist = cursor.fetchall()
527
-
528
- # Database size
529
- db_size = DB_PATH.stat().st_size if DB_PATH.exists() else 0
530
-
531
- conn.close()
532
-
533
- return {
534
- "overview": {
535
- "total_memories": total_memories,
536
- "total_sessions": total_sessions,
537
- "total_clusters": total_clusters,
538
- "graph_nodes": total_graph_nodes,
539
- "graph_edges": total_graph_edges,
540
- "db_size_mb": round(db_size / (1024 * 1024), 2),
541
- "recent_memories_7d": recent_memories
542
- },
543
- "categories": categories,
544
- "projects": projects,
545
- "importance_distribution": importance_dist
546
- }
547
-
548
-
549
- @app.post("/api/search")
550
- async def search_memories(request: SearchRequest):
551
- """
552
- Semantic search using TF-IDF similarity.
553
-
554
- Request body:
555
- - query: Search query
556
- - limit: Max results (default 10)
557
- - min_score: Minimum similarity score (default 0.3)
558
- """
559
- try:
560
- store = MemoryStoreV2(DB_PATH)
561
- results = store.search(
562
- query=request.query,
563
- limit=request.limit
564
- )
565
-
566
- # Filter by min_score
567
- filtered = [
568
- r for r in results
569
- if r.get('score', 0) >= request.min_score
570
- ]
571
-
572
- return {
573
- "query": request.query,
574
- "results": filtered,
575
- "total": len(filtered)
576
- }
577
-
578
- except Exception as e:
579
- raise HTTPException(status_code=500, detail=str(e))
580
-
581
-
582
- @app.get("/api/timeline")
583
- async def get_timeline(days: int = Query(30, le=365)):
584
- """
585
- Get temporal view of memory creation over time.
586
-
587
- Parameters:
588
- - days: Number of days to look back (default 30, max 365)
589
-
590
- Returns daily/weekly aggregates with category breakdown.
591
- """
592
- conn = get_db_connection()
593
- conn.row_factory = dict_factory
594
- cursor = conn.cursor()
595
-
596
- # Daily aggregates
597
- cursor.execute("""
598
- SELECT
599
- DATE(created_at) as date,
600
- COUNT(*) as count,
601
- AVG(importance) as avg_importance,
602
- GROUP_CONCAT(DISTINCT category) as categories
603
- FROM memories
604
- WHERE created_at >= datetime('now', '-' || ? || ' days')
605
- GROUP BY DATE(created_at)
606
- ORDER BY date DESC
607
- """, (days,))
608
- daily = cursor.fetchall()
609
-
610
- # Category trend over time
611
- cursor.execute("""
612
- SELECT
613
- DATE(created_at) as date,
614
- category,
615
- COUNT(*) as count
616
- FROM memories
617
- WHERE created_at >= datetime('now', '-' || ? || ' days')
618
- AND category IS NOT NULL
619
- GROUP BY DATE(created_at), category
620
- ORDER BY date DESC
621
- """, (days,))
622
- category_trend = cursor.fetchall()
623
-
624
- conn.close()
625
-
626
- return {
627
- "timeline": daily,
628
- "category_trend": category_trend,
629
- "period_days": days
630
- }
631
-
632
-
633
- @app.get("/api/tree")
634
- async def get_tree():
635
- """
636
- Get hierarchical tree structure.
637
-
638
- Returns nested tree of projects > categories > memories.
639
- """
640
- conn = get_db_connection()
641
- conn.row_factory = dict_factory
642
- cursor = conn.cursor()
643
-
644
- # Get all memories with hierarchy info
645
- cursor.execute("""
646
- SELECT
647
- id, parent_id, tree_path, depth,
648
- project_name, category,
649
- COALESCE(summary, SUBSTR(content, 1, 100)) as label,
650
- importance, created_at
651
- FROM memories
652
- ORDER BY tree_path
653
- """)
654
- nodes = cursor.fetchall()
655
-
656
- # Build tree structure
657
- tree = []
658
- node_map = {}
659
-
660
- for node in nodes:
661
- node['children'] = []
662
- node_map[node['id']] = node
663
-
664
- if node['parent_id'] is None:
665
- # Root node
666
- tree.append(node)
667
- elif node['parent_id'] in node_map:
668
- # Add to parent
669
- node_map[node['parent_id']]['children'].append(node)
670
-
671
- conn.close()
672
-
673
- return {
674
- "tree": tree,
675
- "total_nodes": len(nodes)
676
- }
677
-
678
-
679
- # ============================================================================
680
- # v2.8 Routes (graceful — don't fail if engines unavailable)
681
- # ============================================================================
682
-
683
- try:
684
- from routes.lifecycle import router as lifecycle_router
685
- app.include_router(lifecycle_router)
686
- except ImportError:
687
- pass
688
-
689
- try:
690
- from routes.behavioral import router as behavioral_router
691
- app.include_router(behavioral_router)
692
- except ImportError:
693
- pass
694
-
695
- try:
696
- from routes.compliance import router as compliance_router
697
- app.include_router(compliance_router)
698
- except ImportError:
699
- pass
700
-
701
-
702
- # ============================================================================
703
- # Server Startup
704
- # ============================================================================
705
-
706
- if __name__ == "__main__":
707
- print("=" * 60)
708
- print("SuperLocalMemory V2 - UI Server")
709
- print("=" * 60)
710
- print(f"Database: {DB_PATH}")
711
- print(f"UI Directory: {UI_DIR}")
712
- print("=" * 60)
713
- print("\nStarting server on http://localhost:8000")
714
- print("API Documentation: http://localhost:8000/docs")
715
- print("\nPress Ctrl+C to stop\n")
716
-
717
- # SECURITY: Bind to localhost only to prevent network exposure
718
- # For network access, use a reverse proxy with authentication
719
- uvicorn.run(
720
- app,
721
- host="127.0.0.1", # localhost only - NEVER use 0.0.0.0 without auth
722
- port=8000,
723
- log_level="info"
724
- )