superlocalmemory 3.6.23 → 3.7.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/CHANGELOG.md +61 -0
- package/README.md +271 -71
- package/bin/slm-npm +43 -89
- package/ide/configs/antigravity-mcp.json +2 -2
- package/ide/configs/chatgpt-desktop-mcp.json +1 -1
- package/ide/configs/claude-desktop-mcp.json +2 -2
- package/ide/configs/windsurf-mcp.json +2 -2
- package/ide/hooks/context-hook.js +6 -2
- package/ide/hooks/post-recall-hook.js +7 -3
- package/ide/hooks/tool-event-hook.sh +2 -1
- package/package.json +17 -9
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/_GENERATED.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/agents/slm-memory-advisor.md +1 -1
- package/plugin-src/manifest.json +1 -1
- package/plugin-src/requirements.txt +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/pyproject.toml +40 -8
- package/scripts/postinstall-interactive.js +17 -94
- package/scripts/postinstall.js +185 -258
- package/scripts/preuninstall.js +9 -50
- package/src/superlocalmemory/__init__.py +2 -2
- package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
- package/src/superlocalmemory/attribution/signer.py +34 -19
- package/src/superlocalmemory/attribution/watermark.py +1 -1
- package/src/superlocalmemory/cli/_lazy_init.py +7 -7
- package/src/superlocalmemory/cli/commands.py +453 -191
- package/src/superlocalmemory/cli/context_commands.py +5 -4
- package/src/superlocalmemory/cli/daemon.py +282 -187
- package/src/superlocalmemory/cli/db_migrate.py +3 -1
- package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
- package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
- package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
- package/src/superlocalmemory/cli/main.py +128 -31
- package/src/superlocalmemory/cli/pending_store.py +54 -38
- package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
- package/src/superlocalmemory/cli/service_installer.py +57 -52
- package/src/superlocalmemory/cli/setup_wizard.py +142 -88
- package/src/superlocalmemory/cli/version_banner.py +2 -1
- package/src/superlocalmemory/code_graph/config.py +3 -1
- package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
- package/src/superlocalmemory/core/config.py +65 -20
- package/src/superlocalmemory/core/consolidation_engine.py +9 -7
- package/src/superlocalmemory/core/context_cache.py +56 -8
- package/src/superlocalmemory/core/derivation_lineage.py +246 -0
- package/src/superlocalmemory/core/embedding_worker.py +32 -20
- package/src/superlocalmemory/core/embeddings.py +54 -18
- package/src/superlocalmemory/core/engine.py +150 -104
- package/src/superlocalmemory/core/engine_ingestion.py +513 -0
- package/src/superlocalmemory/core/engine_wiring.py +32 -23
- package/src/superlocalmemory/core/evidence_bundle.py +526 -0
- package/src/superlocalmemory/core/fact_consolidator.py +5 -11
- package/src/superlocalmemory/core/graph_analyzer.py +2 -2
- package/src/superlocalmemory/core/health_monitor.py +4 -2
- package/src/superlocalmemory/core/ingestion_command.py +636 -0
- package/src/superlocalmemory/core/injection.py +69 -18
- package/src/superlocalmemory/core/lifecycle_state.py +153 -0
- package/src/superlocalmemory/core/maintenance.py +1 -1
- package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
- package/src/superlocalmemory/core/mutations.py +143 -0
- package/src/superlocalmemory/core/platform_utils.py +7 -4
- package/src/superlocalmemory/core/ram_lock.py +16 -5
- package/src/superlocalmemory/core/rate_limit.py +1 -1
- package/src/superlocalmemory/core/recall_pipeline.py +60 -101
- package/src/superlocalmemory/core/recall_worker.py +76 -59
- package/src/superlocalmemory/core/registry.py +1 -1
- package/src/superlocalmemory/core/scale_engine.py +293 -0
- package/src/superlocalmemory/core/score_contract.py +62 -0
- package/src/superlocalmemory/core/security_primitives.py +3 -1
- package/src/superlocalmemory/core/slm_disabled.py +3 -5
- package/src/superlocalmemory/core/store_pipeline.py +172 -40
- package/src/superlocalmemory/core/tier_manager.py +32 -20
- package/src/superlocalmemory/core/worker_pool.py +13 -4
- package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
- package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
- package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
- package/src/superlocalmemory/encoding/auto_linker.py +1 -1
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
- package/src/superlocalmemory/encoding/consolidator.py +22 -5
- package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
- package/src/superlocalmemory/encoding/foresight.py +2 -0
- package/src/superlocalmemory/encoding/graph_builder.py +1 -1
- package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
- package/src/superlocalmemory/evaluation/__init__.py +13 -0
- package/src/superlocalmemory/evaluation/calibration.py +308 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
- package/src/superlocalmemory/graph/cozo_backend.py +256 -23
- package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
- package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
- package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
- package/src/superlocalmemory/hooks/auto_recall.py +31 -6
- package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
- package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
- package/src/superlocalmemory/hooks/claude_code_hooks.py +123 -35
- package/src/superlocalmemory/hooks/codex_assets.py +59 -0
- package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
- package/src/superlocalmemory/hooks/context_payload.py +1 -1
- package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
- package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
- package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
- package/src/superlocalmemory/hooks/hook_handlers.py +219 -32
- package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
- package/src/superlocalmemory/hooks/session_registry.py +15 -8
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
- package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
- package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
- package/src/superlocalmemory/infra/auth_middleware.py +38 -5
- package/src/superlocalmemory/infra/backup.py +7 -5
- package/src/superlocalmemory/infra/cloud_backup.py +18 -8
- package/src/superlocalmemory/infra/daemon_identity.py +248 -0
- package/src/superlocalmemory/infra/data_root.py +199 -0
- package/src/superlocalmemory/infra/event_bus.py +3 -1
- package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
- package/src/superlocalmemory/infra/process_reaper.py +23 -0
- package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
- package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
- package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
- package/src/superlocalmemory/ingestion/credentials.py +14 -7
- package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
- package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
- package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
- package/src/superlocalmemory/learning/ensemble.py +11 -0
- package/src/superlocalmemory/learning/entity_compiler.py +1 -1
- package/src/superlocalmemory/learning/feedback.py +1 -1
- package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
- package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
- package/src/superlocalmemory/learning/ranker.py +4 -1
- package/src/superlocalmemory/learning/source_quality.py +1 -1
- package/src/superlocalmemory/learning/trigram_index.py +3 -2
- package/src/superlocalmemory/llm/backbone.py +1 -1
- package/src/superlocalmemory/math/ebbinghaus.py +1 -1
- package/src/superlocalmemory/math/fisher.py +1 -1
- package/src/superlocalmemory/math/fisher_quantized.py +1 -1
- package/src/superlocalmemory/math/hopfield.py +1 -1
- package/src/superlocalmemory/math/langevin.py +1 -1
- package/src/superlocalmemory/math/polar_quant.py +3 -4
- package/src/superlocalmemory/math/qjl.py +1 -1
- package/src/superlocalmemory/math/sheaf.py +1 -1
- package/src/superlocalmemory/math/turbo_quant.py +3 -2
- package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
- package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
- package/src/superlocalmemory/mcp/http_transport.py +53 -0
- package/src/superlocalmemory/mcp/server.py +39 -13
- package/src/superlocalmemory/mcp/shared.py +69 -3
- package/src/superlocalmemory/mcp/tools_active.py +141 -31
- package/src/superlocalmemory/mcp/tools_core.py +130 -31
- package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
- package/src/superlocalmemory/mcp/tools_learning.py +42 -2
- package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
- package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
- package/src/superlocalmemory/mcp/tools_v28.py +23 -2
- package/src/superlocalmemory/mcp/tools_v3.py +26 -1
- package/src/superlocalmemory/mcp/tools_v33.py +56 -17
- package/src/superlocalmemory/mesh/broker.py +2 -0
- package/src/superlocalmemory/mesh/remote_sync.py +50 -12
- package/src/superlocalmemory/optimize/cache/manager.py +77 -1
- package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
- package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
- package/src/superlocalmemory/optimize/compress/router.py +6 -1
- package/src/superlocalmemory/optimize/config/__init__.py +5 -0
- package/src/superlocalmemory/optimize/config/store.py +6 -4
- package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
- package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
- package/src/superlocalmemory/optimize/proxy/server.py +2 -2
- package/src/superlocalmemory/optimize/storage/db.py +12 -12
- package/src/superlocalmemory/retrieval/agentic.py +1 -1
- package/src/superlocalmemory/retrieval/ann_index.py +1 -1
- package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
- package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
- package/src/superlocalmemory/retrieval/engine.py +169 -79
- package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
- package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
- package/src/superlocalmemory/retrieval/fusion.py +1 -1
- package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
- package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
- package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
- package/src/superlocalmemory/retrieval/reranker.py +56 -20
- package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
- package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
- package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
- package/src/superlocalmemory/retrieval/strategy.py +1 -1
- package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
- package/src/superlocalmemory/retrieval/vector_store.py +1 -1
- package/src/superlocalmemory/server/api.py +10 -7
- package/src/superlocalmemory/server/bandit_loops.py +4 -2
- package/src/superlocalmemory/server/recall_serializer.py +24 -0
- package/src/superlocalmemory/server/route_mutations.py +84 -0
- package/src/superlocalmemory/server/routes/agents.py +8 -6
- package/src/superlocalmemory/server/routes/brain.py +14 -12
- package/src/superlocalmemory/server/routes/chat.py +29 -12
- package/src/superlocalmemory/server/routes/data_io.py +55 -24
- package/src/superlocalmemory/server/routes/helpers.py +8 -63
- package/src/superlocalmemory/server/routes/ingest.py +53 -36
- package/src/superlocalmemory/server/routes/memories.py +104 -43
- package/src/superlocalmemory/server/routes/mesh.py +31 -0
- package/src/superlocalmemory/server/routes/profiles.py +26 -4
- package/src/superlocalmemory/server/routes/tiers.py +43 -11
- package/src/superlocalmemory/server/routes/timeline.py +5 -1
- package/src/superlocalmemory/server/routes/v3_api.py +76 -21
- package/src/superlocalmemory/server/security_middleware.py +1 -1
- package/src/superlocalmemory/server/unified_daemon.py +680 -293
- package/src/superlocalmemory/server/write_identity.py +147 -0
- package/src/superlocalmemory/storage/access_log.py +4 -3
- package/src/superlocalmemory/storage/database.py +118 -25
- package/src/superlocalmemory/storage/migration_runner.py +84 -1
- package/src/superlocalmemory/storage/migration_v33.py +1 -1
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
- package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
- package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
- package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
- package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
- package/src/superlocalmemory/storage/models.py +16 -0
- package/src/superlocalmemory/storage/quantized_store.py +20 -3
- package/src/superlocalmemory/storage/v2_migrator.py +5 -3
- package/src/superlocalmemory/ui/favicon.svg +5 -0
- package/src/superlocalmemory/ui/index.html +1 -0
- package/src/superlocalmemory/ui/js/compliance.js +1 -1
- package/src/superlocalmemory/ui/js/core.js +49 -8
- package/src/superlocalmemory/ui/js/dashboard.js +23 -2
- package/src/superlocalmemory/ui/js/feedback.js +1 -1
- package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
- package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
- package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
- package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
- package/src/superlocalmemory/ui/js/settings.js +4 -2
- package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
- package/bin/slm +0 -59
- package/bin/slm.bat +0 -77
- package/bin/slm.cmd +0 -5
- package/ide/integrations/langchain/README.md +0 -106
- package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
- package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
- package/ide/integrations/langchain/pyproject.toml +0 -38
- package/ide/integrations/langchain/tests/__init__.py +0 -3
- package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
- package/ide/integrations/langchain/tests/test_security.py +0 -117
- package/ide/integrations/llamaindex/README.md +0 -81
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
- package/ide/integrations/llamaindex/pyproject.toml +0 -43
- package/ide/integrations/llamaindex/tests/__init__.py +0 -3
- package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
- package/ide/integrations/llamaindex/tests/test_security.py +0 -241
- package/scripts/__tests__/build-plugin.test.mjs +0 -613
- package/scripts/_savings_math.py +0 -270
- package/scripts/build-dmg.sh +0 -417
- package/scripts/build-plugin.js +0 -742
- package/scripts/build-slm-hook.ps1 +0 -40
- package/scripts/build-slm-hook.sh +0 -45
- package/scripts/build_entry.py +0 -452
- package/scripts/ci/stage5b_gate.sh +0 -50
- package/scripts/dogfood_savings.py +0 -490
- package/scripts/generate-thumbnails.py +0 -218
- package/scripts/install-skills.ps1 +0 -4
- package/scripts/install-skills.sh +0 -5
- package/scripts/install.ps1 +0 -701
- package/scripts/install.sh +0 -1015
- package/scripts/postinstall_binary.js +0 -287
- package/scripts/prepack.js +0 -33
- package/scripts/release_manifest.py +0 -273
- package/scripts/slm-hook.spec +0 -56
- package/scripts/start-dashboard.ps1 +0 -52
- package/scripts/start-dashboard.sh +0 -41
- package/scripts/sync-wiki.ps1 +0 -127
- package/scripts/sync-wiki.sh +0 -82
- package/scripts/test-dmg.sh +0 -161
- package/scripts/test-npm-package.ps1 +0 -252
- package/scripts/test-npm-package.sh +0 -207
- package/scripts/verify-install.ps1 +0 -294
- package/scripts/verify-install.sh +0 -266
- package/scripts/verify-v27.ps1 +0 -301
- package/scripts/verify-v27.sh +0 -233
- package/src/superlocalmemory.egg-info/PKG-INFO +0 -516
- package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
- package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
- package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
- package/src/superlocalmemory.egg-info/requires.txt +0 -71
- package/src/superlocalmemory.egg-info/top_level.txt +0 -1
|
@@ -19,11 +19,13 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import logging
|
|
21
21
|
import os
|
|
22
|
-
import
|
|
22
|
+
import plistlib
|
|
23
23
|
import subprocess
|
|
24
24
|
import sys
|
|
25
25
|
from pathlib import Path
|
|
26
26
|
|
|
27
|
+
from superlocalmemory.infra.data_root import canonical_data_root, state_path
|
|
28
|
+
|
|
27
29
|
logger = logging.getLogger(__name__)
|
|
28
30
|
|
|
29
31
|
_SERVICE_NAME = "com.qualixar.superlocalmemory"
|
|
@@ -36,13 +38,13 @@ def get_python_path() -> str:
|
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
def get_log_path() -> Path:
|
|
39
|
-
log_dir =
|
|
41
|
+
log_dir = state_path("logs")
|
|
40
42
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
41
43
|
return log_dir / "daemon.log"
|
|
42
44
|
|
|
43
45
|
|
|
44
46
|
def get_error_log_path() -> Path:
|
|
45
|
-
log_dir =
|
|
47
|
+
log_dir = state_path("logs")
|
|
46
48
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
47
49
|
return log_dir / "daemon-error.log"
|
|
48
50
|
|
|
@@ -57,44 +59,29 @@ def _macos_plist_content() -> str:
|
|
|
57
59
|
python = get_python_path()
|
|
58
60
|
log = get_log_path()
|
|
59
61
|
err_log = get_error_log_path()
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<integer>30</integer>
|
|
84
|
-
<key>StandardOutPath</key>
|
|
85
|
-
<string>{log}</string>
|
|
86
|
-
<key>StandardErrorPath</key>
|
|
87
|
-
<string>{err_log}</string>
|
|
88
|
-
<key>EnvironmentVariables</key>
|
|
89
|
-
<dict>
|
|
90
|
-
<key>PATH</key>
|
|
91
|
-
<string>/usr/local/bin:/usr/bin:/bin:{Path(python).parent}</string>
|
|
92
|
-
<key>HOME</key>
|
|
93
|
-
<string>{Path.home()}</string>
|
|
94
|
-
</dict>
|
|
95
|
-
</dict>
|
|
96
|
-
</plist>
|
|
97
|
-
"""
|
|
62
|
+
port = str(_configured_daemon_port())
|
|
63
|
+
payload = {
|
|
64
|
+
"Label": _SERVICE_NAME,
|
|
65
|
+
"ProgramArguments": [
|
|
66
|
+
python,
|
|
67
|
+
"-m",
|
|
68
|
+
"superlocalmemory.server.unified_daemon",
|
|
69
|
+
"--start",
|
|
70
|
+
f"--port={port}",
|
|
71
|
+
],
|
|
72
|
+
"RunAtLoad": True,
|
|
73
|
+
"KeepAlive": {"SuccessfulExit": False},
|
|
74
|
+
"ThrottleInterval": 30,
|
|
75
|
+
"StandardOutPath": str(log),
|
|
76
|
+
"StandardErrorPath": str(err_log),
|
|
77
|
+
"EnvironmentVariables": {
|
|
78
|
+
"PATH": f"/usr/local/bin:/usr/bin:/bin:{Path(python).parent}",
|
|
79
|
+
"HOME": str(Path.home()),
|
|
80
|
+
"SLM_DATA_DIR": str(canonical_data_root()),
|
|
81
|
+
"SLM_DAEMON_PORT": port,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
return plistlib.dumps(payload, fmt=plistlib.FMT_XML, sort_keys=False).decode()
|
|
98
85
|
|
|
99
86
|
|
|
100
87
|
def install_macos() -> bool:
|
|
@@ -163,6 +150,8 @@ def _linux_service_path() -> Path:
|
|
|
163
150
|
def _linux_service_content() -> str:
|
|
164
151
|
python = get_python_path()
|
|
165
152
|
log = get_log_path()
|
|
153
|
+
root = canonical_data_root()
|
|
154
|
+
port = _configured_daemon_port()
|
|
166
155
|
|
|
167
156
|
return f"""[Unit]
|
|
168
157
|
Description={_DISPLAY_NAME}
|
|
@@ -170,13 +159,15 @@ After=network.target
|
|
|
170
159
|
|
|
171
160
|
[Service]
|
|
172
161
|
Type=simple
|
|
173
|
-
ExecStart={python} -m superlocalmemory.server.unified_daemon --start
|
|
162
|
+
ExecStart={python} -m superlocalmemory.server.unified_daemon --start --port={port}
|
|
174
163
|
Restart=on-failure
|
|
175
164
|
RestartSec=30
|
|
176
165
|
StandardOutput=append:{log}
|
|
177
166
|
StandardError=append:{get_error_log_path()}
|
|
178
167
|
Environment=HOME={Path.home()}
|
|
179
168
|
Environment=PATH=/usr/local/bin:/usr/bin:/bin:{Path(python).parent}
|
|
169
|
+
Environment="SLM_DATA_DIR={root}"
|
|
170
|
+
Environment="SLM_DAEMON_PORT={port}"
|
|
180
171
|
|
|
181
172
|
[Install]
|
|
182
173
|
WantedBy=default.target
|
|
@@ -247,18 +238,32 @@ def status_linux() -> dict:
|
|
|
247
238
|
_WINDOWS_TASK_NAME = "SuperLocalMemory"
|
|
248
239
|
|
|
249
240
|
|
|
250
|
-
def
|
|
251
|
-
|
|
252
|
-
|
|
241
|
+
def _configured_daemon_port() -> int:
|
|
242
|
+
try:
|
|
243
|
+
port = int(os.environ.get("SLM_DAEMON_PORT", "") or 8765)
|
|
244
|
+
except ValueError:
|
|
245
|
+
port = 8765
|
|
246
|
+
return port if 1 <= port <= 65535 else 8765
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _windows_vbs_content() -> str:
|
|
250
|
+
python = str(get_python_path()).replace('"', '""')
|
|
251
|
+
root = str(canonical_data_root()).replace('"', '""')
|
|
252
|
+
port = str(_configured_daemon_port())
|
|
253
|
+
return (
|
|
254
|
+
'Set WshShell = CreateObject("WScript.Shell")\n'
|
|
255
|
+
f'WshShell.Environment("Process")("SLM_DATA_DIR") = "{root}"\n'
|
|
256
|
+
f'WshShell.Environment("Process")("SLM_DAEMON_PORT") = "{port}"\n'
|
|
257
|
+
f'WshShell.Run """{python}"" -m superlocalmemory.server.unified_daemon '
|
|
258
|
+
f'--start --port={port}", 0, False\n'
|
|
259
|
+
)
|
|
253
260
|
|
|
261
|
+
|
|
262
|
+
def install_windows() -> bool:
|
|
254
263
|
# Create a VBS wrapper to run Python without console window
|
|
255
|
-
vbs_path =
|
|
264
|
+
vbs_path = state_path("start-daemon.vbs")
|
|
256
265
|
vbs_path.parent.mkdir(parents=True, exist_ok=True)
|
|
257
|
-
|
|
258
|
-
f'Set WshShell = CreateObject("WScript.Shell")\n'
|
|
259
|
-
f'WshShell.Run """{python}"" -m superlocalmemory.server.unified_daemon --start", 0, False\n'
|
|
260
|
-
)
|
|
261
|
-
vbs_path.write_text(vbs_content)
|
|
266
|
+
vbs_path.write_text(_windows_vbs_content())
|
|
262
267
|
|
|
263
268
|
# Use schtasks to create a logon trigger task
|
|
264
269
|
try:
|
|
@@ -303,7 +308,7 @@ def uninstall_windows() -> bool:
|
|
|
303
308
|
except Exception:
|
|
304
309
|
pass
|
|
305
310
|
|
|
306
|
-
vbs_path =
|
|
311
|
+
vbs_path = state_path("start-daemon.vbs")
|
|
307
312
|
if vbs_path.exists():
|
|
308
313
|
vbs_path.unlink()
|
|
309
314
|
|
|
@@ -31,15 +31,9 @@ from pathlib import Path
|
|
|
31
31
|
# WP-07: resolve via slm_home() so all 3 env aliases are honoured.
|
|
32
32
|
# Fallback keeps stdlib-only path if the import fails during early bootstrap.
|
|
33
33
|
def _resolve_slm_home() -> Path:
|
|
34
|
-
|
|
35
|
-
from superlocalmemory.cli._lazy_init import slm_home
|
|
36
|
-
return slm_home()
|
|
37
|
-
except Exception:
|
|
38
|
-
return Path(os.environ.get("SL_MEMORY_PATH", "") or Path.home() / ".superlocalmemory")
|
|
39
|
-
|
|
34
|
+
from superlocalmemory.infra.data_root import canonical_data_root
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
_SETUP_MARKER = _SLM_HOME / ".setup-complete"
|
|
36
|
+
return canonical_data_root()
|
|
43
37
|
_EMBED_MODEL = "nomic-ai/nomic-embed-text-v1.5"
|
|
44
38
|
_RERANKER_MODEL = "cross-encoder/ms-marco-MiniLM-L-12-v2"
|
|
45
39
|
# v3.6.10: compulsory LLMLingua-2 prose compression model (~560MB, aggressive mode).
|
|
@@ -61,7 +55,7 @@ def is_interactive() -> bool:
|
|
|
61
55
|
|
|
62
56
|
def is_setup_complete() -> bool:
|
|
63
57
|
"""True if the setup wizard has been run at least once."""
|
|
64
|
-
return
|
|
58
|
+
return (_resolve_slm_home() / ".setup-complete").exists()
|
|
65
59
|
|
|
66
60
|
|
|
67
61
|
def needs_setup() -> bool:
|
|
@@ -290,8 +284,9 @@ def _verify_installation() -> bool:
|
|
|
290
284
|
|
|
291
285
|
def _mark_complete() -> None:
|
|
292
286
|
"""Write .setup-complete marker file."""
|
|
293
|
-
|
|
294
|
-
|
|
287
|
+
slm_root = _resolve_slm_home()
|
|
288
|
+
slm_root.mkdir(parents=True, exist_ok=True)
|
|
289
|
+
(slm_root / ".setup-complete").write_text(
|
|
295
290
|
f"setup_completed={time.strftime('%Y-%m-%dT%H:%M:%S')}\n"
|
|
296
291
|
f"python={sys.executable}\n"
|
|
297
292
|
f"platform={platform.system()}\n"
|
|
@@ -311,6 +306,7 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
311
306
|
or CI environments).
|
|
312
307
|
"""
|
|
313
308
|
interactive = is_interactive() and not auto
|
|
309
|
+
slm_root = _resolve_slm_home()
|
|
314
310
|
|
|
315
311
|
print()
|
|
316
312
|
print("╔══════════════════════════════════════════════════════════╗")
|
|
@@ -329,7 +325,7 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
329
325
|
print(f" Platform: {platform.system()} {platform.machine()}")
|
|
330
326
|
if ram_gb > 0:
|
|
331
327
|
print(f" RAM: {ram_gb:.1f} GB {'✓' if ram_gb >= 4 else '⚠ (4GB+ recommended)'}")
|
|
332
|
-
print(f" Data dir: {
|
|
328
|
+
print(f" Data dir: {slm_root}")
|
|
333
329
|
|
|
334
330
|
# Check sentence-transformers
|
|
335
331
|
st_ok = False
|
|
@@ -351,8 +347,8 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
351
347
|
print("─── Step 2/10: Choose Operating Mode ───")
|
|
352
348
|
print()
|
|
353
349
|
print(" [A] Local Guardian (recommended)")
|
|
354
|
-
print("
|
|
355
|
-
print("
|
|
350
|
+
print(" No model-provider call in the core memory path.")
|
|
351
|
+
print(" Review optional integrations and network policy for your deployment.")
|
|
356
352
|
print()
|
|
357
353
|
print(" [B] Smart Local")
|
|
358
354
|
print(" Local LLM via Ollama for enrichment.")
|
|
@@ -443,8 +439,8 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
443
439
|
code_graph_enabled = cg_choice in ("", "y", "yes")
|
|
444
440
|
|
|
445
441
|
# Write code graph config
|
|
446
|
-
|
|
447
|
-
cg_config_path =
|
|
442
|
+
slm_root.mkdir(parents=True, exist_ok=True)
|
|
443
|
+
cg_config_path = slm_root / "code_graph_config.json"
|
|
448
444
|
import json
|
|
449
445
|
cg_config_data = {"enabled": code_graph_enabled, "bridge_enabled": code_graph_enabled}
|
|
450
446
|
cg_config_path.write_text(json.dumps(cg_config_data, indent=2))
|
|
@@ -556,7 +552,7 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
556
552
|
if name in adapters_config:
|
|
557
553
|
adapters_config[name] = True
|
|
558
554
|
|
|
559
|
-
adapters_path =
|
|
555
|
+
adapters_path = slm_root / "adapters.json"
|
|
560
556
|
import json as _json
|
|
561
557
|
adapters_path.write_text(_json.dumps(
|
|
562
558
|
{k: {"enabled": v, "tier": "polling"} for k, v in adapters_config.items()},
|
|
@@ -613,8 +609,8 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
613
609
|
|
|
614
610
|
# Write evolution config to config.json directly
|
|
615
611
|
# (SLMConfig.save() doesn't serialize evolution)
|
|
616
|
-
|
|
617
|
-
evo_config_path =
|
|
612
|
+
slm_root.mkdir(parents=True, exist_ok=True)
|
|
613
|
+
evo_config_path = slm_root / "config.json"
|
|
618
614
|
evo_cfg: dict = {}
|
|
619
615
|
if evo_config_path.exists():
|
|
620
616
|
try:
|
|
@@ -649,7 +645,7 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
649
645
|
prompt_v3426_options,
|
|
650
646
|
validate_install_data_dir,
|
|
651
647
|
)
|
|
652
|
-
ok, reason = validate_install_data_dir(
|
|
648
|
+
ok, reason = validate_install_data_dir(slm_root)
|
|
653
649
|
if not ok:
|
|
654
650
|
print()
|
|
655
651
|
print(" ⚠ Data directory check failed:")
|
|
@@ -657,11 +653,16 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
657
653
|
print(f" {line}")
|
|
658
654
|
print()
|
|
659
655
|
v3426_opts = prompt_v3426_options(interactive=interactive)
|
|
660
|
-
persist_v3426_options(v3426_opts,
|
|
656
|
+
persist_v3426_options(v3426_opts, slm_root)
|
|
661
657
|
except Exception as exc:
|
|
662
658
|
# Wizard must never crash over an advisory feature.
|
|
663
659
|
print(f" (v3.4.26 options step skipped: {exc})")
|
|
664
660
|
|
|
661
|
+
# External IDE configuration and login-time services cross ownership
|
|
662
|
+
# boundaries. They require explicit consent even inside the setup wizard.
|
|
663
|
+
_configure_external_integrations(interactive=interactive)
|
|
664
|
+
_configure_autostart(interactive=interactive)
|
|
665
|
+
|
|
665
666
|
# -- Done --
|
|
666
667
|
_mark_complete()
|
|
667
668
|
|
|
@@ -697,18 +698,6 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
697
698
|
print(' slm recall "search query"')
|
|
698
699
|
print(" slm dashboard → http://localhost:8765")
|
|
699
700
|
print(" slm adapters enable gmail → start Gmail ingestion")
|
|
700
|
-
print()
|
|
701
|
-
# V3.4.4: Auto-install OS service for daemon persistence (survive reboots)
|
|
702
|
-
try:
|
|
703
|
-
from superlocalmemory.cli.service_installer import install_service
|
|
704
|
-
print(" Installing OS service for auto-start...")
|
|
705
|
-
if install_service():
|
|
706
|
-
print(" ✓ SLM will auto-start on login — zero friction.")
|
|
707
|
-
else:
|
|
708
|
-
print(" ⚠ OS service not installed (run: slm serve install)")
|
|
709
|
-
except Exception:
|
|
710
|
-
print(" ⚠ Could not install OS service (run: slm serve install)")
|
|
711
|
-
|
|
712
701
|
print()
|
|
713
702
|
print(" Need help?")
|
|
714
703
|
print(" slm doctor — diagnose issues")
|
|
@@ -728,12 +717,14 @@ def check_first_use(command: str) -> None:
|
|
|
728
717
|
Called from main.py before dispatching any command.
|
|
729
718
|
Skips for commands that don't need setup (setup, hook, --version, --help).
|
|
730
719
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
720
|
+
First use may initialize SLM-owned defaults, but it never edits an IDE,
|
|
721
|
+
installs a plugin, or creates an operating-system service. Those external
|
|
722
|
+
mutations require explicit consent inside ``slm setup``.
|
|
734
723
|
"""
|
|
735
724
|
# Commands that work without setup
|
|
736
|
-
_SKIP_COMMANDS = {
|
|
725
|
+
_SKIP_COMMANDS = {
|
|
726
|
+
"setup", "init", "hook", "hooks", "reap", "mcp", "diagnostics",
|
|
727
|
+
}
|
|
737
728
|
if command in _SKIP_COMMANDS:
|
|
738
729
|
return
|
|
739
730
|
|
|
@@ -746,16 +737,15 @@ def check_first_use(command: str) -> None:
|
|
|
746
737
|
# any lazy-init content (e.g. a pre-existing mode-A skeleton).
|
|
747
738
|
if not is_interactive():
|
|
748
739
|
try:
|
|
749
|
-
from superlocalmemory.core.config import SLMConfig
|
|
740
|
+
from superlocalmemory.core.config import SLMConfig
|
|
750
741
|
from superlocalmemory.storage.models import Mode
|
|
751
|
-
config_path =
|
|
742
|
+
config_path = _resolve_slm_home() / "config.json"
|
|
752
743
|
if not config_path.exists():
|
|
753
744
|
cfg = SLMConfig.for_mode(Mode.A)
|
|
754
745
|
cfg.save(mode_change=True)
|
|
755
746
|
_mark_complete()
|
|
756
747
|
except Exception:
|
|
757
748
|
pass
|
|
758
|
-
_maybe_install_hooks_on_first_use()
|
|
759
749
|
return
|
|
760
750
|
|
|
761
751
|
# Interactive: run the full wizard
|
|
@@ -763,39 +753,49 @@ def check_first_use(command: str) -> None:
|
|
|
763
753
|
print(" First time using SuperLocalMemory!")
|
|
764
754
|
print(" Running setup wizard...\n")
|
|
765
755
|
run_wizard()
|
|
766
|
-
_maybe_install_hooks_on_first_use()
|
|
767
756
|
|
|
768
757
|
|
|
769
|
-
def
|
|
770
|
-
"""
|
|
758
|
+
def _configure_external_integrations(*, interactive: bool) -> bool:
|
|
759
|
+
"""Request consent before editing Claude Code configuration."""
|
|
760
|
+
print()
|
|
761
|
+
print(" Optional Claude Code integration can install the SLM plugin and hooks.")
|
|
762
|
+
if not interactive:
|
|
763
|
+
print(" Skipped in non-interactive setup. Run: slm connect claude-code")
|
|
764
|
+
return False
|
|
765
|
+
choice = _prompt(
|
|
766
|
+
" Install Claude Code plugin and hooks now? [y/N] (default: N): ",
|
|
767
|
+
"n",
|
|
768
|
+
).lower()
|
|
769
|
+
if choice not in ("y", "yes"):
|
|
770
|
+
print(" Skipped. Run `slm connect claude-code` when ready.")
|
|
771
|
+
return False
|
|
772
|
+
return _install_external_integrations()
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
def _install_external_integrations() -> bool:
|
|
776
|
+
"""Install Claude Code hooks/plugin after explicit setup consent.
|
|
771
777
|
|
|
772
|
-
|
|
778
|
+
Installation rules:
|
|
773
779
|
* Skip if the user explicitly opted out via ``slm hooks remove``
|
|
774
|
-
|
|
775
|
-
*
|
|
776
|
-
to merge into).
|
|
777
|
-
* Silent + best-effort: never fail a CLI command because of this.
|
|
780
|
+
* Skip hook configuration if Claude Code has no settings file.
|
|
781
|
+
* Best-effort: setup remains usable when Claude Code is unavailable.
|
|
778
782
|
"""
|
|
783
|
+
changed = False
|
|
779
784
|
try:
|
|
780
|
-
opt_out =
|
|
781
|
-
if opt_out.exists():
|
|
782
|
-
return
|
|
785
|
+
opt_out = _resolve_slm_home() / "hooks" / ".hooks-disabled"
|
|
783
786
|
claude_settings = Path.home() / ".claude" / "settings.json"
|
|
784
|
-
if not claude_settings.exists():
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
install_hooks()
|
|
787
|
+
if not opt_out.exists() and claude_settings.exists():
|
|
788
|
+
from superlocalmemory.hooks.claude_code_hooks import install_hooks
|
|
789
|
+
changed = bool(install_hooks()) or changed
|
|
788
790
|
except Exception:
|
|
789
|
-
# Best-effort:
|
|
791
|
+
# Best-effort: never block setup over an optional integration.
|
|
790
792
|
pass
|
|
791
793
|
|
|
792
|
-
|
|
793
|
-
# Runs after hooks install, best-effort — never blocks CLI startup.
|
|
794
|
-
_try_install_claude_plugin()
|
|
794
|
+
return _try_install_claude_plugin() or changed
|
|
795
795
|
|
|
796
796
|
|
|
797
|
-
def _try_install_claude_plugin() ->
|
|
798
|
-
"""
|
|
797
|
+
def _try_install_claude_plugin() -> bool:
|
|
798
|
+
"""Install the Claude Code plugin after explicit setup consent.
|
|
799
799
|
|
|
800
800
|
Runs ``claude plugin marketplace add qualixar/superlocalmemory`` then
|
|
801
801
|
``claude plugin install superlocalmemory@qualixar`` if the ``claude``
|
|
@@ -807,49 +807,94 @@ def _try_install_claude_plugin() -> None:
|
|
|
807
807
|
|
|
808
808
|
claude = shutil.which("claude")
|
|
809
809
|
if not claude:
|
|
810
|
-
|
|
810
|
+
print(" Claude Code CLI not found; plugin installation skipped.")
|
|
811
|
+
return False
|
|
811
812
|
|
|
812
813
|
_run = lambda cmd: subprocess.run( # noqa: E731
|
|
813
814
|
cmd, capture_output=True, timeout=30, check=False
|
|
814
815
|
)
|
|
815
816
|
|
|
816
817
|
try:
|
|
817
|
-
|
|
818
|
+
marketplace = _run(
|
|
819
|
+
[claude, "plugin", "marketplace", "add", "qualixar/superlocalmemory"]
|
|
820
|
+
)
|
|
821
|
+
installed = _run(
|
|
822
|
+
[claude, "plugin", "install", "superlocalmemory@qualixar"]
|
|
823
|
+
)
|
|
824
|
+
return marketplace.returncode == 0 and installed.returncode == 0
|
|
818
825
|
except Exception:
|
|
819
|
-
|
|
826
|
+
return False
|
|
820
827
|
|
|
828
|
+
|
|
829
|
+
def _configure_autostart(*, interactive: bool) -> bool:
|
|
830
|
+
"""Request consent before creating a login-time service definition."""
|
|
831
|
+
print()
|
|
832
|
+
print(" Optional auto-start keeps the SLM daemon available after login.")
|
|
833
|
+
if not interactive:
|
|
834
|
+
print(" Skipped in non-interactive setup. Run: slm serve install")
|
|
835
|
+
return False
|
|
836
|
+
choice = _prompt(
|
|
837
|
+
" Install the user-level auto-start service now? [y/N] (default: N): ",
|
|
838
|
+
"n",
|
|
839
|
+
).lower()
|
|
840
|
+
if choice not in ("y", "yes"):
|
|
841
|
+
print(" Skipped. Run `slm serve install` when ready.")
|
|
842
|
+
return False
|
|
843
|
+
return _install_autostart_service()
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
def _install_autostart_service() -> bool:
|
|
847
|
+
"""Install the user service after explicit setup consent."""
|
|
821
848
|
try:
|
|
822
|
-
|
|
849
|
+
from superlocalmemory.cli.service_installer import install_service
|
|
850
|
+
|
|
851
|
+
installed = bool(install_service())
|
|
852
|
+
if installed:
|
|
853
|
+
print(" ✓ User-level SLM auto-start service installed.")
|
|
854
|
+
else:
|
|
855
|
+
print(" ⚠ Service was not installed (run: slm serve install)")
|
|
856
|
+
return installed
|
|
823
857
|
except Exception:
|
|
824
|
-
|
|
858
|
+
print(" ⚠ Service was not installed (run: slm serve install)")
|
|
859
|
+
return False
|
|
825
860
|
|
|
826
861
|
|
|
827
862
|
# ---------------------------------------------------------------------------
|
|
828
863
|
# Mode C provider config (preserved from original)
|
|
829
864
|
# ---------------------------------------------------------------------------
|
|
830
865
|
|
|
831
|
-
def configure_provider(config: object) -> None:
|
|
832
|
-
"""Configure LLM provider for Mode C.
|
|
866
|
+
def configure_provider(config: object, provider_name: str | None = None) -> None:
|
|
867
|
+
"""Configure an LLM provider for Mode C.
|
|
868
|
+
|
|
869
|
+
When ``provider_name`` is supplied by ``slm provider set <provider>``,
|
|
870
|
+
configuration is non-interactive and resolves its credential from the
|
|
871
|
+
provider's documented environment variable. Omitting it preserves the
|
|
872
|
+
existing interactive picker.
|
|
873
|
+
"""
|
|
833
874
|
from superlocalmemory.core.config import SLMConfig
|
|
834
875
|
from superlocalmemory.storage.models import Mode
|
|
835
876
|
|
|
836
877
|
presets = SLMConfig.provider_presets()
|
|
837
878
|
|
|
838
|
-
print()
|
|
839
|
-
print(" Choose your LLM provider:")
|
|
840
|
-
print()
|
|
841
879
|
providers = list(presets.keys())
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
print(
|
|
845
|
-
|
|
880
|
+
interactive_selection = provider_name is None
|
|
881
|
+
if interactive_selection:
|
|
882
|
+
print()
|
|
883
|
+
print(" Choose your LLM provider:")
|
|
884
|
+
print()
|
|
885
|
+
for i, name in enumerate(providers, 1):
|
|
886
|
+
preset = presets[name]
|
|
887
|
+
print(f" [{i}] {name.capitalize()} — {preset['model']}")
|
|
888
|
+
print()
|
|
846
889
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
890
|
+
idx = _prompt(f" Select provider [1-{len(providers)}]: ", "1")
|
|
891
|
+
try:
|
|
892
|
+
provider_name = providers[int(idx) - 1]
|
|
893
|
+
except (ValueError, IndexError):
|
|
894
|
+
print(" Invalid choice. Using OpenAI.")
|
|
895
|
+
provider_name = "openai"
|
|
896
|
+
elif provider_name not in presets:
|
|
897
|
+
raise ValueError(f"Unsupported provider: {provider_name}")
|
|
853
898
|
|
|
854
899
|
preset = presets[provider_name]
|
|
855
900
|
|
|
@@ -861,18 +906,27 @@ def configure_provider(config: object) -> None:
|
|
|
861
906
|
if existing:
|
|
862
907
|
print(f" Found {env_key} in environment.")
|
|
863
908
|
api_key = existing
|
|
864
|
-
elif is_interactive():
|
|
909
|
+
elif interactive_selection and is_interactive():
|
|
865
910
|
api_key = _prompt(
|
|
866
911
|
f" Enter your {provider_name.capitalize()} API key: ",
|
|
867
912
|
)
|
|
868
913
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
914
|
+
# Provider selection is an additive configuration operation. Rebuilding
|
|
915
|
+
# via ``for_mode`` used to reset retrieval, scale-engine, evolution, and
|
|
916
|
+
# user-tuned embedding settings — surprising and unsafe after a user had
|
|
917
|
+
# configured a local or promoted Cozo/Lance deployment. Keep every
|
|
918
|
+
# unrelated setting intact and change only the mode/provider contract.
|
|
919
|
+
from superlocalmemory.core.config import LLMConfig
|
|
920
|
+
|
|
921
|
+
updated = config if isinstance(config, SLMConfig) else SLMConfig.load()
|
|
922
|
+
updated.mode = Mode.C
|
|
923
|
+
updated.llm = LLMConfig(
|
|
924
|
+
provider=provider_name,
|
|
925
|
+
model=preset["model"],
|
|
926
|
+
api_key=api_key,
|
|
927
|
+
api_base=preset["base_url"],
|
|
875
928
|
)
|
|
876
929
|
updated.save(mode_change=True)
|
|
930
|
+
SLMConfig.write_current_mode(Mode.C, updated.base_dir)
|
|
877
931
|
print(f" Provider: {provider_name}")
|
|
878
932
|
print(f" Model: {preset['model']}")
|
|
@@ -28,7 +28,8 @@ _MAX_MARKER_BYTES = 64 # a semver string is ≤ 32 chars; 64 is plenty
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def _data_dir() -> Path:
|
|
31
|
-
|
|
31
|
+
from superlocalmemory.infra.data_root import canonical_data_root
|
|
32
|
+
return canonical_data_root()
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
def _marker_path() -> Path:
|
|
@@ -12,6 +12,8 @@ from __future__ import annotations
|
|
|
12
12
|
from dataclasses import dataclass, field
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
|
|
15
|
+
from superlocalmemory.infra.data_root import state_path
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
# Languages supported out of the box (tree-sitter grammar names)
|
|
17
19
|
DEFAULT_LANGUAGES: frozenset[str] = frozenset({
|
|
@@ -85,4 +87,4 @@ class CodeGraphConfig:
|
|
|
85
87
|
return self.db_path
|
|
86
88
|
if slm_base_dir is not None:
|
|
87
89
|
return slm_base_dir / "code_graph.db"
|
|
88
|
-
return
|
|
90
|
+
return state_path("code_graph.db")
|