superlocalmemory 2.8.6 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/LICENSE +9 -1
  2. package/NOTICE +63 -0
  3. package/README.md +165 -480
  4. package/bin/slm +17 -449
  5. package/bin/slm-npm +62 -48
  6. package/conftest.py +5 -0
  7. package/docs/api-reference.md +284 -0
  8. package/docs/architecture.md +149 -0
  9. package/docs/auto-memory.md +150 -0
  10. package/docs/cli-reference.md +276 -0
  11. package/docs/compliance.md +191 -0
  12. package/docs/configuration.md +182 -0
  13. package/docs/getting-started.md +102 -0
  14. package/docs/ide-setup.md +261 -0
  15. package/docs/mcp-tools.md +220 -0
  16. package/docs/migration-from-v2.md +170 -0
  17. package/docs/profiles.md +173 -0
  18. package/docs/troubleshooting.md +310 -0
  19. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  20. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  21. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  22. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  23. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  24. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  25. package/ide/configs/cursor-mcp.json +15 -0
  26. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  27. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  28. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  29. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  30. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  31. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  32. package/{configs → ide/configs}/zed-mcp.json +2 -2
  33. package/{hooks → ide/hooks}/context-hook.js +9 -20
  34. package/ide/hooks/memory-list-skill.js +70 -0
  35. package/ide/hooks/memory-profile-skill.js +101 -0
  36. package/ide/hooks/memory-recall-skill.js +62 -0
  37. package/ide/hooks/memory-remember-skill.js +68 -0
  38. package/ide/hooks/memory-reset-skill.js +160 -0
  39. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  40. package/ide/integrations/langchain/README.md +106 -0
  41. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  42. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  43. package/ide/integrations/langchain/pyproject.toml +38 -0
  44. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  45. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  46. package/ide/integrations/langchain/tests/test_security.py +117 -0
  47. package/ide/integrations/llamaindex/README.md +81 -0
  48. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  49. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  50. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  51. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  52. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  53. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  54. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  55. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  56. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  57. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  58. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  59. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  60. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  61. package/package.json +13 -22
  62. package/pyproject.toml +85 -0
  63. package/scripts/build-dmg.sh +417 -0
  64. package/scripts/install-skills.ps1 +334 -0
  65. package/scripts/postinstall.js +2 -2
  66. package/scripts/start-dashboard.ps1 +52 -0
  67. package/scripts/start-dashboard.sh +41 -0
  68. package/scripts/sync-wiki.ps1 +127 -0
  69. package/scripts/sync-wiki.sh +82 -0
  70. package/scripts/test-dmg.sh +161 -0
  71. package/scripts/test-npm-package.ps1 +252 -0
  72. package/scripts/test-npm-package.sh +207 -0
  73. package/scripts/verify-install.ps1 +294 -0
  74. package/scripts/verify-install.sh +266 -0
  75. package/src/superlocalmemory/__init__.py +0 -0
  76. package/src/superlocalmemory/attribution/__init__.py +9 -0
  77. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  78. package/src/superlocalmemory/attribution/signer.py +153 -0
  79. package/src/superlocalmemory/attribution/watermark.py +189 -0
  80. package/src/superlocalmemory/cli/__init__.py +5 -0
  81. package/src/superlocalmemory/cli/commands.py +245 -0
  82. package/src/superlocalmemory/cli/main.py +89 -0
  83. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  84. package/src/superlocalmemory/cli/post_install.py +99 -0
  85. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  86. package/src/superlocalmemory/compliance/__init__.py +0 -0
  87. package/src/superlocalmemory/compliance/abac.py +204 -0
  88. package/src/superlocalmemory/compliance/audit.py +314 -0
  89. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  90. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  91. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  92. package/src/superlocalmemory/compliance/retention.py +232 -0
  93. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  94. package/src/superlocalmemory/core/__init__.py +0 -0
  95. package/src/superlocalmemory/core/config.py +391 -0
  96. package/src/superlocalmemory/core/embeddings.py +293 -0
  97. package/src/superlocalmemory/core/engine.py +701 -0
  98. package/src/superlocalmemory/core/hooks.py +65 -0
  99. package/src/superlocalmemory/core/maintenance.py +172 -0
  100. package/src/superlocalmemory/core/modes.py +140 -0
  101. package/src/superlocalmemory/core/profiles.py +234 -0
  102. package/src/superlocalmemory/core/registry.py +117 -0
  103. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  104. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  105. package/src/superlocalmemory/encoding/__init__.py +0 -0
  106. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  107. package/src/superlocalmemory/encoding/emotional.py +125 -0
  108. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  109. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  110. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  111. package/src/superlocalmemory/encoding/foresight.py +91 -0
  112. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  113. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  114. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  115. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  116. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  117. package/src/superlocalmemory/encoding/type_router.py +235 -0
  118. package/src/superlocalmemory/hooks/__init__.py +3 -0
  119. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  120. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  121. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  122. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  123. package/src/superlocalmemory/infra/__init__.py +3 -0
  124. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  125. package/src/superlocalmemory/infra/backup.py +317 -0
  126. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  127. package/src/superlocalmemory/infra/event_bus.py +381 -0
  128. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  129. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  130. package/src/superlocalmemory/learning/__init__.py +0 -0
  131. package/src/superlocalmemory/learning/adaptive.py +172 -0
  132. package/src/superlocalmemory/learning/behavioral.py +490 -0
  133. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  134. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  135. package/src/superlocalmemory/learning/cross_project.py +399 -0
  136. package/src/superlocalmemory/learning/database.py +376 -0
  137. package/src/superlocalmemory/learning/engagement.py +323 -0
  138. package/src/superlocalmemory/learning/features.py +138 -0
  139. package/src/superlocalmemory/learning/feedback.py +316 -0
  140. package/src/superlocalmemory/learning/outcomes.py +255 -0
  141. package/src/superlocalmemory/learning/project_context.py +366 -0
  142. package/src/superlocalmemory/learning/ranker.py +155 -0
  143. package/src/superlocalmemory/learning/source_quality.py +303 -0
  144. package/src/superlocalmemory/learning/workflows.py +309 -0
  145. package/src/superlocalmemory/llm/__init__.py +0 -0
  146. package/src/superlocalmemory/llm/backbone.py +316 -0
  147. package/src/superlocalmemory/math/__init__.py +0 -0
  148. package/src/superlocalmemory/math/fisher.py +356 -0
  149. package/src/superlocalmemory/math/langevin.py +398 -0
  150. package/src/superlocalmemory/math/sheaf.py +257 -0
  151. package/src/superlocalmemory/mcp/__init__.py +0 -0
  152. package/src/superlocalmemory/mcp/resources.py +245 -0
  153. package/src/superlocalmemory/mcp/server.py +61 -0
  154. package/src/superlocalmemory/mcp/tools.py +18 -0
  155. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  156. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  157. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  158. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  159. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  160. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  161. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  162. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  163. package/src/superlocalmemory/retrieval/engine.py +390 -0
  164. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  165. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  166. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  167. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  168. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  169. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  170. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  171. package/src/superlocalmemory/server/__init__.py +1 -0
  172. package/src/superlocalmemory/server/api.py +248 -0
  173. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  174. package/src/superlocalmemory/server/routes/agents.py +107 -0
  175. package/src/superlocalmemory/server/routes/backup.py +91 -0
  176. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  177. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  178. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  179. package/src/superlocalmemory/server/routes/events.py +183 -0
  180. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  181. package/src/superlocalmemory/server/routes/learning.py +273 -0
  182. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  183. package/src/superlocalmemory/server/routes/memories.py +399 -0
  184. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  185. package/src/superlocalmemory/server/routes/stats.py +346 -0
  186. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  187. package/src/superlocalmemory/server/routes/ws.py +82 -0
  188. package/src/superlocalmemory/server/security_middleware.py +57 -0
  189. package/src/superlocalmemory/server/ui.py +245 -0
  190. package/src/superlocalmemory/storage/__init__.py +0 -0
  191. package/src/superlocalmemory/storage/access_control.py +182 -0
  192. package/src/superlocalmemory/storage/database.py +594 -0
  193. package/src/superlocalmemory/storage/migrations.py +303 -0
  194. package/src/superlocalmemory/storage/models.py +406 -0
  195. package/src/superlocalmemory/storage/schema.py +726 -0
  196. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  197. package/src/superlocalmemory/trust/__init__.py +0 -0
  198. package/src/superlocalmemory/trust/gate.py +130 -0
  199. package/src/superlocalmemory/trust/provenance.py +124 -0
  200. package/src/superlocalmemory/trust/scorer.py +347 -0
  201. package/src/superlocalmemory/trust/signals.py +153 -0
  202. package/ui/index.html +278 -5
  203. package/ui/js/auto-settings.js +70 -0
  204. package/ui/js/dashboard.js +90 -0
  205. package/ui/js/fact-detail.js +92 -0
  206. package/ui/js/feedback.js +2 -2
  207. package/ui/js/ide-status.js +102 -0
  208. package/ui/js/math-health.js +98 -0
  209. package/ui/js/recall-lab.js +127 -0
  210. package/ui/js/settings.js +2 -2
  211. package/ui/js/trust-dashboard.js +73 -0
  212. package/api_server.py +0 -724
  213. package/bin/aider-smart +0 -72
  214. package/bin/superlocalmemoryv2-learning +0 -4
  215. package/bin/superlocalmemoryv2-list +0 -3
  216. package/bin/superlocalmemoryv2-patterns +0 -4
  217. package/bin/superlocalmemoryv2-profile +0 -3
  218. package/bin/superlocalmemoryv2-recall +0 -3
  219. package/bin/superlocalmemoryv2-remember +0 -3
  220. package/bin/superlocalmemoryv2-reset +0 -3
  221. package/bin/superlocalmemoryv2-status +0 -3
  222. package/configs/chatgpt-desktop-mcp.json +0 -16
  223. package/configs/cursor-mcp.json +0 -15
  224. package/hooks/memory-list-skill.js +0 -139
  225. package/hooks/memory-profile-skill.js +0 -273
  226. package/hooks/memory-recall-skill.js +0 -114
  227. package/hooks/memory-remember-skill.js +0 -127
  228. package/hooks/memory-reset-skill.js +0 -274
  229. package/mcp_server.py +0 -1808
  230. package/requirements-core.txt +0 -22
  231. package/requirements-learning.txt +0 -12
  232. package/requirements.txt +0 -12
  233. package/src/agent_registry.py +0 -411
  234. package/src/auth_middleware.py +0 -61
  235. package/src/auto_backup.py +0 -459
  236. package/src/behavioral/__init__.py +0 -49
  237. package/src/behavioral/behavioral_listener.py +0 -203
  238. package/src/behavioral/behavioral_patterns.py +0 -275
  239. package/src/behavioral/cross_project_transfer.py +0 -206
  240. package/src/behavioral/outcome_inference.py +0 -194
  241. package/src/behavioral/outcome_tracker.py +0 -193
  242. package/src/behavioral/tests/__init__.py +0 -4
  243. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  244. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  245. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  246. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  247. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  248. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  249. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  250. package/src/cache_manager.py +0 -518
  251. package/src/compliance/__init__.py +0 -48
  252. package/src/compliance/abac_engine.py +0 -149
  253. package/src/compliance/abac_middleware.py +0 -116
  254. package/src/compliance/audit_db.py +0 -215
  255. package/src/compliance/audit_logger.py +0 -148
  256. package/src/compliance/retention_manager.py +0 -289
  257. package/src/compliance/retention_scheduler.py +0 -186
  258. package/src/compliance/tests/__init__.py +0 -4
  259. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  260. package/src/compliance/tests/test_abac_engine.py +0 -124
  261. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  262. package/src/compliance/tests/test_audit_db.py +0 -123
  263. package/src/compliance/tests/test_audit_logger.py +0 -98
  264. package/src/compliance/tests/test_mcp_audit.py +0 -128
  265. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  266. package/src/compliance/tests/test_retention_manager.py +0 -131
  267. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  268. package/src/compression/__init__.py +0 -25
  269. package/src/compression/cli.py +0 -150
  270. package/src/compression/cold_storage.py +0 -217
  271. package/src/compression/config.py +0 -72
  272. package/src/compression/orchestrator.py +0 -133
  273. package/src/compression/tier2_compressor.py +0 -228
  274. package/src/compression/tier3_compressor.py +0 -153
  275. package/src/compression/tier_classifier.py +0 -148
  276. package/src/db_connection_manager.py +0 -536
  277. package/src/embedding_engine.py +0 -63
  278. package/src/embeddings/__init__.py +0 -47
  279. package/src/embeddings/cache.py +0 -70
  280. package/src/embeddings/cli.py +0 -113
  281. package/src/embeddings/constants.py +0 -47
  282. package/src/embeddings/database.py +0 -91
  283. package/src/embeddings/engine.py +0 -247
  284. package/src/embeddings/model_loader.py +0 -145
  285. package/src/event_bus.py +0 -562
  286. package/src/graph/__init__.py +0 -36
  287. package/src/graph/build_helpers.py +0 -74
  288. package/src/graph/cli.py +0 -87
  289. package/src/graph/cluster_builder.py +0 -188
  290. package/src/graph/cluster_summary.py +0 -148
  291. package/src/graph/constants.py +0 -47
  292. package/src/graph/edge_builder.py +0 -162
  293. package/src/graph/entity_extractor.py +0 -95
  294. package/src/graph/graph_core.py +0 -226
  295. package/src/graph/graph_search.py +0 -231
  296. package/src/graph/hierarchical.py +0 -207
  297. package/src/graph/schema.py +0 -99
  298. package/src/graph_engine.py +0 -52
  299. package/src/hnsw_index.py +0 -628
  300. package/src/hybrid_search.py +0 -46
  301. package/src/learning/__init__.py +0 -217
  302. package/src/learning/adaptive_ranker.py +0 -682
  303. package/src/learning/bootstrap/__init__.py +0 -69
  304. package/src/learning/bootstrap/constants.py +0 -93
  305. package/src/learning/bootstrap/db_queries.py +0 -316
  306. package/src/learning/bootstrap/sampling.py +0 -82
  307. package/src/learning/bootstrap/text_utils.py +0 -71
  308. package/src/learning/cross_project_aggregator.py +0 -857
  309. package/src/learning/db/__init__.py +0 -40
  310. package/src/learning/db/constants.py +0 -44
  311. package/src/learning/db/schema.py +0 -279
  312. package/src/learning/engagement_tracker.py +0 -628
  313. package/src/learning/feature_extractor.py +0 -708
  314. package/src/learning/feedback_collector.py +0 -806
  315. package/src/learning/learning_db.py +0 -915
  316. package/src/learning/project_context_manager.py +0 -572
  317. package/src/learning/ranking/__init__.py +0 -33
  318. package/src/learning/ranking/constants.py +0 -84
  319. package/src/learning/ranking/helpers.py +0 -278
  320. package/src/learning/source_quality_scorer.py +0 -676
  321. package/src/learning/synthetic_bootstrap.py +0 -755
  322. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  323. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  324. package/src/learning/tests/test_aggregator.py +0 -306
  325. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  326. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  327. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  328. package/src/learning/tests/test_feedback_collector.py +0 -294
  329. package/src/learning/tests/test_learning_db.py +0 -602
  330. package/src/learning/tests/test_learning_db_v28.py +0 -110
  331. package/src/learning/tests/test_learning_init_v28.py +0 -48
  332. package/src/learning/tests/test_outcome_signals.py +0 -48
  333. package/src/learning/tests/test_project_context.py +0 -292
  334. package/src/learning/tests/test_schema_migration.py +0 -319
  335. package/src/learning/tests/test_signal_inference.py +0 -397
  336. package/src/learning/tests/test_source_quality.py +0 -351
  337. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  338. package/src/learning/tests/test_workflow_miner.py +0 -318
  339. package/src/learning/workflow_pattern_miner.py +0 -655
  340. package/src/lifecycle/__init__.py +0 -54
  341. package/src/lifecycle/bounded_growth.py +0 -239
  342. package/src/lifecycle/compaction_engine.py +0 -226
  343. package/src/lifecycle/lifecycle_engine.py +0 -355
  344. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  345. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  346. package/src/lifecycle/retention_policy.py +0 -285
  347. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  348. package/src/lifecycle/tests/test_compaction.py +0 -179
  349. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  350. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  351. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  352. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  353. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  354. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  355. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  356. package/src/mcp_tools_v28.py +0 -281
  357. package/src/memory/__init__.py +0 -36
  358. package/src/memory/cli.py +0 -205
  359. package/src/memory/constants.py +0 -39
  360. package/src/memory/helpers.py +0 -28
  361. package/src/memory/schema.py +0 -166
  362. package/src/memory-profiles.py +0 -595
  363. package/src/memory-reset.py +0 -491
  364. package/src/memory_compression.py +0 -989
  365. package/src/memory_store_v2.py +0 -1155
  366. package/src/migrate_v1_to_v2.py +0 -629
  367. package/src/pattern_learner.py +0 -34
  368. package/src/patterns/__init__.py +0 -24
  369. package/src/patterns/analyzers.py +0 -251
  370. package/src/patterns/learner.py +0 -271
  371. package/src/patterns/scoring.py +0 -171
  372. package/src/patterns/store.py +0 -225
  373. package/src/patterns/terminology.py +0 -140
  374. package/src/provenance_tracker.py +0 -312
  375. package/src/qualixar_attribution.py +0 -139
  376. package/src/qualixar_watermark.py +0 -78
  377. package/src/query_optimizer.py +0 -511
  378. package/src/rate_limiter.py +0 -83
  379. package/src/search/__init__.py +0 -20
  380. package/src/search/cli.py +0 -77
  381. package/src/search/constants.py +0 -26
  382. package/src/search/engine.py +0 -241
  383. package/src/search/fusion.py +0 -122
  384. package/src/search/index_loader.py +0 -114
  385. package/src/search/methods.py +0 -162
  386. package/src/search_engine_v2.py +0 -401
  387. package/src/setup_validator.py +0 -482
  388. package/src/subscription_manager.py +0 -391
  389. package/src/tree/__init__.py +0 -59
  390. package/src/tree/builder.py +0 -185
  391. package/src/tree/nodes.py +0 -202
  392. package/src/tree/queries.py +0 -257
  393. package/src/tree/schema.py +0 -80
  394. package/src/tree_manager.py +0 -19
  395. package/src/trust/__init__.py +0 -45
  396. package/src/trust/constants.py +0 -66
  397. package/src/trust/queries.py +0 -157
  398. package/src/trust/schema.py +0 -95
  399. package/src/trust/scorer.py +0 -299
  400. package/src/trust/signals.py +0 -95
  401. package/src/trust_scorer.py +0 -44
  402. package/ui/app.js +0 -1588
  403. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  404. package/ui/js/graph-cytoscape.js +0 -1168
  405. package/ui/js/graph-d3-backup.js +0 -32
  406. package/ui/js/graph.js +0 -32
  407. package/ui_server.py +0 -286
  408. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  409. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  410. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  411. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  412. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  413. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  414. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  415. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  416. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  417. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  418. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  419. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  420. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  421. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  422. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  423. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  424. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  425. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  426. /package/{completions → ide/completions}/slm.bash +0 -0
  427. /package/{completions → ide/completions}/slm.zsh +0 -0
  428. /package/{configs → ide/configs}/cody-commands.json +0 -0
  429. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
  430. /package/{install.ps1 → scripts/install.ps1} +0 -0
  431. /package/{install.sh → scripts/install.sh} +0 -0
