superlocalmemory 3.6.22 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +275 -72
  3. package/bin/slm-npm +43 -89
  4. package/docs/pi-dev-integration.md +43 -0
  5. package/ide/configs/antigravity-mcp.json +2 -2
  6. package/ide/configs/chatgpt-desktop-mcp.json +1 -1
  7. package/ide/configs/claude-desktop-mcp.json +2 -2
  8. package/ide/configs/windsurf-mcp.json +2 -2
  9. package/ide/hooks/context-hook.js +6 -2
  10. package/ide/hooks/post-recall-hook.js +7 -3
  11. package/ide/hooks/tool-event-hook.sh +2 -1
  12. package/package.json +19 -10
  13. package/plugin/.claude-plugin/plugin.json +1 -1
  14. package/plugin/_GENERATED.md +1 -1
  15. package/plugin/agents/slm-memory-advisor.md +1 -1
  16. package/plugin/requirements.txt +1 -1
  17. package/plugin/skills/slm-session/SKILL.md +1 -1
  18. package/plugin-src/rules/AGENTS.md +1 -1
  19. package/pyproject.toml +40 -8
  20. package/scripts/postinstall-interactive.js +17 -94
  21. package/scripts/postinstall.js +185 -258
  22. package/scripts/preuninstall.js +9 -50
  23. package/src/superlocalmemory/__init__.py +2 -2
  24. package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
  25. package/src/superlocalmemory/attribution/signer.py +34 -19
  26. package/src/superlocalmemory/attribution/watermark.py +1 -1
  27. package/src/superlocalmemory/cli/_lazy_init.py +3 -5
  28. package/src/superlocalmemory/cli/commands.py +490 -195
  29. package/src/superlocalmemory/cli/context_commands.py +5 -4
  30. package/src/superlocalmemory/cli/daemon.py +282 -187
  31. package/src/superlocalmemory/cli/db_migrate.py +3 -1
  32. package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
  33. package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
  34. package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
  35. package/src/superlocalmemory/cli/main.py +128 -31
  36. package/src/superlocalmemory/cli/pending_store.py +54 -38
  37. package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
  38. package/src/superlocalmemory/cli/service_installer.py +57 -52
  39. package/src/superlocalmemory/cli/setup_wizard.py +142 -88
  40. package/src/superlocalmemory/cli/version_banner.py +2 -1
  41. package/src/superlocalmemory/code_graph/config.py +3 -1
  42. package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
  43. package/src/superlocalmemory/core/config.py +65 -20
  44. package/src/superlocalmemory/core/consolidation_engine.py +9 -7
  45. package/src/superlocalmemory/core/context_cache.py +56 -8
  46. package/src/superlocalmemory/core/derivation_lineage.py +246 -0
  47. package/src/superlocalmemory/core/embedding_worker.py +32 -20
  48. package/src/superlocalmemory/core/embeddings.py +54 -18
  49. package/src/superlocalmemory/core/engine.py +150 -104
  50. package/src/superlocalmemory/core/engine_ingestion.py +513 -0
  51. package/src/superlocalmemory/core/engine_wiring.py +2 -0
  52. package/src/superlocalmemory/core/evidence_bundle.py +526 -0
  53. package/src/superlocalmemory/core/fact_consolidator.py +5 -11
  54. package/src/superlocalmemory/core/graph_analyzer.py +2 -2
  55. package/src/superlocalmemory/core/health_monitor.py +4 -2
  56. package/src/superlocalmemory/core/ingestion_command.py +636 -0
  57. package/src/superlocalmemory/core/injection.py +69 -18
  58. package/src/superlocalmemory/core/lifecycle_state.py +153 -0
  59. package/src/superlocalmemory/core/maintenance.py +23 -22
  60. package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
  61. package/src/superlocalmemory/core/mutations.py +143 -0
  62. package/src/superlocalmemory/core/platform_utils.py +7 -4
  63. package/src/superlocalmemory/core/ram_lock.py +16 -5
  64. package/src/superlocalmemory/core/rate_limit.py +1 -1
  65. package/src/superlocalmemory/core/recall_pipeline.py +60 -101
  66. package/src/superlocalmemory/core/recall_worker.py +76 -59
  67. package/src/superlocalmemory/core/registry.py +1 -1
  68. package/src/superlocalmemory/core/scale_engine.py +293 -0
  69. package/src/superlocalmemory/core/score_contract.py +62 -0
  70. package/src/superlocalmemory/core/security_primitives.py +3 -1
  71. package/src/superlocalmemory/core/slm_disabled.py +3 -5
  72. package/src/superlocalmemory/core/store_pipeline.py +172 -40
  73. package/src/superlocalmemory/core/tier_manager.py +32 -20
  74. package/src/superlocalmemory/core/worker_pool.py +13 -4
  75. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
  76. package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
  77. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
  78. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
  79. package/src/superlocalmemory/encoding/auto_linker.py +1 -1
  80. package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
  81. package/src/superlocalmemory/encoding/consolidator.py +22 -5
  82. package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
  83. package/src/superlocalmemory/encoding/foresight.py +2 -0
  84. package/src/superlocalmemory/encoding/graph_builder.py +1 -1
  85. package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
  86. package/src/superlocalmemory/evaluation/__init__.py +13 -0
  87. package/src/superlocalmemory/evaluation/calibration.py +308 -0
  88. package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
  89. package/src/superlocalmemory/graph/cozo_backend.py +256 -23
  90. package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
  91. package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
  92. package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
  93. package/src/superlocalmemory/hooks/auto_recall.py +31 -6
  94. package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
  95. package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
  96. package/src/superlocalmemory/hooks/claude_code_hooks.py +126 -39
  97. package/src/superlocalmemory/hooks/codex_assets.py +59 -0
  98. package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
  99. package/src/superlocalmemory/hooks/context_payload.py +1 -1
  100. package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
  101. package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
  102. package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
  103. package/src/superlocalmemory/hooks/hook_handlers.py +241 -55
  104. package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
  105. package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
  106. package/src/superlocalmemory/hooks/session_registry.py +15 -8
  107. package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
  108. package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
  109. package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
  110. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
  111. package/src/superlocalmemory/infra/auth_middleware.py +38 -5
  112. package/src/superlocalmemory/infra/backup.py +7 -5
  113. package/src/superlocalmemory/infra/cloud_backup.py +18 -8
  114. package/src/superlocalmemory/infra/daemon_identity.py +248 -0
  115. package/src/superlocalmemory/infra/data_root.py +199 -0
  116. package/src/superlocalmemory/infra/event_bus.py +3 -1
  117. package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
  118. package/src/superlocalmemory/infra/process_reaper.py +23 -0
  119. package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
  120. package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
  121. package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
  122. package/src/superlocalmemory/ingestion/credentials.py +14 -7
  123. package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
  124. package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
  125. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
  126. package/src/superlocalmemory/learning/ensemble.py +11 -0
  127. package/src/superlocalmemory/learning/entity_compiler.py +1 -1
  128. package/src/superlocalmemory/learning/feedback.py +1 -1
  129. package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
  130. package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
  131. package/src/superlocalmemory/learning/ranker.py +4 -1
  132. package/src/superlocalmemory/learning/source_quality.py +1 -1
  133. package/src/superlocalmemory/learning/trigram_index.py +3 -2
  134. package/src/superlocalmemory/llm/backbone.py +13 -8
  135. package/src/superlocalmemory/math/ebbinghaus.py +1 -1
  136. package/src/superlocalmemory/math/fisher.py +1 -1
  137. package/src/superlocalmemory/math/fisher_quantized.py +1 -1
  138. package/src/superlocalmemory/math/hopfield.py +1 -1
  139. package/src/superlocalmemory/math/langevin.py +1 -1
  140. package/src/superlocalmemory/math/polar_quant.py +3 -4
  141. package/src/superlocalmemory/math/qjl.py +1 -1
  142. package/src/superlocalmemory/math/sheaf.py +1 -1
  143. package/src/superlocalmemory/math/turbo_quant.py +3 -2
  144. package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
  145. package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
  146. package/src/superlocalmemory/mcp/http_transport.py +53 -0
  147. package/src/superlocalmemory/mcp/server.py +39 -13
  148. package/src/superlocalmemory/mcp/shared.py +69 -3
  149. package/src/superlocalmemory/mcp/tools_active.py +141 -31
  150. package/src/superlocalmemory/mcp/tools_core.py +128 -29
  151. package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
  152. package/src/superlocalmemory/mcp/tools_learning.py +42 -2
  153. package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
  154. package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
  155. package/src/superlocalmemory/mcp/tools_v28.py +23 -2
  156. package/src/superlocalmemory/mcp/tools_v3.py +26 -1
  157. package/src/superlocalmemory/mcp/tools_v33.py +56 -17
  158. package/src/superlocalmemory/mesh/broker.py +2 -0
  159. package/src/superlocalmemory/mesh/remote_sync.py +50 -12
  160. package/src/superlocalmemory/optimize/cache/manager.py +77 -1
  161. package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
  162. package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
  163. package/src/superlocalmemory/optimize/compress/router.py +6 -1
  164. package/src/superlocalmemory/optimize/config/__init__.py +5 -0
  165. package/src/superlocalmemory/optimize/config/store.py +6 -4
  166. package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
  167. package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
  168. package/src/superlocalmemory/optimize/proxy/server.py +2 -2
  169. package/src/superlocalmemory/optimize/storage/db.py +14 -13
  170. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  171. package/src/superlocalmemory/retrieval/ann_index.py +1 -1
  172. package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
  173. package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
  174. package/src/superlocalmemory/retrieval/engine.py +169 -79
  175. package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
  176. package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
  177. package/src/superlocalmemory/retrieval/fusion.py +1 -1
  178. package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
  179. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  180. package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
  181. package/src/superlocalmemory/retrieval/reranker.py +56 -20
  182. package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
  183. package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
  184. package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
  185. package/src/superlocalmemory/retrieval/strategy.py +1 -1
  186. package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
  187. package/src/superlocalmemory/retrieval/vector_store.py +1 -1
  188. package/src/superlocalmemory/server/api.py +10 -7
  189. package/src/superlocalmemory/server/bandit_loops.py +4 -2
  190. package/src/superlocalmemory/server/recall_serializer.py +24 -0
  191. package/src/superlocalmemory/server/route_mutations.py +84 -0
  192. package/src/superlocalmemory/server/routes/agents.py +8 -6
  193. package/src/superlocalmemory/server/routes/brain.py +14 -12
  194. package/src/superlocalmemory/server/routes/chat.py +29 -12
  195. package/src/superlocalmemory/server/routes/data_io.py +55 -24
  196. package/src/superlocalmemory/server/routes/helpers.py +29 -4
  197. package/src/superlocalmemory/server/routes/ingest.py +53 -36
  198. package/src/superlocalmemory/server/routes/memories.py +104 -43
  199. package/src/superlocalmemory/server/routes/mesh.py +31 -0
  200. package/src/superlocalmemory/server/routes/profiles.py +26 -4
  201. package/src/superlocalmemory/server/routes/tiers.py +43 -11
  202. package/src/superlocalmemory/server/routes/timeline.py +5 -1
  203. package/src/superlocalmemory/server/routes/v3_api.py +76 -21
  204. package/src/superlocalmemory/server/security_middleware.py +1 -1
  205. package/src/superlocalmemory/server/ui.py +6 -3
  206. package/src/superlocalmemory/server/unified_daemon.py +680 -293
  207. package/src/superlocalmemory/server/write_identity.py +147 -0
  208. package/src/superlocalmemory/storage/access_log.py +4 -3
  209. package/src/superlocalmemory/storage/database.py +118 -25
  210. package/src/superlocalmemory/storage/migration_runner.py +84 -1
  211. package/src/superlocalmemory/storage/migration_v33.py +1 -1
  212. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
  213. package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
  214. package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
  215. package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
  216. package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
  217. package/src/superlocalmemory/storage/models.py +16 -0
  218. package/src/superlocalmemory/storage/quantized_store.py +20 -3
  219. package/src/superlocalmemory/storage/v2_migrator.py +5 -3
  220. package/src/superlocalmemory/ui/favicon.svg +5 -0
  221. package/src/superlocalmemory/ui/index.html +1 -0
  222. package/src/superlocalmemory/ui/js/compliance.js +1 -1
  223. package/src/superlocalmemory/ui/js/core.js +49 -8
  224. package/src/superlocalmemory/ui/js/dashboard.js +23 -2
  225. package/src/superlocalmemory/ui/js/feedback.js +1 -1
  226. package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
  227. package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
  228. package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
  229. package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
  230. package/src/superlocalmemory/ui/js/settings.js +4 -2
  231. package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
  232. package/bin/slm +0 -59
  233. package/bin/slm.bat +0 -77
  234. package/bin/slm.cmd +0 -5
  235. package/ide/integrations/langchain/README.md +0 -106
  236. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
  237. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
  238. package/ide/integrations/langchain/pyproject.toml +0 -38
  239. package/ide/integrations/langchain/tests/__init__.py +0 -3
  240. package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
  241. package/ide/integrations/langchain/tests/test_security.py +0 -117
  242. package/ide/integrations/llamaindex/README.md +0 -81
  243. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
  244. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
  245. package/ide/integrations/llamaindex/pyproject.toml +0 -43
  246. package/ide/integrations/llamaindex/tests/__init__.py +0 -3
  247. package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
  248. package/ide/integrations/llamaindex/tests/test_security.py +0 -241
  249. package/plugin-src/.mcp.json +0 -12
  250. package/plugin-src/agents/slm-memory-advisor.md +0 -44
  251. package/plugin-src/agents/slm-optimize-advisor.md +0 -38
  252. package/plugin-src/hooks/.gitkeep +0 -0
  253. package/plugin-src/hooks/hooks.json +0 -23
  254. package/plugin-src/manifest.json +0 -25
  255. package/plugin-src/requirements.txt +0 -1
  256. package/plugin-src/rules/CLAUDE.md.fragment +0 -44
  257. package/plugin-src/scripts/ensure-venv.bat +0 -122
  258. package/plugin-src/scripts/ensure-venv.sh +0 -105
  259. package/plugin-src/scripts/slm-launch +0 -15
  260. package/plugin-src/scripts/slm-launch.bat +0 -17
  261. package/plugin-src/settings.json +0 -16
  262. package/plugin-src/skills/slm-cache/SKILL.md +0 -140
  263. package/plugin-src/skills/slm-compress/SKILL.md +0 -143
  264. package/plugin-src/skills/slm-graph/SKILL.md +0 -300
  265. package/plugin-src/skills/slm-recall/SKILL.md +0 -204
  266. package/plugin-src/skills/slm-remember/SKILL.md +0 -194
  267. package/plugin-src/skills/slm-session/SKILL.md +0 -207
  268. package/plugin-src/skills/slm-status/SKILL.md +0 -149
  269. package/scripts/__tests__/build-plugin.test.mjs +0 -613
  270. package/scripts/_savings_math.py +0 -270
  271. package/scripts/build-dmg.sh +0 -417
  272. package/scripts/build-plugin.js +0 -742
  273. package/scripts/build-slm-hook.ps1 +0 -40
  274. package/scripts/build-slm-hook.sh +0 -45
  275. package/scripts/build_entry.py +0 -452
  276. package/scripts/ci/stage5b_gate.sh +0 -50
  277. package/scripts/dogfood_savings.py +0 -490
  278. package/scripts/generate-thumbnails.py +0 -218
  279. package/scripts/install-skills.ps1 +0 -4
  280. package/scripts/install-skills.sh +0 -5
  281. package/scripts/install.ps1 +0 -701
  282. package/scripts/install.sh +0 -1015
  283. package/scripts/postinstall_binary.js +0 -287
  284. package/scripts/prepack.js +0 -33
  285. package/scripts/release_manifest.py +0 -273
  286. package/scripts/slm-hook.spec +0 -56
  287. package/scripts/start-dashboard.ps1 +0 -52
  288. package/scripts/start-dashboard.sh +0 -41
  289. package/scripts/sync-wiki.ps1 +0 -127
  290. package/scripts/sync-wiki.sh +0 -82
  291. package/scripts/test-dmg.sh +0 -161
  292. package/scripts/test-npm-package.ps1 +0 -252
  293. package/scripts/test-npm-package.sh +0 -207
  294. package/scripts/verify-install.ps1 +0 -294
  295. package/scripts/verify-install.sh +0 -266
  296. package/scripts/verify-v27.ps1 +0 -301
  297. package/scripts/verify-v27.sh +0 -233
  298. package/src/superlocalmemory.egg-info/PKG-INFO +0 -513
  299. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
  300. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  301. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  302. package/src/superlocalmemory.egg-info/requires.txt +0 -71
  303. 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 shutil
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 = Path.home() / ".superlocalmemory" / "logs"
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 = Path.home() / ".superlocalmemory" / "logs"
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
- return f"""<?xml version="1.0" encoding="UTF-8"?>
62
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
63
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
64
- <plist version="1.0">
65
- <dict>
66
- <key>Label</key>
67
- <string>{_SERVICE_NAME}</string>
68
- <key>ProgramArguments</key>
69
- <array>
70
- <string>{python}</string>
71
- <string>-m</string>
72
- <string>superlocalmemory.server.unified_daemon</string>
73
- <string>--start</string>
74
- </array>
75
- <key>RunAtLoad</key>
76
- <true/>
77
- <key>KeepAlive</key>
78
- <dict>
79
- <key>SuccessfulExit</key>
80
- <false/>
81
- </dict>
82
- <key>ThrottleInterval</key>
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 install_windows() -> bool:
251
- python = get_python_path()
252
- log = get_log_path()
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 = Path.home() / ".superlocalmemory" / "start-daemon.vbs"
264
+ vbs_path = state_path("start-daemon.vbs")
256
265
  vbs_path.parent.mkdir(parents=True, exist_ok=True)
257
- vbs_content = (
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 = Path.home() / ".superlocalmemory" / "start-daemon.vbs"
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
- try:
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
- _SLM_HOME = _resolve_slm_home()
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 _SETUP_MARKER.exists()
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
- _SLM_HOME.mkdir(parents=True, exist_ok=True)
294
- _SETUP_MARKER.write_text(
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: {_SLM_HOME}")
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(" Zero cloud. Zero LLM. Full privacy.")
355
- print(" EU AI Act compliant. Works immediately.")
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
- _SLM_HOME.mkdir(parents=True, exist_ok=True)
447
- cg_config_path = _SLM_HOME / "code_graph_config.json"
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 = _SLM_HOME / "adapters.json"
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
- _SLM_HOME.mkdir(parents=True, exist_ok=True)
617
- evo_config_path = _SLM_HOME / "config.json"
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(_SLM_HOME)
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, _SLM_HOME)
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
- On first use, also auto-installs Claude Code hooks so pip installs have
732
- the same "it just works" experience as npm installs (npm does this via
733
- postinstall; pip has no postinstall, so we do it here).
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 = {"setup", "init", "hook", "hooks", "reap", "mcp"}
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, DEFAULT_BASE_DIR
740
+ from superlocalmemory.core.config import SLMConfig
750
741
  from superlocalmemory.storage.models import Mode
751
- config_path = DEFAULT_BASE_DIR / "config.json"
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 _maybe_install_hooks_on_first_use() -> None:
770
- """Install Claude Code hooks on first SLM run — matches npm postinstall.
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
- Install/uninstall parity rules:
778
+ Installation rules:
773
779
  * Skip if the user explicitly opted out via ``slm hooks remove``
