superlocalmemory 3.8.11 → 3.8.13
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 +85 -0
- package/README.md +7 -3
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/agents/slm-optimize-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-cache/SKILL.md +1 -1
- package/plugin/skills/slm-compress/SKILL.md +1 -1
- package/plugin/skills/slm-governance/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-loop/SKILL.md +1 -1
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +1 -1
- package/plugin/skills/slm-recall/SKILL.md +1 -1
- package/plugin/skills/slm-remember/SKILL.md +1 -1
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/skills/slm-cache/SKILL.md +1 -1
- package/plugin-src/skills/slm-compress/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-recall/SKILL.md +1 -1
- package/plugin-src/skills/slm-remember/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/pyproject.toml +1 -1
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/commands.py +62 -3
- package/src/superlocalmemory/cli/daemon.py +219 -10
- package/src/superlocalmemory/cli/setup_wizard.py +45 -1
- package/src/superlocalmemory/core/component_registry.py +25 -0
- package/src/superlocalmemory/core/config.py +35 -1
- package/src/superlocalmemory/core/engine_wiring.py +81 -5
- package/src/superlocalmemory/core/recall_pipeline.py +25 -4
- package/src/superlocalmemory/core/reranker_worker.py +23 -4
- package/src/superlocalmemory/infra/daemon_identity.py +16 -0
- package/src/superlocalmemory/infra/process_identity.py +180 -0
- package/src/superlocalmemory/infra/version_integrity.py +229 -0
- package/src/superlocalmemory/learning/feedback.py +288 -29
- package/src/superlocalmemory/learning/legacy_migration.py +45 -4
- package/src/superlocalmemory/mcp/_daemon_proxy.py +23 -1
- package/src/superlocalmemory/mcp/tools_active.py +109 -58
- package/src/superlocalmemory/mcp/tools_core.py +6 -5
- package/src/superlocalmemory/retrieval/remote_reranker.py +636 -0
- package/src/superlocalmemory/server/unified_daemon.py +27 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,91 @@ All notable changes to SuperLocalMemory V3 will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.8.13] - 2026-08-03 — Stale-process detection
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- A running process can now tell when it is serving superseded code. Python
|
|
12
|
+
imports a module once, so `__version__` is frozen at process start and
|
|
13
|
+
upgrading the package underneath a long-lived `slm mcp` server changes
|
|
14
|
+
nothing for that server — it keeps serving the code it read at startup,
|
|
15
|
+
indefinitely. Nothing detected this. The stale process did not error; it
|
|
16
|
+
returned confident, plausible, wrong answers and reported a
|
|
17
|
+
`serverInfo.version` matching the code it had loaded, which is
|
|
18
|
+
self-consistent and therefore useless as a staleness signal. During the
|
|
19
|
+
3.8.12 work one machine had eighteen `slm mcp` processes alive at once
|
|
20
|
+
spanning four days and two releases, and one of them made issue #106 look
|
|
21
|
+
unfixed across two debugging sessions. (#107)
|
|
22
|
+
|
|
23
|
+
The existing process reaper does not cover this: it kills *orphans*, whose
|
|
24
|
+
parent has died. A server whose IDE is still running is never an orphan.
|
|
25
|
+
|
|
26
|
+
Staleness is now reported by `slm doctor` (as a warning, with a restart
|
|
27
|
+
hint), on the loopback `/health` payload as `version_integrity`, and in the
|
|
28
|
+
`slm mcp` startup log. The MCP path logs to stderr only — that transport is
|
|
29
|
+
JSON-RPC over stdio, where a printed warning would corrupt the protocol and
|
|
30
|
+
turn a cosmetic problem into a dead session.
|
|
31
|
+
|
|
32
|
+
Running *ahead* of the installed distribution — normal for an editable
|
|
33
|
+
checkout — is deliberately reported separately and does not warn. A warning
|
|
34
|
+
that fires on every developer machine is one everybody learns to ignore, and
|
|
35
|
+
then it goes unread on the day it matters. Every failure path resolves to
|
|
36
|
+
`unknown` rather than to a false `current`.
|
|
37
|
+
|
|
38
|
+
## [3.8.12] - 2026-08-03 — Canonical learning signals, clock-independent daemon identity, remote reranker
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
- Explicit feedback now reaches the store every consumer actually reads.
|
|
42
|
+
Three tables carry a "feedback" name: `feedback_records` (memory.db, read by
|
|
43
|
+
nothing), `learning_feedback` (the pre-v3.4.22 legacy table that
|
|
44
|
+
`legacy_migration` copies forward), and `learning_signals` +
|
|
45
|
+
`learning_features` (canonical — read by the dashboard Living Brain panel,
|
|
46
|
+
the ranker-phase card, and the LightGBM retrainer). The 3.8.11 fix wrote to
|
|
47
|
+
the legacy table, so it moved a counter nothing consumes. `record_explicit`
|
|
48
|
+
now writes the legacy row and the canonical signal/feature pair in one
|
|
49
|
+
transaction, flagged `is_synthetic=1` so the LightGBM trainer's
|
|
50
|
+
`WHERE is_synthetic=0` filter excludes them from training. (#106)
|
|
51
|
+
- The recall phase gate and the dashboard no longer read different tables.
|
|
52
|
+
The gate counted `learning_feedback` while every user-visible surface counted
|
|
53
|
+
`learning_signals`, so the phase a user was shown and the phase that actually
|
|
54
|
+
ranked their results could disagree without limit. Both now resolve from the
|
|
55
|
+
canonical store, with thresholds imported from `learning.ranker` rather than
|
|
56
|
+
duplicated as literals — duplicated literals are how the two surfaces drifted
|
|
57
|
+
apart in the first place. (#106)
|
|
58
|
+
- `report_feedback` no longer reports success for a write that did not happen.
|
|
59
|
+
It fell back to the `feedback_records` count when the canonical read failed,
|
|
60
|
+
and that table increments on every call regardless, so total write failure was
|
|
61
|
+
indistinguishable from success. The cross-store fallback is removed; a failed
|
|
62
|
+
durable write returns `success: false` with `durable: false`. (#106)
|
|
63
|
+
- The CLI no longer disowns a healthy daemon after a few minutes on WSL2.
|
|
64
|
+
psutil derives `create_time` as boot time plus start ticks and re-reads
|
|
65
|
+
`/proc/stat` `btime` on every call; WSL2 resyncs its VM clock mid-session, so
|
|
66
|
+
`btime` moves and every process's computed creation time moves with it,
|
|
67
|
+
retroactively. The recorded value stopped matching the same live PID while
|
|
68
|
+
`/health` still answered in milliseconds. Ownership now compares a
|
|
69
|
+
clock-independent process token — `boot_id` plus raw start ticks on
|
|
70
|
+
Linux/WSL2, psutil's monotonic creation time elsewhere — as exact equality,
|
|
71
|
+
with no tolerance constant left to silently expire. PID-reuse protection is
|
|
72
|
+
strengthened: a creation-time mismatch no longer condemns a process outright,
|
|
73
|
+
it falls through to cryptographic identity proof over loopback. (#104)
|
|
74
|
+
- `DAEMON_UNAVAILABLE` now names one of eight specific reasons with an
|
|
75
|
+
actionable hint instead of "owned daemon is unavailable; retry later". (#104)
|
|
76
|
+
- `slm setup` no longer wipes the `retrieval` config block on every re-run.
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
- Remote and custom reranker endpoints, mirroring the remote embedding support
|
|
80
|
+
added in v3.4.24. Setting `cross_encoder_backend` to `openai` (or `remote`)
|
|
81
|
+
with a `cross_encoder_endpoint` routes reranking to an OpenAI-compatible
|
|
82
|
+
`/v1/rerank` service instead of the local subprocess worker. The built-in
|
|
83
|
+
cross-encoder is English-only, silently degrading recall for non-English
|
|
84
|
+
users; this lets them bring a multilingual model. Failure degrades to fusion
|
|
85
|
+
order with `applied=False` and an error log — never a silent fall back to the
|
|
86
|
+
local English model, which would recreate the very problem this solves. The
|
|
87
|
+
new outbound HTTP surface enforces an http/https allow-list, rejects 3xx and
|
|
88
|
+
does not follow redirects, refuses credentials embedded in the URL, and
|
|
89
|
+
bounds response reads at 8 MB. (#105)
|
|
90
|
+
- `cross_encoder_endpoint` is now a real config field. It was previously
|
|
91
|
+
accepted and silently ignored — the remaining half of #103.
|
|
92
|
+
|
|
8
93
|
## [3.8.11] - 2026-08-02 — Learning-signal integrity and honest reranker diagnostics
|
|
9
94
|
|
|
10
95
|
### Fixed
|
package/README.md
CHANGED
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
<h1 align="center">SuperLocalMemory V3.8.
|
|
8
|
+
<h1 align="center">SuperLocalMemory V3.8.13</h1>
|
|
9
9
|
<p align="center"><strong>Enterprise-grade, local-first memory for AI agents and teams.</strong><br/>
|
|
10
10
|
<em>A persistent, auditable long-term brain for your agents that runs on your own infrastructure — with multi-workspace isolation, role-based access, and GDPR + EU AI Act governance controls built in.</em></p>
|
|
11
|
-
<p align="center"><code>v3.8.
|
|
11
|
+
<p align="center"><code>v3.8.13</code> — one control plane: auditable retrieval · multi-scope memory (personal / shared / global) · Cache · Compress · trusted-peer Mesh · bounded loops — across CLI, MCP, dashboard, the <strong>Claude plugin</strong>, the <strong>Codex add-on</strong>, and documented IDE integrations.<br/>
|
|
12
12
|
Proxy: <code>slm wrap claude</code> · MCP: add <code>slm_compress</code> to your config · Skill: zero-config</p>
|
|
13
13
|
<p align="center"><strong>3 public research preprints</strong> (arXiv + Zenodo archives) · <a href="https://arxiv.org/abs/2603.02240">arXiv:2603.02240</a> · <a href="https://arxiv.org/abs/2603.14588">arXiv:2603.14588</a> · <a href="https://arxiv.org/abs/2604.04514">arXiv:2604.04514</a></p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
16
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/v3.8.
|
|
16
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/v3.8.13-Current_Release-2ea44f?style=for-the-badge&logo=checkmarx&logoColor=white" alt="v3.8.13 — Current Release"/></a>
|
|
17
17
|
<a href="https://arxiv.org/abs/2603.14588"><img src="https://img.shields.io/badge/arXiv-2603.14588-b31b1b?style=for-the-badge&logo=arxiv&logoColor=white" alt="arXiv Paper"/></a>
|
|
18
18
|
<a href="#three-surfaces-proxy--mcp-tools--skill"><img src="https://img.shields.io/badge/Proxy_|_MCP_|_Skill-22c55e?style=for-the-badge" alt="Three Surfaces: Proxy, MCP Tools, Skill"/></a>
|
|
19
19
|
<a href="https://pypi.org/project/superlocalmemory/"><img src="https://img.shields.io/pypi/v/superlocalmemory?style=for-the-badge&logo=pypi&logoColor=white" alt="PyPI"/></a>
|
|
@@ -294,6 +294,10 @@ quality must be evaluated for the target client and workload; V3.8.0 publishes n
|
|
|
294
294
|
|
|
295
295
|
**Multilingual models:** configure an OpenAI-compatible embedding endpoint such as Ollama, vLLM, LiteLLM, `bge-m3`, `multilingual-e5`, or `Qwen3-Embedding`. Language coverage and retrieval quality depend on the selected model and should be evaluated for the deployment corpus.
|
|
296
296
|
|
|
297
|
+
<a id="remote-embedding-and-rerank-endpoints"></a>
|
|
298
|
+
|
|
299
|
+
**Remote embedding + rerank endpoints.** The bundled reranker `cross-encoder/ms-marco-MiniLM-L-12-v2` is **English-only**, so a Chinese, Japanese, or Arabic corpus is scored by a model that cannot read it. Set `retrieval.cross_encoder_backend: "openai"` plus `retrieval.cross_encoder_endpoint` to route reranking to any Cohere-shaped `POST /v1/rerank` service — llama-server, text-embeddings-inference, Infinity — running a multilingual model such as `BAAI/bge-reranker-v2-m3` (v3.8.12, [#105](https://github.com/qualixar/superlocalmemory/issues/105); the same escape hatch embeddings got in v3.4.24, [#16](https://github.com/qualixar/superlocalmemory/issues/16)). No subprocess and no local model download. An unreachable, slow, or malformed endpoint logs an error and returns fusion-ranked results — SLM never silently substitutes the local English model. Keys, auth, and failure semantics: **[docs/configuration.md](docs/configuration.md#remote-embedding-and-rerank-endpoints)**.
|
|
300
|
+
|
|
297
301
|
### Cache + Compress
|
|
298
302
|
|
|
299
303
|
<a id="three-surfaces-proxy--mcp-tools--skill"></a>
|
package/package.json
CHANGED
package/plugin/CLAUDE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- BEGIN SuperLocalMemory v3.8.
|
|
1
|
+
<!-- BEGIN SuperLocalMemory v3.8.13 -->
|
|
2
2
|
|
|
3
3
|
## SuperLocalMemory (SLM) — Agent Rules
|
|
4
4
|
|
|
@@ -39,6 +39,6 @@ slm-recall · slm-remember · slm-session · slm-status · slm-cache · slm-comp
|
|
|
39
39
|
### Subagents
|
|
40
40
|
slm-memory-advisor (memory decisions, session hygiene, scope/profile guidance) · slm-optimize-advisor (context compression + KV cache) · slm-governance-advisor (scope/roles/compliance/GDPR)
|
|
41
41
|
|
|
42
|
-
<!-- END SuperLocalMemory v3.8.
|
|
42
|
+
<!-- END SuperLocalMemory v3.8.13 -->
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v3.8.
|
|
44
|
+
SuperLocalMemory v3.8.13 · Qualixar · AGPL-3.0-or-later
|
|
@@ -77,4 +77,4 @@ slm-scope · slm-governance · slm-profile · slm-remember · slm-recall
|
|
|
77
77
|
# What NOT to do
|
|
78
78
|
Never session_init twice; never forget without dry-run preview; never store secrets; never bypass role checks; never claim an erasure succeeded without verifying via recall.
|
|
79
79
|
|
|
80
|
-
SuperLocalMemory v3.8.
|
|
80
|
+
SuperLocalMemory v3.8.13 · Qualixar · AGPL-3.0-or-later
|
|
@@ -46,4 +46,4 @@ slm-recall · slm-remember · slm-session · slm-scope · slm-profile · slm-gov
|
|
|
46
46
|
# What NOT to do
|
|
47
47
|
Never session_init twice; never forget dry_run=False without reporting preview; never dump a whole file into remember; never invent a memory; never claim "saved" without success:true / clean CLI exit; never bypass scope or governance restrictions.
|
|
48
48
|
|
|
49
|
-
SuperLocalMemory v3.8.
|
|
49
|
+
SuperLocalMemory v3.8.13 · Qualixar · AGPL-3.0-or-later
|
|
@@ -41,4 +41,4 @@ slm-compress · slm-cache · slm-status · slm-profile
|
|
|
41
41
|
# What NOT to do
|
|
42
42
|
Never compress code-for-edit/JSON-to-parse/<500 chars; never store secrets/ccr_ids; never let optimize failure block/alter the task; never claim a specific savings %; never carry ccr_ids across profile switches.
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v3.8.
|
|
44
|
+
SuperLocalMemory v3.8.13 · Qualixar · AGPL-3.0-or-later
|
package/plugin/requirements.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
superlocalmemory==3.8.
|
|
1
|
+
superlocalmemory==3.8.13
|
|
@@ -128,4 +128,4 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
|
|
|
128
128
|
- **slm-optimize-advisor** — context compression and KV cache
|
|
129
129
|
- **slm-governance-advisor** — scope/role compliance, retention policies, GDPR
|
|
130
130
|
|
|
131
|
-
SuperLocalMemory v3.8.
|
|
131
|
+
SuperLocalMemory v3.8.13 · Qualixar · AGPL-3.0-or-later
|
package/pyproject.toml
CHANGED
|
@@ -32,7 +32,7 @@ if "OMP_NUM_THREADS" not in os.environ:
|
|
|
32
32
|
os.environ["OMP_NUM_THREADS"] = "2"
|
|
33
33
|
# ---------------------------------------------------------------------------
|
|
34
34
|
|
|
35
|
-
__version__ = "3.8.
|
|
35
|
+
__version__ = "3.8.13"
|
|
36
36
|
|
|
37
37
|
_REQUIRED_VERSIONS = {
|
|
38
38
|
"sentence_transformers": "5.3.0",
|
|
@@ -22,10 +22,21 @@ logger = logging.getLogger(__name__)
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def _daemon_unavailable(command: str, use_json: bool) -> None:
|
|
25
|
-
"""Exit a mutation client without opening a process-local writer.
|
|
25
|
+
"""Exit a mutation client without opening a process-local writer.
|
|
26
|
+
|
|
27
|
+
The bare "owned daemon is unavailable" of earlier releases described a
|
|
28
|
+
stopped daemon, a recycled PID, an unreachable port and an identity
|
|
29
|
+
mismatch identically, which gave issue #104's reporter nothing to act on.
|
|
30
|
+
The diagnosis names the evidence and the next command to run.
|
|
31
|
+
"""
|
|
32
|
+
from superlocalmemory.cli.daemon import describe_daemon_unavailability
|
|
33
|
+
|
|
34
|
+
diagnosis = describe_daemon_unavailability()
|
|
26
35
|
error = {
|
|
27
36
|
"code": "DAEMON_UNAVAILABLE",
|
|
28
|
-
"
|
|
37
|
+
"reason": diagnosis["reason"],
|
|
38
|
+
"message": f"Owned daemon is unavailable: {diagnosis['message']}",
|
|
39
|
+
"hint": diagnosis["hint"],
|
|
29
40
|
"retryable": True,
|
|
30
41
|
}
|
|
31
42
|
if use_json:
|
|
@@ -34,7 +45,8 @@ def _daemon_unavailable(command: str, use_json: bool) -> None:
|
|
|
34
45
|
json_print(command, error=error)
|
|
35
46
|
else:
|
|
36
47
|
print(
|
|
37
|
-
"DAEMON_UNAVAILABLE:
|
|
48
|
+
f"DAEMON_UNAVAILABLE ({diagnosis['reason']}): "
|
|
49
|
+
f"{diagnosis['message']} {diagnosis['hint']}",
|
|
38
50
|
file=sys.stderr,
|
|
39
51
|
)
|
|
40
52
|
raise SystemExit(1)
|
|
@@ -2282,6 +2294,28 @@ def cmd_doctor(args: Namespace) -> None:
|
|
|
2282
2294
|
_check("Python", "FAIL", f"{v.major}.{v.minor}.{v.micro} (need >= 3.11)",
|
|
2283
2295
|
"Install Python 3.11+ from https://python.org/downloads/")
|
|
2284
2296
|
|
|
2297
|
+
# 1b. Version integrity (issue #107). Doctor is what a user runs when
|
|
2298
|
+
# something seems wrong, so it is exactly where "the code you are running
|
|
2299
|
+
# is not the code you installed" has to appear. Reported as WARN rather
|
|
2300
|
+
# than FAIL: the installation is sound, it is this *process* that is
|
|
2301
|
+
# behind, and `slm doctor` itself is short-lived so it is rarely the
|
|
2302
|
+
# stale one -- it is reporting on behalf of the long-lived servers.
|
|
2303
|
+
try:
|
|
2304
|
+
from superlocalmemory.infra.version_integrity import check_version_integrity
|
|
2305
|
+
|
|
2306
|
+
_vi = check_version_integrity()
|
|
2307
|
+
if _vi.is_stale:
|
|
2308
|
+
_check("Version integrity", "WARN", _vi.detail, _vi.hint)
|
|
2309
|
+
elif _vi.state == "mismatch":
|
|
2310
|
+
_check("Version integrity", "WARN", _vi.detail, _vi.hint)
|
|
2311
|
+
elif _vi.state == "unknown":
|
|
2312
|
+
_check("Version integrity", "WARN", _vi.detail,
|
|
2313
|
+
"Reinstall so distribution metadata is readable.")
|
|
2314
|
+
else:
|
|
2315
|
+
_check("Version integrity", "PASS", _vi.detail)
|
|
2316
|
+
except Exception as _vi_exc: # noqa: BLE001 - never break doctor
|
|
2317
|
+
_check("Version integrity", "WARN", f"could not verify: {_vi_exc}")
|
|
2318
|
+
|
|
2285
2319
|
# 2. Core deps
|
|
2286
2320
|
core_modules = {
|
|
2287
2321
|
"numpy": "numpy", "scipy": "scipy", "networkx": "networkx",
|
|
@@ -2796,6 +2830,31 @@ def cmd_mcp(_args: Namespace) -> None:
|
|
|
2796
2830
|
except Exception:
|
|
2797
2831
|
pass # Never block MCP startup on cleanup failure
|
|
2798
2832
|
|
|
2833
|
+
# Version integrity (issue #107). The reaper above only kills *orphans* —
|
|
2834
|
+
# servers whose parent died. A server whose IDE is still alive is never an
|
|
2835
|
+
# orphan, so it survives upgrades indefinitely and keeps serving the code
|
|
2836
|
+
# it imported at startup. That is how eighteen `slm mcp` processes spanning
|
|
2837
|
+
# four days and two releases stayed alive on one machine, and how a stale
|
|
2838
|
+
# one made issue #106 look unfixed across two debugging sessions.
|
|
2839
|
+
#
|
|
2840
|
+
# This runs at startup, so a server launched *after* an upgrade is correct
|
|
2841
|
+
# by construction and stays silent. It fires for a server that started
|
|
2842
|
+
# before its own package was upgraded — which is possible when the client
|
|
2843
|
+
# respawns it from an old cached path.
|
|
2844
|
+
#
|
|
2845
|
+
# CRITICAL: logging only, never stdout — MCP speaks JSON-RPC over stdio and
|
|
2846
|
+
# any print corrupts the protocol. The logger writes to stderr.
|
|
2847
|
+
try:
|
|
2848
|
+
from superlocalmemory.infra.version_integrity import check_version_integrity
|
|
2849
|
+
|
|
2850
|
+
_vi = check_version_integrity()
|
|
2851
|
+
if _vi.is_stale:
|
|
2852
|
+
logger.warning("MCP server version drift: %s. %s", _vi.detail, _vi.hint)
|
|
2853
|
+
elif _vi.differs:
|
|
2854
|
+
logger.info("MCP server version note: %s", _vi.detail)
|
|
2855
|
+
except Exception:
|
|
2856
|
+
pass # A diagnostic must never prevent the server from starting.
|
|
2857
|
+
|
|
2799
2858
|
# Auto-install hooks on MCP startup (fast path: ~0.1ms if already current)
|
|
2800
2859
|
# CRITICAL: No stdout — MCP uses stdio transport, any print corrupts protocol
|
|
2801
2860
|
try:
|