@@ -1,595 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- SuperLocalMemory V2 - Profile Management System (Column-Based)
6
-
7
- v2.4.0: Rewritten to use column-based profiles in a SINGLE database.
8
- All memories live in one memory.db with a 'profile' column.
9
- Switching profiles = updating config. No file copying. No data loss risk.
10
-
11
- Previous versions used separate database files per profile, which caused
12
- data loss when switching. This version is backward compatible and will
13
- auto-migrate old profile directories on first run.
14
-
15
- Allows users to maintain separate memory contexts:
16
- - Work profile: Professional coding memories
17
- - Personal profile: Personal projects and learning
18
- - Client-specific profiles: Different clients get isolated memories
19
- - Experimentation profile: Testing and experiments
20
- """
21
-
22
- import os
23
- import sys
24
- import json
25
- import sqlite3
26
- import hashlib
27
- from pathlib import Path
28
- from datetime import datetime
29
- import argparse
30
- import re
31
-
32
- MEMORY_DIR = Path.home() / ".claude-memory"
33
- DB_PATH = MEMORY_DIR / "memory.db"
34
- PROFILES_DIR = MEMORY_DIR / "profiles"
35
- CONFIG_FILE = MEMORY_DIR / "profiles.json"
36
-
37
-
38
- class ProfileManager:
39
- """
40
- Column-based profile manager. All memories in ONE database.
41
- Profile = a value in the 'profile' column of the memories table.
42
- Switching = updating which profile name is active in config.
43
- """
44
-
45
- def __init__(self):
46
- self.memory_dir = MEMORY_DIR
47
- self.db_path = DB_PATH
48
- self.config_file = CONFIG_FILE
49
-
50
- # Ensure memory directory exists
51
- self.memory_dir.mkdir(exist_ok=True)
52
-
53
- # Ensure profile column exists in DB
54
- self._ensure_profile_column()
55
-
56
- # Load or create config
57
- self.config = self._load_config()
58
-
59
- # Auto-migrate old profile directories if they exist
60
- self._migrate_old_profiles()
61
-
62
- def _ensure_profile_column(self):
63
- """Add 'profile' column to memories table if it doesn't exist."""
64
- if not self.db_path.exists():
65
- return
66
-
67
- conn = sqlite3.connect(self.db_path)
68
- cursor = conn.cursor()
69
-
70
- cursor.execute("PRAGMA table_info(memories)")
71
- columns = {row[1] for row in cursor.fetchall()}
72
-
73
- if 'profile' not in columns:
74
- cursor.execute("ALTER TABLE memories ADD COLUMN profile TEXT DEFAULT 'default'")
75
- cursor.execute("UPDATE memories SET profile = 'default' WHERE profile IS NULL")
76
- try:
77
- cursor.execute("CREATE INDEX IF NOT EXISTS idx_profile ON memories(profile)")
78
- except sqlite3.OperationalError:
79
- pass
80
- conn.commit()
81
-
82
- conn.close()
83
-
84
- def _migrate_old_profiles(self):
85
- """
86
- Backward compatibility: migrate old separate-DB profiles into the main DB.
87
- Old profiles stored in ~/.claude-memory/profiles/<name>/memory.db
88
- New profiles use a 'profile' column in the main memory.db
89
- """
90
- profiles_dir = MEMORY_DIR / "profiles"
91
- if not profiles_dir.exists():
92
- return
93
-
94
- migrated_any = False
95
- for profile_dir in profiles_dir.iterdir():
96
- if not profile_dir.is_dir():
97
- continue
98
-
99
- profile_db = profile_dir / "memory.db"
100
- if not profile_db.exists():
101
- continue
102
-
103
- profile_name = profile_dir.name
104
- marker_file = profile_dir / ".migrated_to_column"
105
-
106
- # Skip if already migrated
107
- if marker_file.exists():
108
- continue
109
-
110
- # Import memories from old profile DB
111
- try:
112
- self._import_from_old_profile(profile_name, profile_db)
113
- # Mark as migrated
114
- marker_file.write_text(datetime.now().isoformat())
115
- migrated_any = True
116
- except Exception as e:
117
- print(f" Warning: Could not migrate profile '{profile_name}': {e}", file=sys.stderr)
118
-
119
- if migrated_any:
120
- print(" Profile migration complete (old separate DBs -> column-based)", file=sys.stderr)
121
-
122
- def _import_from_old_profile(self, profile_name, old_db_path):
123
- """Import memories from an old separate-DB profile into main DB."""
124
- if not self.db_path.exists():
125
- return
126
-
127
- main_conn = sqlite3.connect(self.db_path)
128
- main_cursor = main_conn.cursor()
129
-
130
- old_conn = sqlite3.connect(old_db_path)
131
- try:
132
- old_cursor = old_conn.cursor()
133
-
134
- # Get existing hashes
135
- main_cursor.execute("SELECT content_hash FROM memories WHERE content_hash IS NOT NULL")
136
- existing_hashes = {row[0] for row in main_cursor.fetchall()}
137
-
138
- # Get columns from old DB
139
- old_cursor.execute("PRAGMA table_info(memories)")
140
- old_columns = {row[1] for row in old_cursor.fetchall()}
141
-
142
- # Build SELECT based on available columns
143
- select_cols = ['content', 'summary', 'project_path', 'project_name', 'tags',
144
- 'category', 'memory_type', 'importance', 'created_at', 'updated_at',
145
- 'content_hash']
146
- available_cols = [c for c in select_cols if c in old_columns]
147
-
148
- if 'content' not in available_cols:
149
- return
150
-
151
- old_cursor.execute(f"SELECT {', '.join(available_cols)} FROM memories")
152
- rows = old_cursor.fetchall()
153
-
154
- imported = 0
155
- for row in rows:
156
- row_dict = dict(zip(available_cols, row))
157
- content = row_dict.get('content', '')
158
- content_hash = row_dict.get('content_hash')
159
-
160
- if not content:
161
- continue
162
-
163
- # Generate hash if missing
164
- if not content_hash:
165
- content_hash = hashlib.sha256(content.encode()).hexdigest()[:32]
166
-
167
- if content_hash in existing_hashes:
168
- continue
169
-
170
- try:
171
- main_cursor.execute('''
172
- INSERT INTO memories (content, summary, project_path, project_name, tags,
173
- category, memory_type, importance, created_at, updated_at,
174
- content_hash, profile)
175
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
176
- ''', (
177
- content,
178
- row_dict.get('summary'),
179
- row_dict.get('project_path'),
180
- row_dict.get('project_name'),
181
- row_dict.get('tags'),
182
- row_dict.get('category'),
183
- row_dict.get('memory_type', 'session'),
184
- row_dict.get('importance', 5),
185
- row_dict.get('created_at'),
186
- row_dict.get('updated_at'),
187
- content_hash,
188
- profile_name
189
- ))
190
- imported += 1
191
- existing_hashes.add(content_hash)
192
- except sqlite3.IntegrityError:
193
- pass
194
-
195
- main_conn.commit()
196
- finally:
197
- old_conn.close()
198
- main_conn.close()
199
-
200
- if imported > 0:
201
- # Add profile to config if not present
202
- config = self._load_config()
203
- if profile_name not in config.get('profiles', {}):
204
- config['profiles'][profile_name] = {
205
- 'name': profile_name,
206
- 'description': f'Memory profile: {profile_name} (migrated)',
207
- 'created_at': datetime.now().isoformat(),
208
- 'last_used': None
209
- }
210
- self._save_config(config)
211
-
212
- def _load_config(self):
213
- """Load profiles configuration."""
214
- if self.config_file.exists():
215
- with open(self.config_file, 'r') as f:
216
- return json.load(f)
217
- else:
218
- config = {
219
- 'profiles': {
220
- 'default': {
221
- 'name': 'default',
222
- 'description': 'Default memory profile',
223
- 'created_at': datetime.now().isoformat(),
224
- 'last_used': datetime.now().isoformat()
225
- }
226
- },
227
- 'active_profile': 'default'
228
- }
229
- self._save_config(config)
230
- return config
231
-
232
- def _save_config(self, config=None):
233
- """Save profiles configuration."""
234
- if config is None:
235
- config = self.config
236
-
237
- with open(self.config_file, 'w') as f:
238
- json.dump(config, f, indent=2)
239
-
240
- def _validate_profile_name(self, profile_name):
241
- """Validate profile name for security."""
242
- if not profile_name:
243
- raise ValueError("Profile name cannot be empty")
244
-
245
- if not re.match(r'^[a-zA-Z0-9_-]+$', profile_name):
246
- raise ValueError("Invalid profile name. Use only letters, numbers, dash, underscore.")
247
-
248
- if len(profile_name) > 50:
249
- raise ValueError("Profile name too long (max 50 characters)")
250
-
251
- if profile_name in ['.', '..']:
252
- raise ValueError(f"Reserved profile name: {profile_name}")
253
-
254
- def _get_memory_count(self, profile_name):
255
- """Get memory count for a specific profile."""
256
- if not self.db_path.exists():
257
- return 0
258
-
259
- conn = sqlite3.connect(self.db_path)
260
- try:
261
- cursor = conn.cursor()
262
- cursor.execute("SELECT COUNT(*) FROM memories WHERE profile = ?", (profile_name,))
263
- count = cursor.fetchone()[0]
264
- finally:
265
- conn.close()
266
- return count
267
-
268
- def get_active_profile(self) -> str:
269
- """Get the currently active profile name."""
270
- return self.config.get('active_profile', 'default')
271
-
272
- def list_profiles(self) -> list:
273
- """List all available profiles with memory counts."""
274
- print("\n" + "=" * 60)
275
- print("AVAILABLE MEMORY PROFILES")
276
- print("=" * 60)
277
-
278
- active = self.config.get('active_profile', 'default')
279
-
280
- if not self.config.get('profiles'):
281
- print("\n No profiles found. Create one with: create <name>")
282
- return
283
-
284
- print(f"\n{'Profile':20s} {'Description':30s} {'Memories':10s} {'Status':10s}")
285
- print("-" * 75)
286
-
287
- for name, info in self.config['profiles'].items():
288
- status = "ACTIVE" if name == active else ""
289
- desc = info.get('description', 'No description')[:30]
290
- marker = "-> " if name == active else " "
291
- count = self._get_memory_count(name)
292
- print(f"{marker}{name:17s} {desc:30s} {count:<10d} {status:10s}")
293
-
294
- print(f"\nTotal profiles: {len(self.config['profiles'])}")
295
- print(f"Active profile: {active}")
296
-
297
- def create_profile(self, name, description=None, from_current=False):
298
- """
299
- Create a new profile.
300
- Column-based: just adds to config. If from_current, copies memories.
301
- """
302
- print(f"\nCreating profile: {name}")
303
-
304
- self._validate_profile_name(name)
305
-
306
- if name in self.config['profiles']:
307
- print(f"Error: Profile '{name}' already exists")
308
- return False
309
-
310
- if from_current:
311
- # Copy current profile's memories to new profile
312
- active = self.config.get('active_profile', 'default')
313
- if self.db_path.exists():
314
- conn = sqlite3.connect(self.db_path)
315
- cursor = conn.cursor()
316
- cursor.execute("""
317
- INSERT INTO memories (content, summary, project_path, project_name, tags,
318
- category, parent_id, tree_path, depth, memory_type,
319
- importance, created_at, updated_at, last_accessed,
320
- access_count, content_hash, cluster_id, profile)
321
- SELECT content, summary, project_path, project_name, tags,
322
- category, parent_id, tree_path, depth, memory_type,
323
- importance, created_at, updated_at, last_accessed,
324
- access_count, NULL, cluster_id, ?
325
- FROM memories WHERE profile = ?
326
- """, (name, active))
327
- copied = cursor.rowcount
328
- conn.commit()
329
-
330
- # Generate new content hashes for copied memories
331
- cursor.execute("SELECT id, content FROM memories WHERE profile = ? AND content_hash IS NULL", (name,))
332
- for row in cursor.fetchall():
333
- new_hash = hashlib.sha256(row[1].encode()).hexdigest()[:32]
334
- try:
335
- cursor.execute("UPDATE memories SET content_hash = ? WHERE id = ?", (new_hash + f"_{name}", row[0]))
336
- except sqlite3.IntegrityError:
337
- pass
338
- conn.commit()
339
- conn.close()
340
-
341
- print(f" Copied {copied} memories from '{active}' profile")
342
- else:
343
- print(" No database found, creating empty profile")
344
- else:
345
- print(f" Empty profile created (memories will be saved here when active)")
346
-
347
- # Add to config
348
- self.config['profiles'][name] = {
349
- 'name': name,
350
- 'description': description or f'Memory profile: {name}',
351
- 'created_at': datetime.now().isoformat(),
352
- 'last_used': None,
353
- 'created_from': 'current' if from_current else 'empty'
354
- }
355
- self._save_config()
356
-
357
- print(f"Profile '{name}' created successfully")
358
- return True
359
-
360
- def switch_profile(self, name):
361
- """
362
- Switch to a different profile.
363
- Column-based: just updates the active_profile in config. Instant. No data risk.
364
- """
365
- if name not in self.config['profiles']:
366
- print(f"Error: Profile '{name}' not found")
367
- print(f" Available: {', '.join(self.config['profiles'].keys())}")
368
- return False
369
-
370
- current = self.config.get('active_profile', 'default')
371
-
372
- if current == name:
373
- print(f"Already using profile: {name}")
374
- return True
375
-
376
- # Column-based switch: just update config
377
- self.config['active_profile'] = name
378
- self.config['profiles'][name]['last_used'] = datetime.now().isoformat()
379
- self._save_config()
380
-
381
- count = self._get_memory_count(name)
382
- print(f"\nSwitched to profile: {name} ({count} memories)")
383
- print(f"Previous profile: {current}")
384
- return True
385
-
386
- def delete_profile(self, name, force=False):
387
- """Delete a profile. Moves memories to 'default' or deletes them."""
388
- if name not in self.config['profiles']:
389
- print(f"Error: Profile '{name}' not found")
390
- return False
391
-
392
- if name == 'default':
393
- print(f"Error: Cannot delete 'default' profile")
394
- return False
395
-
396
- if self.config.get('active_profile') == name:
397
- print(f"Error: Cannot delete active profile")
398
- print(f" Switch to another profile first: slm profile switch default")
399
- return False
400
-
401
- count = self._get_memory_count(name)
402
-
403
- if not force:
404
- print(f"\nWARNING: This will delete profile '{name}' ({count} memories)")
405
- print(f"Memories will be moved to 'default' profile before deletion.")
406
- response = input(f"Type profile name '{name}' to confirm: ")
407
-
408
- if response != name:
409
- print("Cancelled.")
410
- return False
411
-
412
- # Move memories to default profile
413
- if self.db_path.exists() and count > 0:
414
- conn = sqlite3.connect(self.db_path)
415
- try:
416
- cursor = conn.cursor()
417
- cursor.execute("UPDATE memories SET profile = 'default' WHERE profile = ?", (name,))
418
- moved = cursor.rowcount
419
- conn.commit()
420
- finally:
421
- conn.close()
422
- print(f" Moved {moved} memories to 'default' profile")
423
-
424
- # Remove from config
425
- del self.config['profiles'][name]
426
- self._save_config()
427
-
428
- print(f"Profile '{name}' deleted")
429
- return True
430
-
431
- def show_current(self):
432
- """Show current active profile with stats."""
433
- active = self.config.get('active_profile', 'default')
434
-
435
- if active in self.config['profiles']:
436
- info = self.config['profiles'][active]
437
-
438
- print("\n" + "=" * 60)
439
- print("CURRENT ACTIVE PROFILE")
440
- print("=" * 60)
441
- print(f"\nProfile: {active}")
442
- print(f"Description: {info.get('description', 'N/A')}")
443
- print(f"Created: {info.get('created_at', 'N/A')}")
444
- print(f"Last used: {info.get('last_used', 'N/A')}")
445
-
446
- count = self._get_memory_count(active)
447
- print(f"\nMemories in this profile: {count}")
448
-
449
- # Show total memories across all profiles
450
- if self.db_path.exists():
451
- conn = sqlite3.connect(self.db_path)
452
- try:
453
- cursor = conn.cursor()
454
- cursor.execute("SELECT COUNT(*) FROM memories")
455
- total = cursor.fetchone()[0]
456
- finally:
457
- conn.close()
458
- print(f"Total memories (all profiles): {total}")
459
- else:
460
- print(f"Warning: Current profile '{active}' not found in config")
461
- print("Resetting to 'default' profile...")
462
- self.config['active_profile'] = 'default'
463
- self._save_config()
464
-
465
- def rename_profile(self, old_name, new_name):
466
- """Rename a profile. Updates the column value in all memories."""
467
- if old_name not in self.config['profiles']:
468
- print(f"Error: Profile '{old_name}' not found")
469
- return False
470
-
471
- if new_name in self.config['profiles']:
472
- print(f"Error: Profile '{new_name}' already exists")
473
- return False
474
-
475
- if old_name == 'default':
476
- print(f"Error: Cannot rename 'default' profile")
477
- return False
478
-
479
- self._validate_profile_name(new_name)
480
-
481
- # Update profile column in all memories
482
- if self.db_path.exists():
483
- conn = sqlite3.connect(self.db_path)
484
- try:
485
- cursor = conn.cursor()
486
- cursor.execute("UPDATE memories SET profile = ? WHERE profile = ?", (new_name, old_name))
487
- updated = cursor.rowcount
488
- conn.commit()
489
- finally:
490
- conn.close()
491
- print(f" Updated {updated} memories")
492
-
493
- # Update config
494
- self.config['profiles'][new_name] = self.config['profiles'][old_name]
495
- self.config['profiles'][new_name]['name'] = new_name
496
- del self.config['profiles'][old_name]
497
-
498
- if self.config.get('active_profile') == old_name:
499
- self.config['active_profile'] = new_name
500
-
501
- self._save_config()
502
-
503
- print(f"Profile renamed: '{old_name}' -> '{new_name}'")
504
- return True
505
-
506
-
507
-
508
- def main():
509
- parser = argparse.ArgumentParser(
510
- description='SuperLocalMemory V2 - Profile Management (Column-Based)',
511
- formatter_class=argparse.RawDescriptionHelpFormatter,
512
- epilog='''
513
- Examples:
514
- # List all profiles
515
- python memory-profiles.py list
516
-
517
- # Show current profile
518
- python memory-profiles.py current
519
-
520
- # Create new empty profile
521
- python memory-profiles.py create work --description "Work projects"
522
-
523
- # Create profile from current memories
524
- python memory-profiles.py create personal --from-current
525
-
526
- # Switch to different profile (instant, no restart needed)
527
- python memory-profiles.py switch work
528
-
529
- # Delete a profile (memories moved to default)
530
- python memory-profiles.py delete old-profile
531
-
532
- # Rename profile
533
- python memory-profiles.py rename old-name new-name
534
-
535
- Architecture (v2.4.0):
536
- All profiles share ONE database (memory.db).
537
- Each memory has a 'profile' column.
538
- Switching profiles = changing config. Instant. Safe.
539
- '''
540
- )
541
-
542
- parser.add_argument('command',
543
- choices=['list', 'current', 'create', 'switch', 'delete', 'rename'],
544
- help='Profile command')
545
- parser.add_argument('name', nargs='?', help='Profile name')
546
- parser.add_argument('name2', nargs='?', help='Second name (for rename)')
547
- parser.add_argument('--description', help='Profile description')
548
- parser.add_argument('--from-current', action='store_true',
549
- help='Create from current profile memories')
550
- parser.add_argument('--force', action='store_true',
551
- help='Force operation without confirmation')
552
-
553
- args = parser.parse_args()
554
-
555
- manager = ProfileManager()
556
-
557
- if args.command == 'list':
558
- manager.list_profiles()
559
-
560
- elif args.command == 'current':
561
- manager.show_current()
562
-
563
- elif args.command == 'create':
564
- if not args.name:
565
- print("Error: Profile name required")
566
- print(" Usage: python memory-profiles.py create <name>")
567
- sys.exit(1)
568
-
569
- manager.create_profile(args.name, args.description, args.from_current)
570
-
571
- elif args.command == 'switch':
572
- if not args.name:
573
- print("Error: Profile name required")
574
- sys.exit(1)
575
-
576
- manager.switch_profile(args.name)
577
-
578
- elif args.command == 'delete':
579
- if not args.name:
580
- print("Error: Profile name required")
581
- sys.exit(1)
582
-
583
- manager.delete_profile(args.name, args.force)
584
-
585
- elif args.command == 'rename':
586
- if not args.name or not args.name2:
587
- print("Error: Both old and new names required")
588
- print(" Usage: python memory-profiles.py rename <old> <new>")
589
- sys.exit(1)
590
-
591
- manager.rename_profile(args.name, args.name2)
592
-
593
-
594
- if __name__ == '__main__':
595
- main()