774
- (creates ``~/.superlocalmemory/hooks/.hooks-disabled``).
775
- * Skip if Claude Code isn't installed (no ``~/.claude/settings.json``
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 = _SLM_HOME / "hooks" / ".hooks-disabled"
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
- return # Claude Code not installed — nothing to hook into.
786
- from superlocalmemory.hooks.claude_code_hooks import install_hooks
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: parity-fallback, never block CLI.
791
+ # Best-effort: never block setup over an optional integration.
790
792
  pass
791
793
 
792
- # T1-B: Auto-install Claude Code plugin (skills, agents, hooks).
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() -> None:
798
- """Auto-install the Claude Code plugin on first pip/uvx SLM install.
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
- return # Claude Code not in PATH skip silently
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
- _run([claude, "plugin", "marketplace", "add", "qualixar/superlocalmemory"])
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
- pass
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
- _run([claude, "plugin", "install", "superlocalmemory@qualixar"])
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
- pass
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
- for i, name in enumerate(providers, 1):
843
- preset = presets[name]
844
- print(f" [{i}] {name.capitalize()} — {preset['model']}")
845
- print()
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
- idx = _prompt(f" Select provider [1-{len(providers)}]: ", "1")
848
- try:
849
- provider_name = providers[int(idx) - 1]
850
- except (ValueError, IndexError):
851
- print(" Invalid choice. Using OpenAI.")
852
- provider_name = "openai"
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
- updated = SLMConfig.for_mode(
870
- Mode.C,
871
- llm_provider=provider_name,
872
- llm_model=preset["model"],
873
- llm_api_key=api_key,
874
- llm_api_base=preset["base_url"],
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
- return Path(os.environ.get("SLM_DATA_DIR") or Path.home() / ".superlocalmemory")
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 Path.home() / ".superlocalmemory" / "code_graph.db"
90
+ return state_path("code_graph.db")