superlocalmemory 3.4.3 → 3.4.4
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/README.md +9 -12
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/superlocalmemory/cli/commands.py +29 -0
- package/src/superlocalmemory/cli/daemon.py +128 -68
- package/src/superlocalmemory/cli/main.py +15 -2
- package/src/superlocalmemory/cli/service_installer.py +367 -0
- package/src/superlocalmemory/cli/setup_wizard.py +13 -0
- package/src/superlocalmemory/mcp/server.py +32 -3
- package/src/superlocalmemory/mcp/tools_mesh.py +249 -0
- package/src/superlocalmemory/server/routes/adapters.py +63 -0
- package/src/superlocalmemory/server/routes/entity.py +56 -0
- package/src/superlocalmemory/server/unified_daemon.py +2 -0
- package/src/superlocalmemory/ui/css/neural-glass.css +1588 -0
- package/src/superlocalmemory/ui/index.html +134 -4
- package/src/superlocalmemory/ui/js/memory-chat.js +28 -1
- package/src/superlocalmemory/ui/js/ng-entities.js +272 -0
- package/src/superlocalmemory/ui/js/ng-health.js +208 -0
- package/src/superlocalmemory/ui/js/ng-ingestion.js +203 -0
- package/src/superlocalmemory/ui/js/ng-mesh.js +311 -0
- package/src/superlocalmemory/ui/js/ng-shell.js +471 -0
- package/src/superlocalmemory.egg-info/PKG-INFO +601 -0
- package/src/superlocalmemory.egg-info/SOURCES.txt +313 -0
- package/src/superlocalmemory.egg-info/dependency_links.txt +1 -0
- package/src/superlocalmemory.egg-info/entry_points.txt +2 -0
- package/src/superlocalmemory.egg-info/requires.txt +55 -0
- package/src/superlocalmemory.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under the Elastic License 2.0 - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
|
|
5
|
+
"""OS-level service installer — daemon survives reboots.
|
|
6
|
+
|
|
7
|
+
Cross-platform:
|
|
8
|
+
- macOS: LaunchAgent plist (user-level, no sudo)
|
|
9
|
+
- Linux: systemd user service (no sudo)
|
|
10
|
+
- Windows: Task Scheduler (runs at logon)
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
slm serve install — install OS service
|
|
14
|
+
slm serve uninstall — remove OS service
|
|
15
|
+
slm serve status — show daemon + service status
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import logging
|
|
21
|
+
import os
|
|
22
|
+
import shutil
|
|
23
|
+
import subprocess
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
_SERVICE_NAME = "com.qualixar.superlocalmemory"
|
|
30
|
+
_DISPLAY_NAME = "SuperLocalMemory Daemon"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_python_path() -> str:
|
|
34
|
+
"""Get the full path to the Python interpreter running SLM."""
|
|
35
|
+
return sys.executable
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_log_path() -> Path:
|
|
39
|
+
log_dir = Path.home() / ".superlocalmemory" / "logs"
|
|
40
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
return log_dir / "daemon.log"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_error_log_path() -> Path:
|
|
45
|
+
log_dir = Path.home() / ".superlocalmemory" / "logs"
|
|
46
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
return log_dir / "daemon-error.log"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ─── macOS: LaunchAgent ───────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
def _macos_plist_path() -> Path:
|
|
53
|
+
return Path.home() / "Library" / "LaunchAgents" / f"{_SERVICE_NAME}.plist"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _macos_plist_content() -> str:
|
|
57
|
+
python = get_python_path()
|
|
58
|
+
log = get_log_path()
|
|
59
|
+
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
|
+
"""
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def install_macos() -> bool:
|
|
101
|
+
plist = _macos_plist_path()
|
|
102
|
+
plist.parent.mkdir(parents=True, exist_ok=True)
|
|
103
|
+
plist.write_text(_macos_plist_content())
|
|
104
|
+
logger.info("Wrote LaunchAgent plist: %s", plist)
|
|
105
|
+
|
|
106
|
+
# Load the service
|
|
107
|
+
try:
|
|
108
|
+
subprocess.run(
|
|
109
|
+
["launchctl", "unload", str(plist)],
|
|
110
|
+
capture_output=True, timeout=10,
|
|
111
|
+
)
|
|
112
|
+
except Exception:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
result = subprocess.run(
|
|
116
|
+
["launchctl", "load", str(plist)],
|
|
117
|
+
capture_output=True, text=True, timeout=10,
|
|
118
|
+
)
|
|
119
|
+
if result.returncode == 0:
|
|
120
|
+
logger.info("LaunchAgent loaded successfully")
|
|
121
|
+
return True
|
|
122
|
+
else:
|
|
123
|
+
logger.error("launchctl load failed: %s", result.stderr)
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def uninstall_macos() -> bool:
|
|
128
|
+
plist = _macos_plist_path()
|
|
129
|
+
if plist.exists():
|
|
130
|
+
try:
|
|
131
|
+
subprocess.run(
|
|
132
|
+
["launchctl", "unload", str(plist)],
|
|
133
|
+
capture_output=True, timeout=10,
|
|
134
|
+
)
|
|
135
|
+
except Exception:
|
|
136
|
+
pass
|
|
137
|
+
plist.unlink()
|
|
138
|
+
logger.info("LaunchAgent removed: %s", plist)
|
|
139
|
+
return True
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def status_macos() -> dict:
|
|
143
|
+
result = subprocess.run(
|
|
144
|
+
["launchctl", "list", _SERVICE_NAME],
|
|
145
|
+
capture_output=True, text=True, timeout=10,
|
|
146
|
+
)
|
|
147
|
+
installed = result.returncode == 0
|
|
148
|
+
return {
|
|
149
|
+
"platform": "macOS",
|
|
150
|
+
"service_type": "LaunchAgent",
|
|
151
|
+
"installed": installed,
|
|
152
|
+
"plist_path": str(_macos_plist_path()),
|
|
153
|
+
"details": result.stdout.strip() if installed else "Not installed",
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# ─── Linux: systemd user service ──────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
def _linux_service_path() -> Path:
|
|
160
|
+
return Path.home() / ".config" / "systemd" / "user" / "superlocalmemory.service"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _linux_service_content() -> str:
|
|
164
|
+
python = get_python_path()
|
|
165
|
+
log = get_log_path()
|
|
166
|
+
|
|
167
|
+
return f"""[Unit]
|
|
168
|
+
Description={_DISPLAY_NAME}
|
|
169
|
+
After=network.target
|
|
170
|
+
|
|
171
|
+
[Service]
|
|
172
|
+
Type=simple
|
|
173
|
+
ExecStart={python} -m superlocalmemory.server.unified_daemon --start
|
|
174
|
+
Restart=on-failure
|
|
175
|
+
RestartSec=30
|
|
176
|
+
StandardOutput=append:{log}
|
|
177
|
+
StandardError=append:{get_error_log_path()}
|
|
178
|
+
Environment=HOME={Path.home()}
|
|
179
|
+
Environment=PATH=/usr/local/bin:/usr/bin:/bin:{Path(python).parent}
|
|
180
|
+
|
|
181
|
+
[Install]
|
|
182
|
+
WantedBy=default.target
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def install_linux() -> bool:
|
|
187
|
+
service = _linux_service_path()
|
|
188
|
+
service.parent.mkdir(parents=True, exist_ok=True)
|
|
189
|
+
service.write_text(_linux_service_content())
|
|
190
|
+
logger.info("Wrote systemd user service: %s", service)
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
subprocess.run(["systemctl", "--user", "daemon-reload"], capture_output=True, timeout=10)
|
|
194
|
+
subprocess.run(["systemctl", "--user", "enable", "superlocalmemory"], capture_output=True, timeout=10)
|
|
195
|
+
result = subprocess.run(
|
|
196
|
+
["systemctl", "--user", "start", "superlocalmemory"],
|
|
197
|
+
capture_output=True, text=True, timeout=10,
|
|
198
|
+
)
|
|
199
|
+
if result.returncode == 0:
|
|
200
|
+
logger.info("systemd user service started")
|
|
201
|
+
return True
|
|
202
|
+
else:
|
|
203
|
+
logger.error("systemctl start failed: %s", result.stderr)
|
|
204
|
+
return False
|
|
205
|
+
except FileNotFoundError:
|
|
206
|
+
logger.warning("systemctl not found — systemd not available on this system")
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def uninstall_linux() -> bool:
|
|
211
|
+
try:
|
|
212
|
+
subprocess.run(["systemctl", "--user", "stop", "superlocalmemory"], capture_output=True, timeout=10)
|
|
213
|
+
subprocess.run(["systemctl", "--user", "disable", "superlocalmemory"], capture_output=True, timeout=10)
|
|
214
|
+
except Exception:
|
|
215
|
+
pass
|
|
216
|
+
service = _linux_service_path()
|
|
217
|
+
if service.exists():
|
|
218
|
+
service.unlink()
|
|
219
|
+
logger.info("systemd user service removed: %s", service)
|
|
220
|
+
try:
|
|
221
|
+
subprocess.run(["systemctl", "--user", "daemon-reload"], capture_output=True, timeout=10)
|
|
222
|
+
except Exception:
|
|
223
|
+
pass
|
|
224
|
+
return True
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def status_linux() -> dict:
|
|
228
|
+
try:
|
|
229
|
+
result = subprocess.run(
|
|
230
|
+
["systemctl", "--user", "is-active", "superlocalmemory"],
|
|
231
|
+
capture_output=True, text=True, timeout=10,
|
|
232
|
+
)
|
|
233
|
+
active = result.stdout.strip() == "active"
|
|
234
|
+
return {
|
|
235
|
+
"platform": "Linux",
|
|
236
|
+
"service_type": "systemd user service",
|
|
237
|
+
"installed": True,
|
|
238
|
+
"active": active,
|
|
239
|
+
"details": result.stdout.strip(),
|
|
240
|
+
}
|
|
241
|
+
except Exception:
|
|
242
|
+
return {"platform": "Linux", "service_type": "systemd", "installed": False}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# ─── Windows: Task Scheduler ─────────────────────────────────────────────
|
|
246
|
+
|
|
247
|
+
_WINDOWS_TASK_NAME = "SuperLocalMemory"
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def install_windows() -> bool:
|
|
251
|
+
python = get_python_path()
|
|
252
|
+
log = get_log_path()
|
|
253
|
+
|
|
254
|
+
# Create a VBS wrapper to run Python without console window
|
|
255
|
+
vbs_path = Path.home() / ".superlocalmemory" / "start-daemon.vbs"
|
|
256
|
+
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)
|
|
262
|
+
|
|
263
|
+
# Use schtasks to create a logon trigger task
|
|
264
|
+
try:
|
|
265
|
+
# Remove existing task if any
|
|
266
|
+
subprocess.run(
|
|
267
|
+
["schtasks", "/Delete", "/TN", _WINDOWS_TASK_NAME, "/F"],
|
|
268
|
+
capture_output=True, timeout=10,
|
|
269
|
+
)
|
|
270
|
+
except Exception:
|
|
271
|
+
pass
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
result = subprocess.run(
|
|
275
|
+
[
|
|
276
|
+
"schtasks", "/Create",
|
|
277
|
+
"/TN", _WINDOWS_TASK_NAME,
|
|
278
|
+
"/TR", f'wscript.exe "{vbs_path}"',
|
|
279
|
+
"/SC", "ONLOGON",
|
|
280
|
+
"/RL", "LIMITED",
|
|
281
|
+
"/F",
|
|
282
|
+
],
|
|
283
|
+
capture_output=True, text=True, timeout=10,
|
|
284
|
+
)
|
|
285
|
+
if result.returncode == 0:
|
|
286
|
+
logger.info("Windows Task Scheduler task created: %s", _WINDOWS_TASK_NAME)
|
|
287
|
+
return True
|
|
288
|
+
else:
|
|
289
|
+
logger.error("schtasks create failed: %s", result.stderr)
|
|
290
|
+
return False
|
|
291
|
+
except FileNotFoundError:
|
|
292
|
+
logger.warning("schtasks not found — not a standard Windows system")
|
|
293
|
+
return False
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def uninstall_windows() -> bool:
|
|
297
|
+
try:
|
|
298
|
+
subprocess.run(
|
|
299
|
+
["schtasks", "/Delete", "/TN", _WINDOWS_TASK_NAME, "/F"],
|
|
300
|
+
capture_output=True, timeout=10,
|
|
301
|
+
)
|
|
302
|
+
logger.info("Windows Task Scheduler task removed")
|
|
303
|
+
except Exception:
|
|
304
|
+
pass
|
|
305
|
+
|
|
306
|
+
vbs_path = Path.home() / ".superlocalmemory" / "start-daemon.vbs"
|
|
307
|
+
if vbs_path.exists():
|
|
308
|
+
vbs_path.unlink()
|
|
309
|
+
|
|
310
|
+
return True
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def status_windows() -> dict:
|
|
314
|
+
try:
|
|
315
|
+
result = subprocess.run(
|
|
316
|
+
["schtasks", "/Query", "/TN", _WINDOWS_TASK_NAME, "/FO", "LIST"],
|
|
317
|
+
capture_output=True, text=True, timeout=10,
|
|
318
|
+
)
|
|
319
|
+
installed = result.returncode == 0
|
|
320
|
+
return {
|
|
321
|
+
"platform": "Windows",
|
|
322
|
+
"service_type": "Task Scheduler",
|
|
323
|
+
"installed": installed,
|
|
324
|
+
"task_name": _WINDOWS_TASK_NAME,
|
|
325
|
+
"details": result.stdout.strip()[:200] if installed else "Not installed",
|
|
326
|
+
}
|
|
327
|
+
except Exception:
|
|
328
|
+
return {"platform": "Windows", "service_type": "Task Scheduler", "installed": False}
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# ─── Cross-platform dispatcher ───────────────────────────────────────────
|
|
332
|
+
|
|
333
|
+
def install_service() -> bool:
|
|
334
|
+
"""Install OS-level service for auto-start on login/boot."""
|
|
335
|
+
if sys.platform == "darwin":
|
|
336
|
+
return install_macos()
|
|
337
|
+
elif sys.platform == "win32":
|
|
338
|
+
return install_windows()
|
|
339
|
+
elif sys.platform.startswith("linux"):
|
|
340
|
+
return install_linux()
|
|
341
|
+
else:
|
|
342
|
+
logger.warning("Unsupported platform: %s", sys.platform)
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def uninstall_service() -> bool:
|
|
347
|
+
"""Remove OS-level service."""
|
|
348
|
+
if sys.platform == "darwin":
|
|
349
|
+
return uninstall_macos()
|
|
350
|
+
elif sys.platform == "win32":
|
|
351
|
+
return uninstall_windows()
|
|
352
|
+
elif sys.platform.startswith("linux"):
|
|
353
|
+
return uninstall_linux()
|
|
354
|
+
else:
|
|
355
|
+
return False
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def service_status() -> dict:
|
|
359
|
+
"""Get OS-level service status."""
|
|
360
|
+
if sys.platform == "darwin":
|
|
361
|
+
return status_macos()
|
|
362
|
+
elif sys.platform == "win32":
|
|
363
|
+
return status_windows()
|
|
364
|
+
elif sys.platform.startswith("linux"):
|
|
365
|
+
return status_linux()
|
|
366
|
+
else:
|
|
367
|
+
return {"platform": sys.platform, "installed": False, "details": "Unsupported platform"}
|
|
@@ -548,10 +548,23 @@ def run_wizard(auto: bool = False) -> None:
|
|
|
548
548
|
print(' slm recall "search query"')
|
|
549
549
|
print(" slm dashboard → http://localhost:8765")
|
|
550
550
|
print(" slm adapters enable gmail → start Gmail ingestion")
|
|
551
|
+
print()
|
|
552
|
+
# V3.4.4: Auto-install OS service for daemon persistence (survive reboots)
|
|
553
|
+
try:
|
|
554
|
+
from superlocalmemory.cli.service_installer import install_service
|
|
555
|
+
print(" Installing OS service for auto-start...")
|
|
556
|
+
if install_service():
|
|
557
|
+
print(" ✓ SLM will auto-start on login — zero friction.")
|
|
558
|
+
else:
|
|
559
|
+
print(" ⚠ OS service not installed (run: slm serve install)")
|
|
560
|
+
except Exception:
|
|
561
|
+
print(" ⚠ Could not install OS service (run: slm serve install)")
|
|
562
|
+
|
|
551
563
|
print()
|
|
552
564
|
print(" Need help?")
|
|
553
565
|
print(" slm doctor — diagnose issues")
|
|
554
566
|
print(" slm --help — all commands")
|
|
567
|
+
print(" slm serve install — install auto-start service")
|
|
555
568
|
print(" https://github.com/qualixar/superlocalmemory")
|
|
556
569
|
print()
|
|
557
570
|
|
|
@@ -65,7 +65,7 @@ def reset_engine():
|
|
|
65
65
|
|
|
66
66
|
import os as _os_reg
|
|
67
67
|
|
|
68
|
-
_ESSENTIAL_TOOLS:
|
|
68
|
+
_ESSENTIAL_TOOLS: set[str] = {
|
|
69
69
|
# Core memory operations (8)
|
|
70
70
|
"remember", "recall", "search", "fetch",
|
|
71
71
|
"list_recent", "delete_memory", "update_memory", "get_status",
|
|
@@ -76,7 +76,25 @@ _ESSENTIAL_TOOLS: frozenset[str] = frozenset({
|
|
|
76
76
|
# Infinite memory + learning (4)
|
|
77
77
|
"consolidate_cognitive", "get_soft_prompts",
|
|
78
78
|
"set_mode", "report_outcome",
|
|
79
|
-
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# v3.4.4: Mesh tools — enabled if mesh_enabled in config or SLM_MCP_MESH_TOOLS=1
|
|
82
|
+
_mesh_tools_enabled = _os_reg.environ.get("SLM_MCP_MESH_TOOLS", "").lower() in ("1", "true")
|
|
83
|
+
if not _mesh_tools_enabled:
|
|
84
|
+
try:
|
|
85
|
+
from superlocalmemory.core.config import SLMConfig
|
|
86
|
+
_cfg = SLMConfig.load()
|
|
87
|
+
_mesh_tools_enabled = getattr(_cfg, "mesh_enabled", True) # default True in v3.4.3+
|
|
88
|
+
except Exception:
|
|
89
|
+
_mesh_tools_enabled = True # Safe default — mesh broker is always in daemon
|
|
90
|
+
|
|
91
|
+
if _mesh_tools_enabled:
|
|
92
|
+
_ESSENTIAL_TOOLS.update({
|
|
93
|
+
"mesh_summary", "mesh_peers", "mesh_send", "mesh_inbox",
|
|
94
|
+
"mesh_state", "mesh_lock", "mesh_events", "mesh_status",
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
_ESSENTIAL_TOOLS = frozenset(_ESSENTIAL_TOOLS)
|
|
80
98
|
|
|
81
99
|
_all_tools = _os_reg.environ.get("SLM_MCP_ALL_TOOLS") == "1"
|
|
82
100
|
|
|
@@ -115,6 +133,7 @@ from superlocalmemory.mcp.tools_active import register_active_tools
|
|
|
115
133
|
from superlocalmemory.mcp.tools_v33 import register_v33_tools
|
|
116
134
|
from superlocalmemory.mcp.resources import register_resources
|
|
117
135
|
from superlocalmemory.mcp.tools_code_graph import register_code_graph_tools
|
|
136
|
+
from superlocalmemory.mcp.tools_mesh import register_mesh_tools
|
|
118
137
|
|
|
119
138
|
register_core_tools(_target, get_engine)
|
|
120
139
|
register_v28_tools(_target, get_engine)
|
|
@@ -123,6 +142,7 @@ register_active_tools(_target, get_engine)
|
|
|
123
142
|
register_v33_tools(_target, get_engine)
|
|
124
143
|
register_resources(server, get_engine) # Resources always registered (not tools)
|
|
125
144
|
register_code_graph_tools(_target, get_engine) # CodeGraph: filtered like other tools (SLM_MCP_ALL_TOOLS=1 to show all)
|
|
145
|
+
register_mesh_tools(_target, get_engine) # v3.4.4: Mesh P2P tools — ships with SLM, no separate slm-mesh needed
|
|
126
146
|
|
|
127
147
|
|
|
128
148
|
# V3.3.21: Eager engine warmup — start initializing BEFORE first tool call.
|
|
@@ -132,7 +152,7 @@ register_code_graph_tools(_target, get_engine) # CodeGraph: filtered like other
|
|
|
132
152
|
# the first tool call arrives (1-2s later), the engine is already warm.
|
|
133
153
|
# This applies to ALL IDEs: Claude Code, Cursor, Antigravity, Gemini CLI, etc.
|
|
134
154
|
def _eager_warmup() -> None:
|
|
135
|
-
"""Pre-warm engine
|
|
155
|
+
"""Pre-warm engine + ensure daemon is running (background thread)."""
|
|
136
156
|
import logging
|
|
137
157
|
_logger = logging.getLogger(__name__)
|
|
138
158
|
try:
|
|
@@ -141,6 +161,15 @@ def _eager_warmup() -> None:
|
|
|
141
161
|
except Exception as exc:
|
|
142
162
|
_logger.debug("MCP engine pre-warmup failed (non-fatal): %s", exc)
|
|
143
163
|
|
|
164
|
+
# V3.4.4: Also ensure daemon is running for dashboard/mesh/health features.
|
|
165
|
+
# This runs in background — doesn't block MCP tool registration.
|
|
166
|
+
try:
|
|
167
|
+
from superlocalmemory.cli.daemon import ensure_daemon
|
|
168
|
+
if ensure_daemon():
|
|
169
|
+
_logger.info("Daemon auto-started by MCP server")
|
|
170
|
+
except Exception as exc:
|
|
171
|
+
_logger.debug("Daemon auto-start failed (non-fatal): %s", exc)
|
|
172
|
+
|
|
144
173
|
import threading
|
|
145
174
|
_warmup_thread = threading.Thread(target=_eager_warmup, daemon=True, name="mcp-warmup")
|
|
146
175
|
_warmup_thread.start()
|