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.
- package/LICENSE +9 -1
- package/NOTICE +63 -0
- package/README.md +165 -480
- package/bin/slm +17 -449
- package/bin/slm-npm +62 -48
- package/conftest.py +5 -0
- package/docs/api-reference.md +284 -0
- package/docs/architecture.md +149 -0
- package/docs/auto-memory.md +150 -0
- package/docs/cli-reference.md +276 -0
- package/docs/compliance.md +191 -0
- package/docs/configuration.md +182 -0
- package/docs/getting-started.md +102 -0
- package/docs/ide-setup.md +261 -0
- package/docs/mcp-tools.md +220 -0
- package/docs/migration-from-v2.md +170 -0
- package/docs/profiles.md +173 -0
- package/docs/troubleshooting.md +310 -0
- package/{configs → ide/configs}/antigravity-mcp.json +3 -3
- package/ide/configs/chatgpt-desktop-mcp.json +16 -0
- package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
- package/{configs → ide/configs}/codex-mcp.toml +4 -4
- package/{configs → ide/configs}/continue-mcp.yaml +4 -3
- package/{configs → ide/configs}/continue-skills.yaml +6 -6
- package/ide/configs/cursor-mcp.json +15 -0
- package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
- package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
- package/{configs → ide/configs}/opencode-mcp.json +2 -2
- package/{configs → ide/configs}/perplexity-mcp.json +2 -2
- package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
- package/{configs → ide/configs}/windsurf-mcp.json +3 -3
- package/{configs → ide/configs}/zed-mcp.json +2 -2
- package/{hooks → ide/hooks}/context-hook.js +9 -20
- package/ide/hooks/memory-list-skill.js +70 -0
- package/ide/hooks/memory-profile-skill.js +101 -0
- package/ide/hooks/memory-recall-skill.js +62 -0
- package/ide/hooks/memory-remember-skill.js +68 -0
- package/ide/hooks/memory-reset-skill.js +160 -0
- package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
- package/ide/integrations/langchain/README.md +106 -0
- package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
- package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
- package/ide/integrations/langchain/pyproject.toml +38 -0
- package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
- package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
- package/ide/integrations/langchain/tests/test_security.py +117 -0
- package/ide/integrations/llamaindex/README.md +81 -0
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
- package/ide/integrations/llamaindex/pyproject.toml +43 -0
- package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
- package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
- package/ide/integrations/llamaindex/tests/test_security.py +241 -0
- package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
- package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
- package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
- package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
- package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
- package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
- package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
- package/package.json +13 -22
- package/pyproject.toml +85 -0
- package/scripts/build-dmg.sh +417 -0
- package/scripts/install-skills.ps1 +334 -0
- package/scripts/postinstall.js +2 -2
- package/scripts/start-dashboard.ps1 +52 -0
- package/scripts/start-dashboard.sh +41 -0
- package/scripts/sync-wiki.ps1 +127 -0
- package/scripts/sync-wiki.sh +82 -0
- package/scripts/test-dmg.sh +161 -0
- package/scripts/test-npm-package.ps1 +252 -0
- package/scripts/test-npm-package.sh +207 -0
- package/scripts/verify-install.ps1 +294 -0
- package/scripts/verify-install.sh +266 -0
- package/src/superlocalmemory/__init__.py +0 -0
- package/src/superlocalmemory/attribution/__init__.py +9 -0
- package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
- package/src/superlocalmemory/attribution/signer.py +153 -0
- package/src/superlocalmemory/attribution/watermark.py +189 -0
- package/src/superlocalmemory/cli/__init__.py +5 -0
- package/src/superlocalmemory/cli/commands.py +245 -0
- package/src/superlocalmemory/cli/main.py +89 -0
- package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
- package/src/superlocalmemory/cli/post_install.py +99 -0
- package/src/superlocalmemory/cli/setup_wizard.py +129 -0
- package/src/superlocalmemory/compliance/__init__.py +0 -0
- package/src/superlocalmemory/compliance/abac.py +204 -0
- package/src/superlocalmemory/compliance/audit.py +314 -0
- package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
- package/src/superlocalmemory/compliance/gdpr.py +294 -0
- package/src/superlocalmemory/compliance/lifecycle.py +158 -0
- package/src/superlocalmemory/compliance/retention.py +232 -0
- package/src/superlocalmemory/compliance/scheduler.py +148 -0
- package/src/superlocalmemory/core/__init__.py +0 -0
- package/src/superlocalmemory/core/config.py +391 -0
- package/src/superlocalmemory/core/embeddings.py +293 -0
- package/src/superlocalmemory/core/engine.py +701 -0
- package/src/superlocalmemory/core/hooks.py +65 -0
- package/src/superlocalmemory/core/maintenance.py +172 -0
- package/src/superlocalmemory/core/modes.py +140 -0
- package/src/superlocalmemory/core/profiles.py +234 -0
- package/src/superlocalmemory/core/registry.py +117 -0
- package/src/superlocalmemory/dynamics/__init__.py +0 -0
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
- package/src/superlocalmemory/encoding/__init__.py +0 -0
- package/src/superlocalmemory/encoding/consolidator.py +485 -0
- package/src/superlocalmemory/encoding/emotional.py +125 -0
- package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
- package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
- package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
- package/src/superlocalmemory/encoding/foresight.py +91 -0
- package/src/superlocalmemory/encoding/graph_builder.py +302 -0
- package/src/superlocalmemory/encoding/observation_builder.py +160 -0
- package/src/superlocalmemory/encoding/scene_builder.py +183 -0
- package/src/superlocalmemory/encoding/signal_inference.py +90 -0
- package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
- package/src/superlocalmemory/encoding/type_router.py +235 -0
- package/src/superlocalmemory/hooks/__init__.py +3 -0
- package/src/superlocalmemory/hooks/auto_capture.py +111 -0
- package/src/superlocalmemory/hooks/auto_recall.py +93 -0
- package/src/superlocalmemory/hooks/ide_connector.py +204 -0
- package/src/superlocalmemory/hooks/rules_engine.py +99 -0
- package/src/superlocalmemory/infra/__init__.py +3 -0
- package/src/superlocalmemory/infra/auth_middleware.py +82 -0
- package/src/superlocalmemory/infra/backup.py +317 -0
- package/src/superlocalmemory/infra/cache_manager.py +267 -0
- package/src/superlocalmemory/infra/event_bus.py +381 -0
- package/src/superlocalmemory/infra/rate_limiter.py +135 -0
- package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
- package/src/superlocalmemory/learning/__init__.py +0 -0
- package/src/superlocalmemory/learning/adaptive.py +172 -0
- package/src/superlocalmemory/learning/behavioral.py +490 -0
- package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
- package/src/superlocalmemory/learning/bootstrap.py +298 -0
- package/src/superlocalmemory/learning/cross_project.py +399 -0
- package/src/superlocalmemory/learning/database.py +376 -0
- package/src/superlocalmemory/learning/engagement.py +323 -0
- package/src/superlocalmemory/learning/features.py +138 -0
- package/src/superlocalmemory/learning/feedback.py +316 -0
- package/src/superlocalmemory/learning/outcomes.py +255 -0
- package/src/superlocalmemory/learning/project_context.py +366 -0
- package/src/superlocalmemory/learning/ranker.py +155 -0
- package/src/superlocalmemory/learning/source_quality.py +303 -0
- package/src/superlocalmemory/learning/workflows.py +309 -0
- package/src/superlocalmemory/llm/__init__.py +0 -0
- package/src/superlocalmemory/llm/backbone.py +316 -0
- package/src/superlocalmemory/math/__init__.py +0 -0
- package/src/superlocalmemory/math/fisher.py +356 -0
- package/src/superlocalmemory/math/langevin.py +398 -0
- package/src/superlocalmemory/math/sheaf.py +257 -0
- package/src/superlocalmemory/mcp/__init__.py +0 -0
- package/src/superlocalmemory/mcp/resources.py +245 -0
- package/src/superlocalmemory/mcp/server.py +61 -0
- package/src/superlocalmemory/mcp/tools.py +18 -0
- package/src/superlocalmemory/mcp/tools_core.py +305 -0
- package/src/superlocalmemory/mcp/tools_v28.py +223 -0
- package/src/superlocalmemory/mcp/tools_v3.py +286 -0
- package/src/superlocalmemory/retrieval/__init__.py +0 -0
- package/src/superlocalmemory/retrieval/agentic.py +295 -0
- package/src/superlocalmemory/retrieval/ann_index.py +223 -0
- package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
- package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
- package/src/superlocalmemory/retrieval/engine.py +390 -0
- package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
- package/src/superlocalmemory/retrieval/fusion.py +78 -0
- package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
- package/src/superlocalmemory/retrieval/reranker.py +154 -0
- package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
- package/src/superlocalmemory/retrieval/strategy.py +96 -0
- package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
- package/src/superlocalmemory/server/__init__.py +1 -0
- package/src/superlocalmemory/server/api.py +248 -0
- package/src/superlocalmemory/server/routes/__init__.py +4 -0
- package/src/superlocalmemory/server/routes/agents.py +107 -0
- package/src/superlocalmemory/server/routes/backup.py +91 -0
- package/src/superlocalmemory/server/routes/behavioral.py +127 -0
- package/src/superlocalmemory/server/routes/compliance.py +160 -0
- package/src/superlocalmemory/server/routes/data_io.py +188 -0
- package/src/superlocalmemory/server/routes/events.py +183 -0
- package/src/superlocalmemory/server/routes/helpers.py +85 -0
- package/src/superlocalmemory/server/routes/learning.py +273 -0
- package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
- package/src/superlocalmemory/server/routes/memories.py +399 -0
- package/src/superlocalmemory/server/routes/profiles.py +219 -0
- package/src/superlocalmemory/server/routes/stats.py +346 -0
- package/src/superlocalmemory/server/routes/v3_api.py +365 -0
- package/src/superlocalmemory/server/routes/ws.py +82 -0
- package/src/superlocalmemory/server/security_middleware.py +57 -0
- package/src/superlocalmemory/server/ui.py +245 -0
- package/src/superlocalmemory/storage/__init__.py +0 -0
- package/src/superlocalmemory/storage/access_control.py +182 -0
- package/src/superlocalmemory/storage/database.py +594 -0
- package/src/superlocalmemory/storage/migrations.py +303 -0
- package/src/superlocalmemory/storage/models.py +406 -0
- package/src/superlocalmemory/storage/schema.py +726 -0
- package/src/superlocalmemory/storage/v2_migrator.py +317 -0
- package/src/superlocalmemory/trust/__init__.py +0 -0
- package/src/superlocalmemory/trust/gate.py +130 -0
- package/src/superlocalmemory/trust/provenance.py +124 -0
- package/src/superlocalmemory/trust/scorer.py +347 -0
- package/src/superlocalmemory/trust/signals.py +153 -0
- package/ui/index.html +278 -5
- package/ui/js/auto-settings.js +70 -0
- package/ui/js/dashboard.js +90 -0
- package/ui/js/fact-detail.js +92 -0
- package/ui/js/feedback.js +2 -2
- package/ui/js/ide-status.js +102 -0
- package/ui/js/math-health.js +98 -0
- package/ui/js/recall-lab.js +127 -0
- package/ui/js/settings.js +2 -2
- package/ui/js/trust-dashboard.js +73 -0
- package/api_server.py +0 -724
- package/bin/aider-smart +0 -72
- package/bin/superlocalmemoryv2-learning +0 -4
- package/bin/superlocalmemoryv2-list +0 -3
- package/bin/superlocalmemoryv2-patterns +0 -4
- package/bin/superlocalmemoryv2-profile +0 -3
- package/bin/superlocalmemoryv2-recall +0 -3
- package/bin/superlocalmemoryv2-remember +0 -3
- package/bin/superlocalmemoryv2-reset +0 -3
- package/bin/superlocalmemoryv2-status +0 -3
- package/configs/chatgpt-desktop-mcp.json +0 -16
- package/configs/cursor-mcp.json +0 -15
- package/hooks/memory-list-skill.js +0 -139
- package/hooks/memory-profile-skill.js +0 -273
- package/hooks/memory-recall-skill.js +0 -114
- package/hooks/memory-remember-skill.js +0 -127
- package/hooks/memory-reset-skill.js +0 -274
- package/mcp_server.py +0 -1808
- package/requirements-core.txt +0 -22
- package/requirements-learning.txt +0 -12
- package/requirements.txt +0 -12
- package/src/agent_registry.py +0 -411
- package/src/auth_middleware.py +0 -61
- package/src/auto_backup.py +0 -459
- package/src/behavioral/__init__.py +0 -49
- package/src/behavioral/behavioral_listener.py +0 -203
- package/src/behavioral/behavioral_patterns.py +0 -275
- package/src/behavioral/cross_project_transfer.py +0 -206
- package/src/behavioral/outcome_inference.py +0 -194
- package/src/behavioral/outcome_tracker.py +0 -193
- package/src/behavioral/tests/__init__.py +0 -4
- package/src/behavioral/tests/test_behavioral_integration.py +0 -108
- package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
- package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
- package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
- package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
- package/src/behavioral/tests/test_outcome_inference.py +0 -107
- package/src/behavioral/tests/test_outcome_tracker.py +0 -96
- package/src/cache_manager.py +0 -518
- package/src/compliance/__init__.py +0 -48
- package/src/compliance/abac_engine.py +0 -149
- package/src/compliance/abac_middleware.py +0 -116
- package/src/compliance/audit_db.py +0 -215
- package/src/compliance/audit_logger.py +0 -148
- package/src/compliance/retention_manager.py +0 -289
- package/src/compliance/retention_scheduler.py +0 -186
- package/src/compliance/tests/__init__.py +0 -4
- package/src/compliance/tests/test_abac_enforcement.py +0 -95
- package/src/compliance/tests/test_abac_engine.py +0 -124
- package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
- package/src/compliance/tests/test_audit_db.py +0 -123
- package/src/compliance/tests/test_audit_logger.py +0 -98
- package/src/compliance/tests/test_mcp_audit.py +0 -128
- package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
- package/src/compliance/tests/test_retention_manager.py +0 -131
- package/src/compliance/tests/test_retention_scheduler.py +0 -99
- package/src/compression/__init__.py +0 -25
- package/src/compression/cli.py +0 -150
- package/src/compression/cold_storage.py +0 -217
- package/src/compression/config.py +0 -72
- package/src/compression/orchestrator.py +0 -133
- package/src/compression/tier2_compressor.py +0 -228
- package/src/compression/tier3_compressor.py +0 -153
- package/src/compression/tier_classifier.py +0 -148
- package/src/db_connection_manager.py +0 -536
- package/src/embedding_engine.py +0 -63
- package/src/embeddings/__init__.py +0 -47
- package/src/embeddings/cache.py +0 -70
- package/src/embeddings/cli.py +0 -113
- package/src/embeddings/constants.py +0 -47
- package/src/embeddings/database.py +0 -91
- package/src/embeddings/engine.py +0 -247
- package/src/embeddings/model_loader.py +0 -145
- package/src/event_bus.py +0 -562
- package/src/graph/__init__.py +0 -36
- package/src/graph/build_helpers.py +0 -74
- package/src/graph/cli.py +0 -87
- package/src/graph/cluster_builder.py +0 -188
- package/src/graph/cluster_summary.py +0 -148
- package/src/graph/constants.py +0 -47
- package/src/graph/edge_builder.py +0 -162
- package/src/graph/entity_extractor.py +0 -95
- package/src/graph/graph_core.py +0 -226
- package/src/graph/graph_search.py +0 -231
- package/src/graph/hierarchical.py +0 -207
- package/src/graph/schema.py +0 -99
- package/src/graph_engine.py +0 -52
- package/src/hnsw_index.py +0 -628
- package/src/hybrid_search.py +0 -46
- package/src/learning/__init__.py +0 -217
- package/src/learning/adaptive_ranker.py +0 -682
- package/src/learning/bootstrap/__init__.py +0 -69
- package/src/learning/bootstrap/constants.py +0 -93
- package/src/learning/bootstrap/db_queries.py +0 -316
- package/src/learning/bootstrap/sampling.py +0 -82
- package/src/learning/bootstrap/text_utils.py +0 -71
- package/src/learning/cross_project_aggregator.py +0 -857
- package/src/learning/db/__init__.py +0 -40
- package/src/learning/db/constants.py +0 -44
- package/src/learning/db/schema.py +0 -279
- package/src/learning/engagement_tracker.py +0 -628
- package/src/learning/feature_extractor.py +0 -708
- package/src/learning/feedback_collector.py +0 -806
- package/src/learning/learning_db.py +0 -915
- package/src/learning/project_context_manager.py +0 -572
- package/src/learning/ranking/__init__.py +0 -33
- package/src/learning/ranking/constants.py +0 -84
- package/src/learning/ranking/helpers.py +0 -278
- package/src/learning/source_quality_scorer.py +0 -676
- package/src/learning/synthetic_bootstrap.py +0 -755
- package/src/learning/tests/test_adaptive_ranker.py +0 -325
- package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
- package/src/learning/tests/test_aggregator.py +0 -306
- package/src/learning/tests/test_auto_retrain_v28.py +0 -35
- package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
- package/src/learning/tests/test_feature_extractor_v28.py +0 -93
- package/src/learning/tests/test_feedback_collector.py +0 -294
- package/src/learning/tests/test_learning_db.py +0 -602
- package/src/learning/tests/test_learning_db_v28.py +0 -110
- package/src/learning/tests/test_learning_init_v28.py +0 -48
- package/src/learning/tests/test_outcome_signals.py +0 -48
- package/src/learning/tests/test_project_context.py +0 -292
- package/src/learning/tests/test_schema_migration.py +0 -319
- package/src/learning/tests/test_signal_inference.py +0 -397
- package/src/learning/tests/test_source_quality.py +0 -351
- package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
- package/src/learning/tests/test_workflow_miner.py +0 -318
- package/src/learning/workflow_pattern_miner.py +0 -655
- package/src/lifecycle/__init__.py +0 -54
- package/src/lifecycle/bounded_growth.py +0 -239
- package/src/lifecycle/compaction_engine.py +0 -226
- package/src/lifecycle/lifecycle_engine.py +0 -355
- package/src/lifecycle/lifecycle_evaluator.py +0 -257
- package/src/lifecycle/lifecycle_scheduler.py +0 -130
- package/src/lifecycle/retention_policy.py +0 -285
- package/src/lifecycle/tests/test_bounded_growth.py +0 -193
- package/src/lifecycle/tests/test_compaction.py +0 -179
- package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
- package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
- package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
- package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
- package/src/lifecycle/tests/test_mcp_compact.py +0 -149
- package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
- package/src/lifecycle/tests/test_retention_policy.py +0 -162
- package/src/mcp_tools_v28.py +0 -281
- package/src/memory/__init__.py +0 -36
- package/src/memory/cli.py +0 -205
- package/src/memory/constants.py +0 -39
- package/src/memory/helpers.py +0 -28
- package/src/memory/schema.py +0 -166
- package/src/memory-profiles.py +0 -595
- package/src/memory-reset.py +0 -491
- package/src/memory_compression.py +0 -989
- package/src/memory_store_v2.py +0 -1155
- package/src/migrate_v1_to_v2.py +0 -629
- package/src/pattern_learner.py +0 -34
- package/src/patterns/__init__.py +0 -24
- package/src/patterns/analyzers.py +0 -251
- package/src/patterns/learner.py +0 -271
- package/src/patterns/scoring.py +0 -171
- package/src/patterns/store.py +0 -225
- package/src/patterns/terminology.py +0 -140
- package/src/provenance_tracker.py +0 -312
- package/src/qualixar_attribution.py +0 -139
- package/src/qualixar_watermark.py +0 -78
- package/src/query_optimizer.py +0 -511
- package/src/rate_limiter.py +0 -83
- package/src/search/__init__.py +0 -20
- package/src/search/cli.py +0 -77
- package/src/search/constants.py +0 -26
- package/src/search/engine.py +0 -241
- package/src/search/fusion.py +0 -122
- package/src/search/index_loader.py +0 -114
- package/src/search/methods.py +0 -162
- package/src/search_engine_v2.py +0 -401
- package/src/setup_validator.py +0 -482
- package/src/subscription_manager.py +0 -391
- package/src/tree/__init__.py +0 -59
- package/src/tree/builder.py +0 -185
- package/src/tree/nodes.py +0 -202
- package/src/tree/queries.py +0 -257
- package/src/tree/schema.py +0 -80
- package/src/tree_manager.py +0 -19
- package/src/trust/__init__.py +0 -45
- package/src/trust/constants.py +0 -66
- package/src/trust/queries.py +0 -157
- package/src/trust/schema.py +0 -95
- package/src/trust/scorer.py +0 -299
- package/src/trust/signals.py +0 -95
- package/src/trust_scorer.py +0 -44
- package/ui/app.js +0 -1588
- package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
- package/ui/js/graph-cytoscape.js +0 -1168
- package/ui/js/graph-d3-backup.js +0 -32
- package/ui/js/graph.js +0 -32
- package/ui_server.py +0 -286
- /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
- /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
- /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
- /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
- /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
- /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
- /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
- /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
- /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
- /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
- /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
- /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
- /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
- /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
- /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
- /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
- /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
- /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
- /package/{completions → ide/completions}/slm.bash +0 -0
- /package/{completions → ide/completions}/slm.zsh +0 -0
- /package/{configs → ide/configs}/cody-commands.json +0 -0
- /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
- /package/{install.ps1 → scripts/install.ps1} +0 -0
- /package/{install.sh → scripts/install.sh} +0 -0
package/src/auto_backup.py
DELETED
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""SuperLocalMemory V2 - Auto Backup System
|
|
5
|
-
|
|
6
|
-
Automated backup system for memory.db:
|
|
7
|
-
- Configurable interval: 24h (daily) or 7 days (weekly, default)
|
|
8
|
-
- Timestamped backups in ~/.claude-memory/backups/
|
|
9
|
-
- Retention policy: keeps last N backups (default 10)
|
|
10
|
-
- Auto-triggers on memory operations when backup is due
|
|
11
|
-
- Manual backup via CLI
|
|
12
|
-
"""
|
|
13
|
-
import sqlite3
|
|
14
|
-
import shutil
|
|
15
|
-
import json
|
|
16
|
-
import logging
|
|
17
|
-
from datetime import datetime, timedelta
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from typing import Dict, List, Optional
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
MEMORY_DIR = Path.home() / ".claude-memory"
|
|
24
|
-
DB_PATH = MEMORY_DIR / "memory.db"
|
|
25
|
-
BACKUP_DIR = MEMORY_DIR / "backups"
|
|
26
|
-
CONFIG_FILE = MEMORY_DIR / "backup_config.json"
|
|
27
|
-
|
|
28
|
-
# Defaults
|
|
29
|
-
DEFAULT_INTERVAL_HOURS = 168 # 7 days
|
|
30
|
-
DEFAULT_MAX_BACKUPS = 10
|
|
31
|
-
MIN_INTERVAL_HOURS = 1 # Safety: no more than once per hour
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class AutoBackup:
|
|
35
|
-
"""Automated backup manager for SuperLocalMemory V2."""
|
|
36
|
-
|
|
37
|
-
def __init__(self, db_path: Path = DB_PATH, backup_dir: Path = BACKUP_DIR):
|
|
38
|
-
self.db_path = db_path
|
|
39
|
-
self.backup_dir = backup_dir
|
|
40
|
-
self.config = self._load_config()
|
|
41
|
-
self._ensure_backup_dir()
|
|
42
|
-
|
|
43
|
-
def _ensure_backup_dir(self):
|
|
44
|
-
"""Create backup directory if it doesn't exist."""
|
|
45
|
-
self.backup_dir.mkdir(parents=True, exist_ok=True)
|
|
46
|
-
|
|
47
|
-
def _load_config(self) -> Dict:
|
|
48
|
-
"""Load backup configuration."""
|
|
49
|
-
if CONFIG_FILE.exists():
|
|
50
|
-
try:
|
|
51
|
-
with open(CONFIG_FILE, 'r') as f:
|
|
52
|
-
config = json.load(f)
|
|
53
|
-
# Merge with defaults for any missing keys
|
|
54
|
-
defaults = self._default_config()
|
|
55
|
-
for key in defaults:
|
|
56
|
-
if key not in config:
|
|
57
|
-
config[key] = defaults[key]
|
|
58
|
-
return config
|
|
59
|
-
except (json.JSONDecodeError, IOError):
|
|
60
|
-
pass
|
|
61
|
-
return self._default_config()
|
|
62
|
-
|
|
63
|
-
def _default_config(self) -> Dict:
|
|
64
|
-
"""Return default configuration."""
|
|
65
|
-
return {
|
|
66
|
-
'enabled': True,
|
|
67
|
-
'interval_hours': DEFAULT_INTERVAL_HOURS,
|
|
68
|
-
'max_backups': DEFAULT_MAX_BACKUPS,
|
|
69
|
-
'last_backup': None,
|
|
70
|
-
'last_backup_file': None,
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
def _save_config(self):
|
|
74
|
-
"""Save configuration to disk."""
|
|
75
|
-
try:
|
|
76
|
-
with open(CONFIG_FILE, 'w') as f:
|
|
77
|
-
json.dump(self.config, f, indent=2)
|
|
78
|
-
except IOError as e:
|
|
79
|
-
logger.error(f"Failed to save backup config: {e}")
|
|
80
|
-
|
|
81
|
-
def configure(self, interval_hours: Optional[int] = None,
|
|
82
|
-
max_backups: Optional[int] = None,
|
|
83
|
-
enabled: Optional[bool] = None) -> Dict:
|
|
84
|
-
"""
|
|
85
|
-
Update backup configuration.
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
interval_hours: Hours between backups (24 for daily, 168 for weekly)
|
|
89
|
-
max_backups: Maximum number of backup files to retain
|
|
90
|
-
enabled: Enable/disable auto-backup
|
|
91
|
-
|
|
92
|
-
Returns:
|
|
93
|
-
Updated configuration
|
|
94
|
-
"""
|
|
95
|
-
if interval_hours is not None:
|
|
96
|
-
self.config['interval_hours'] = max(MIN_INTERVAL_HOURS, interval_hours)
|
|
97
|
-
if max_backups is not None:
|
|
98
|
-
self.config['max_backups'] = max(1, max_backups)
|
|
99
|
-
if enabled is not None:
|
|
100
|
-
self.config['enabled'] = enabled
|
|
101
|
-
|
|
102
|
-
self._save_config()
|
|
103
|
-
return self.get_status()
|
|
104
|
-
|
|
105
|
-
def is_backup_due(self) -> bool:
|
|
106
|
-
"""Check if a backup is due based on configured interval."""
|
|
107
|
-
if not self.config.get('enabled', True):
|
|
108
|
-
return False
|
|
109
|
-
|
|
110
|
-
last_backup = self.config.get('last_backup')
|
|
111
|
-
if not last_backup:
|
|
112
|
-
return True # Never backed up
|
|
113
|
-
|
|
114
|
-
try:
|
|
115
|
-
last_dt = datetime.fromisoformat(last_backup)
|
|
116
|
-
interval = timedelta(hours=self.config.get('interval_hours', DEFAULT_INTERVAL_HOURS))
|
|
117
|
-
return datetime.now() >= last_dt + interval
|
|
118
|
-
except (ValueError, TypeError):
|
|
119
|
-
return True # Invalid date, backup now
|
|
120
|
-
|
|
121
|
-
def check_and_backup(self) -> Optional[str]:
|
|
122
|
-
"""
|
|
123
|
-
Check if backup is due and create one if needed.
|
|
124
|
-
Called automatically by memory operations.
|
|
125
|
-
|
|
126
|
-
Returns:
|
|
127
|
-
Backup filename if created, None if not due
|
|
128
|
-
"""
|
|
129
|
-
if not self.is_backup_due():
|
|
130
|
-
return None
|
|
131
|
-
|
|
132
|
-
return self.create_backup()
|
|
133
|
-
|
|
134
|
-
def create_backup(self, label: Optional[str] = None) -> str:
|
|
135
|
-
"""
|
|
136
|
-
Create a backup of memory.db.
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
label: Optional label for the backup (e.g., 'pre-migration')
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
Backup filename
|
|
143
|
-
"""
|
|
144
|
-
if not self.db_path.exists():
|
|
145
|
-
logger.warning("No database to backup")
|
|
146
|
-
return ""
|
|
147
|
-
|
|
148
|
-
self._ensure_backup_dir()
|
|
149
|
-
|
|
150
|
-
# Generate timestamped filename
|
|
151
|
-
timestamp = datetime.now().strftime('%Y%m%d-%H%M%S')
|
|
152
|
-
label_suffix = f"-{label}" if label else ""
|
|
153
|
-
backup_name = f"memory-{timestamp}{label_suffix}.db"
|
|
154
|
-
backup_path = self.backup_dir / backup_name
|
|
155
|
-
|
|
156
|
-
try:
|
|
157
|
-
# Use SQLite backup API for consistency (safe even during writes)
|
|
158
|
-
source_conn = sqlite3.connect(self.db_path)
|
|
159
|
-
backup_conn = sqlite3.connect(backup_path)
|
|
160
|
-
try:
|
|
161
|
-
source_conn.backup(backup_conn)
|
|
162
|
-
finally:
|
|
163
|
-
backup_conn.close()
|
|
164
|
-
source_conn.close()
|
|
165
|
-
|
|
166
|
-
# Get backup size
|
|
167
|
-
size_mb = backup_path.stat().st_size / (1024 * 1024)
|
|
168
|
-
|
|
169
|
-
# Update config
|
|
170
|
-
self.config['last_backup'] = datetime.now().isoformat()
|
|
171
|
-
self.config['last_backup_file'] = backup_name
|
|
172
|
-
self._save_config()
|
|
173
|
-
|
|
174
|
-
logger.info(f"Backup created: {backup_name} ({size_mb:.1f} MB)")
|
|
175
|
-
|
|
176
|
-
# v2.7.4: Also backup learning.db if it exists
|
|
177
|
-
learning_db = self.db_path.parent / "learning.db"
|
|
178
|
-
if learning_db.exists():
|
|
179
|
-
try:
|
|
180
|
-
learning_backup_name = f"learning-{timestamp}{label_suffix}.db"
|
|
181
|
-
learning_backup_path = self.backup_dir / learning_backup_name
|
|
182
|
-
l_source = sqlite3.connect(learning_db)
|
|
183
|
-
l_backup = sqlite3.connect(learning_backup_path)
|
|
184
|
-
try:
|
|
185
|
-
l_source.backup(l_backup)
|
|
186
|
-
finally:
|
|
187
|
-
l_backup.close()
|
|
188
|
-
l_source.close()
|
|
189
|
-
l_size = learning_backup_path.stat().st_size / (1024 * 1024)
|
|
190
|
-
logger.info(f"Learning backup created: {learning_backup_name} ({l_size:.1f} MB)")
|
|
191
|
-
except Exception as le:
|
|
192
|
-
logger.warning(f"Learning DB backup failed (non-critical): {le}")
|
|
193
|
-
|
|
194
|
-
# Enforce retention policy
|
|
195
|
-
self._enforce_retention()
|
|
196
|
-
|
|
197
|
-
return backup_name
|
|
198
|
-
|
|
199
|
-
except Exception as e:
|
|
200
|
-
logger.error(f"Backup failed: {e}")
|
|
201
|
-
# Clean up partial backup
|
|
202
|
-
if backup_path.exists():
|
|
203
|
-
backup_path.unlink()
|
|
204
|
-
return ""
|
|
205
|
-
|
|
206
|
-
def _enforce_retention(self):
|
|
207
|
-
"""Remove old backups exceeding max_backups limit."""
|
|
208
|
-
max_backups = self.config.get('max_backups', DEFAULT_MAX_BACKUPS)
|
|
209
|
-
|
|
210
|
-
# Enforce for both memory and learning backups (v2.7.4)
|
|
211
|
-
for pattern in ['memory-*.db', 'learning-*.db']:
|
|
212
|
-
backups = sorted(
|
|
213
|
-
self.backup_dir.glob(pattern),
|
|
214
|
-
key=lambda f: f.stat().st_mtime
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
while len(backups) > max_backups:
|
|
218
|
-
oldest = backups.pop(0)
|
|
219
|
-
try:
|
|
220
|
-
oldest.unlink()
|
|
221
|
-
logger.info(f"Removed old backup: {oldest.name}")
|
|
222
|
-
except OSError as e:
|
|
223
|
-
logger.error(f"Failed to remove old backup {oldest.name}: {e}")
|
|
224
|
-
|
|
225
|
-
def list_backups(self) -> List[Dict]:
|
|
226
|
-
"""
|
|
227
|
-
List all available backups (memory.db + learning.db).
|
|
228
|
-
|
|
229
|
-
Returns:
|
|
230
|
-
List of backup info dictionaries
|
|
231
|
-
"""
|
|
232
|
-
backups = []
|
|
233
|
-
|
|
234
|
-
if not self.backup_dir.exists():
|
|
235
|
-
return backups
|
|
236
|
-
|
|
237
|
-
# v2.7.4: List both memory and learning backups
|
|
238
|
-
for pattern in ['memory-*.db', 'learning-*.db']:
|
|
239
|
-
for backup_file in sorted(
|
|
240
|
-
self.backup_dir.glob(pattern),
|
|
241
|
-
key=lambda f: f.stat().st_mtime,
|
|
242
|
-
reverse=True
|
|
243
|
-
):
|
|
244
|
-
stat = backup_file.stat()
|
|
245
|
-
db_type = 'learning' if backup_file.name.startswith('learning-') else 'memory'
|
|
246
|
-
backups.append({
|
|
247
|
-
'filename': backup_file.name,
|
|
248
|
-
'path': str(backup_file),
|
|
249
|
-
'size_mb': round(stat.st_size / (1024 * 1024), 2),
|
|
250
|
-
'created': datetime.fromtimestamp(stat.st_mtime).isoformat(),
|
|
251
|
-
'age_hours': round((datetime.now() - datetime.fromtimestamp(stat.st_mtime)).total_seconds() / 3600, 1),
|
|
252
|
-
'type': db_type,
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
# Sort all by creation time (newest first)
|
|
256
|
-
backups.sort(key=lambda b: b['created'], reverse=True)
|
|
257
|
-
return backups
|
|
258
|
-
|
|
259
|
-
def restore_backup(self, filename: str) -> bool:
|
|
260
|
-
"""
|
|
261
|
-
Restore database from a backup file.
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
filename: Backup filename to restore from
|
|
265
|
-
|
|
266
|
-
Returns:
|
|
267
|
-
Success status
|
|
268
|
-
"""
|
|
269
|
-
backup_path = self.backup_dir / filename
|
|
270
|
-
|
|
271
|
-
if not backup_path.exists():
|
|
272
|
-
logger.error(f"Backup file not found: {filename}")
|
|
273
|
-
return False
|
|
274
|
-
|
|
275
|
-
try:
|
|
276
|
-
# Create a safety backup of current state first
|
|
277
|
-
self.create_backup(label='pre-restore')
|
|
278
|
-
|
|
279
|
-
# Determine target DB based on filename prefix
|
|
280
|
-
if filename.startswith('learning-'):
|
|
281
|
-
target_db = self.db_path.parent / "learning.db"
|
|
282
|
-
else:
|
|
283
|
-
target_db = self.db_path
|
|
284
|
-
|
|
285
|
-
# Restore using SQLite backup API
|
|
286
|
-
source_conn = sqlite3.connect(backup_path)
|
|
287
|
-
target_conn = sqlite3.connect(target_db)
|
|
288
|
-
try:
|
|
289
|
-
source_conn.backup(target_conn)
|
|
290
|
-
finally:
|
|
291
|
-
target_conn.close()
|
|
292
|
-
source_conn.close()
|
|
293
|
-
|
|
294
|
-
logger.info(f"Restored from backup: {filename} → {target_db.name}")
|
|
295
|
-
return True
|
|
296
|
-
|
|
297
|
-
except Exception as e:
|
|
298
|
-
logger.error(f"Restore failed: {e}")
|
|
299
|
-
return False
|
|
300
|
-
|
|
301
|
-
def get_status(self) -> Dict:
|
|
302
|
-
"""
|
|
303
|
-
Get backup system status.
|
|
304
|
-
|
|
305
|
-
Returns:
|
|
306
|
-
Status dictionary
|
|
307
|
-
"""
|
|
308
|
-
backups = self.list_backups()
|
|
309
|
-
next_backup = None
|
|
310
|
-
|
|
311
|
-
if self.config.get('enabled') and self.config.get('last_backup'):
|
|
312
|
-
try:
|
|
313
|
-
last_dt = datetime.fromisoformat(self.config['last_backup'])
|
|
314
|
-
interval = timedelta(hours=self.config.get('interval_hours', DEFAULT_INTERVAL_HOURS))
|
|
315
|
-
next_dt = last_dt + interval
|
|
316
|
-
if next_dt > datetime.now():
|
|
317
|
-
next_backup = next_dt.isoformat()
|
|
318
|
-
else:
|
|
319
|
-
next_backup = 'overdue'
|
|
320
|
-
except (ValueError, TypeError):
|
|
321
|
-
next_backup = 'unknown'
|
|
322
|
-
|
|
323
|
-
# Calculate interval display
|
|
324
|
-
hours = self.config.get('interval_hours', DEFAULT_INTERVAL_HOURS)
|
|
325
|
-
if hours >= 168:
|
|
326
|
-
interval_display = f"{hours // 168} week(s)"
|
|
327
|
-
elif hours >= 24:
|
|
328
|
-
interval_display = f"{hours // 24} day(s)"
|
|
329
|
-
else:
|
|
330
|
-
interval_display = f"{hours} hour(s)"
|
|
331
|
-
|
|
332
|
-
# v2.7.4: Separate counts for memory vs learning backups
|
|
333
|
-
memory_backups = [b for b in backups if b.get('type') == 'memory']
|
|
334
|
-
learning_backups = [b for b in backups if b.get('type') == 'learning']
|
|
335
|
-
|
|
336
|
-
return {
|
|
337
|
-
'enabled': self.config.get('enabled', True),
|
|
338
|
-
'interval_hours': hours,
|
|
339
|
-
'interval_display': interval_display,
|
|
340
|
-
'max_backups': self.config.get('max_backups', DEFAULT_MAX_BACKUPS),
|
|
341
|
-
'last_backup': self.config.get('last_backup'),
|
|
342
|
-
'last_backup_file': self.config.get('last_backup_file'),
|
|
343
|
-
'next_backup': next_backup,
|
|
344
|
-
'backup_count': len(memory_backups),
|
|
345
|
-
'learning_backup_count': len(learning_backups),
|
|
346
|
-
'total_size_mb': round(sum(b['size_mb'] for b in backups), 2),
|
|
347
|
-
'backups': backups,
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
# CLI Interface
|
|
352
|
-
if __name__ == "__main__":
|
|
353
|
-
import sys
|
|
354
|
-
|
|
355
|
-
backup = AutoBackup()
|
|
356
|
-
|
|
357
|
-
if len(sys.argv) < 2:
|
|
358
|
-
print("Auto Backup System - SuperLocalMemory V2")
|
|
359
|
-
print("\nUsage:")
|
|
360
|
-
print(" python auto_backup.py status Show backup status")
|
|
361
|
-
print(" python auto_backup.py backup [label] Create backup now")
|
|
362
|
-
print(" python auto_backup.py list List all backups")
|
|
363
|
-
print(" python auto_backup.py restore <filename> Restore from backup")
|
|
364
|
-
print(" python auto_backup.py configure Show/set configuration")
|
|
365
|
-
print(" --interval <hours> Set backup interval (24=daily, 168=weekly)")
|
|
366
|
-
print(" --max-backups <N> Set max retained backups")
|
|
367
|
-
print(" --enable Enable auto-backup")
|
|
368
|
-
print(" --disable Disable auto-backup")
|
|
369
|
-
sys.exit(0)
|
|
370
|
-
|
|
371
|
-
command = sys.argv[1]
|
|
372
|
-
|
|
373
|
-
if command == "status":
|
|
374
|
-
status = backup.get_status()
|
|
375
|
-
print(f"\nAuto-Backup Status")
|
|
376
|
-
print(f"{'='*40}")
|
|
377
|
-
print(f" Enabled: {'Yes' if status['enabled'] else 'No'}")
|
|
378
|
-
print(f" Interval: {status['interval_display']}")
|
|
379
|
-
print(f" Max backups: {status['max_backups']}")
|
|
380
|
-
print(f" Last backup: {status['last_backup'] or 'Never'}")
|
|
381
|
-
print(f" Next backup: {status['next_backup'] or 'N/A'}")
|
|
382
|
-
print(f" Backup count: {status['backup_count']}")
|
|
383
|
-
print(f" Total size: {status['total_size_mb']} MB")
|
|
384
|
-
|
|
385
|
-
elif command == "backup":
|
|
386
|
-
label = sys.argv[2] if len(sys.argv) > 2 else None
|
|
387
|
-
print("Creating backup...")
|
|
388
|
-
result = backup.create_backup(label=label)
|
|
389
|
-
if result:
|
|
390
|
-
print(f"Backup created: {result}")
|
|
391
|
-
else:
|
|
392
|
-
print("Backup failed!")
|
|
393
|
-
sys.exit(1)
|
|
394
|
-
|
|
395
|
-
elif command == "list":
|
|
396
|
-
backups = backup.list_backups()
|
|
397
|
-
if not backups:
|
|
398
|
-
print("No backups found.")
|
|
399
|
-
else:
|
|
400
|
-
print(f"\n{'Filename':<45} {'Size':<10} {'Age':<15} {'Created'}")
|
|
401
|
-
print("-" * 95)
|
|
402
|
-
for b in backups:
|
|
403
|
-
age = f"{b['age_hours']:.0f}h" if b['age_hours'] < 48 else f"{b['age_hours']/24:.0f}d"
|
|
404
|
-
created = b['created'][:19]
|
|
405
|
-
print(f"{b['filename']:<45} {b['size_mb']:<10.2f} {age:<15} {created}")
|
|
406
|
-
|
|
407
|
-
elif command == "restore":
|
|
408
|
-
if len(sys.argv) < 3:
|
|
409
|
-
print("Error: Backup filename required")
|
|
410
|
-
print("Usage: python auto_backup.py restore <filename>")
|
|
411
|
-
sys.exit(1)
|
|
412
|
-
filename = sys.argv[2]
|
|
413
|
-
print(f"Restoring from {filename}...")
|
|
414
|
-
if backup.restore_backup(filename):
|
|
415
|
-
print("Restore successful! Restart any running tools to use the restored data.")
|
|
416
|
-
else:
|
|
417
|
-
print("Restore failed!")
|
|
418
|
-
sys.exit(1)
|
|
419
|
-
|
|
420
|
-
elif command == "configure":
|
|
421
|
-
interval = None
|
|
422
|
-
max_bk = None
|
|
423
|
-
enabled = None
|
|
424
|
-
|
|
425
|
-
i = 2
|
|
426
|
-
while i < len(sys.argv):
|
|
427
|
-
if sys.argv[i] == '--interval' and i + 1 < len(sys.argv):
|
|
428
|
-
interval = int(sys.argv[i + 1])
|
|
429
|
-
i += 2
|
|
430
|
-
elif sys.argv[i] == '--max-backups' and i + 1 < len(sys.argv):
|
|
431
|
-
max_bk = int(sys.argv[i + 1])
|
|
432
|
-
i += 2
|
|
433
|
-
elif sys.argv[i] == '--enable':
|
|
434
|
-
enabled = True
|
|
435
|
-
i += 1
|
|
436
|
-
elif sys.argv[i] == '--disable':
|
|
437
|
-
enabled = False
|
|
438
|
-
i += 1
|
|
439
|
-
else:
|
|
440
|
-
i += 1
|
|
441
|
-
|
|
442
|
-
if interval is not None or max_bk is not None or enabled is not None:
|
|
443
|
-
status = backup.configure(
|
|
444
|
-
interval_hours=interval,
|
|
445
|
-
max_backups=max_bk,
|
|
446
|
-
enabled=enabled
|
|
447
|
-
)
|
|
448
|
-
print("Configuration updated:")
|
|
449
|
-
else:
|
|
450
|
-
status = backup.get_status()
|
|
451
|
-
print("Current configuration:")
|
|
452
|
-
|
|
453
|
-
print(f" Enabled: {'Yes' if status['enabled'] else 'No'}")
|
|
454
|
-
print(f" Interval: {status['interval_display']}")
|
|
455
|
-
print(f" Max backups: {status['max_backups']}")
|
|
456
|
-
|
|
457
|
-
else:
|
|
458
|
-
print(f"Unknown command: {command}")
|
|
459
|
-
sys.exit(1)
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# SPDX-License-Identifier: MIT
|
|
2
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
3
|
-
"""SLM v2.8 Behavioral Learning Engine — Action Outcome Learning.
|
|
4
|
-
|
|
5
|
-
Tracks what happens AFTER memories are recalled (success/failure/partial).
|
|
6
|
-
Extracts behavioral patterns. Transfers across projects (privacy-safe).
|
|
7
|
-
All local, zero-LLM.
|
|
8
|
-
|
|
9
|
-
Graceful degradation: if this module fails to import,
|
|
10
|
-
adaptive ranking continues with v2.7 features only.
|
|
11
|
-
"""
|
|
12
|
-
import threading
|
|
13
|
-
from pathlib import Path
|
|
14
|
-
from typing import Optional, Dict, Any
|
|
15
|
-
|
|
16
|
-
BEHAVIORAL_AVAILABLE = False
|
|
17
|
-
_init_error = None
|
|
18
|
-
|
|
19
|
-
try:
|
|
20
|
-
from .outcome_tracker import OutcomeTracker
|
|
21
|
-
from .behavioral_patterns import BehavioralPatternExtractor
|
|
22
|
-
BEHAVIORAL_AVAILABLE = True
|
|
23
|
-
except ImportError as e:
|
|
24
|
-
_init_error = str(e)
|
|
25
|
-
|
|
26
|
-
_outcome_tracker: Optional["OutcomeTracker"] = None
|
|
27
|
-
_tracker_lock = threading.Lock()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def get_outcome_tracker(db_path: Optional[Path] = None) -> Optional["OutcomeTracker"]:
|
|
31
|
-
"""Get or create the outcome tracker singleton."""
|
|
32
|
-
global _outcome_tracker
|
|
33
|
-
if not BEHAVIORAL_AVAILABLE:
|
|
34
|
-
return None
|
|
35
|
-
with _tracker_lock:
|
|
36
|
-
if _outcome_tracker is None:
|
|
37
|
-
try:
|
|
38
|
-
_outcome_tracker = OutcomeTracker(db_path)
|
|
39
|
-
except Exception:
|
|
40
|
-
return None
|
|
41
|
-
return _outcome_tracker
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def get_status() -> Dict[str, Any]:
|
|
45
|
-
return {
|
|
46
|
-
"behavioral_available": BEHAVIORAL_AVAILABLE,
|
|
47
|
-
"init_error": _init_error,
|
|
48
|
-
"tracker_active": _outcome_tracker is not None,
|
|
49
|
-
}
|