superlocalmemory 3.8.3 → 3.8.5
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 +42 -0
- package/README.md +3 -2
- 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/access/rbac.py +68 -76
- package/src/superlocalmemory/cli/commands.py +19 -0
- package/src/superlocalmemory/cli/ingest_cmd.py +11 -1
- package/src/superlocalmemory/cli/main.py +30 -0
- package/src/superlocalmemory/cli/pending_store.py +39 -14
- package/src/superlocalmemory/core/backend_orchestrator.py +93 -0
- package/src/superlocalmemory/core/config.py +78 -0
- package/src/superlocalmemory/core/consolidation_engine.py +79 -73
- package/src/superlocalmemory/core/engine.py +92 -11
- package/src/superlocalmemory/core/fact_consolidator.py +148 -30
- package/src/superlocalmemory/core/graph_pruner.py +436 -39
- package/src/superlocalmemory/core/ingestion_command.py +160 -31
- package/src/superlocalmemory/core/maintenance_scheduler.py +61 -1
- package/src/superlocalmemory/core/recall_pipeline.py +3 -0
- package/src/superlocalmemory/core/registry.py +5 -1
- package/src/superlocalmemory/core/remote_mode.py +3 -1
- package/src/superlocalmemory/core/scale_engine.py +41 -18
- package/src/superlocalmemory/core/store_pipeline.py +18 -4
- package/src/superlocalmemory/encoding/entity_resolver.py +18 -11
- package/src/superlocalmemory/hooks/_outcome_common.py +9 -2
- package/src/superlocalmemory/hooks/adapter_base.py +58 -44
- package/src/superlocalmemory/hooks/ide_connector.py +26 -8
- package/src/superlocalmemory/hooks/portable_kit.py +105 -9
- package/src/superlocalmemory/hooks/prewarm_auth.py +21 -2
- package/src/superlocalmemory/infra/auth_middleware.py +3 -1
- package/src/superlocalmemory/infra/cloud_backup.py +26 -27
- package/src/superlocalmemory/infra/event_bus.py +250 -88
- package/src/superlocalmemory/learning/consolidation_cycle.py +33 -16
- package/src/superlocalmemory/learning/entity_compiler.py +148 -132
- package/src/superlocalmemory/learning/memory_merge.py +97 -82
- package/src/superlocalmemory/learning/reward_archive.py +98 -90
- package/src/superlocalmemory/learning/reward_boost.py +40 -30
- package/src/superlocalmemory/mcp/http_transport.py +335 -3
- package/src/superlocalmemory/retrieval/engine.py +7 -1
- package/src/superlocalmemory/retrieval/entity_channel.py +25 -1
- package/src/superlocalmemory/retrieval/reranker.py +98 -15
- package/src/superlocalmemory/retrieval/spreading_activation.py +20 -12
- package/src/superlocalmemory/retrieval/vector_store.py +84 -69
- package/src/superlocalmemory/server/loopback.py +91 -0
- package/src/superlocalmemory/server/origin.py +9 -4
- package/src/superlocalmemory/server/routes/backup.py +6 -2
- package/src/superlocalmemory/server/routes/behavioral.py +6 -12
- package/src/superlocalmemory/server/routes/compliance.py +20 -23
- package/src/superlocalmemory/server/routes/config_api.py +83 -0
- package/src/superlocalmemory/server/routes/helpers.py +24 -13
- package/src/superlocalmemory/server/routes/memories.py +67 -68
- package/src/superlocalmemory/server/routes/mesh.py +7 -2
- package/src/superlocalmemory/server/routes/profiles.py +20 -21
- package/src/superlocalmemory/server/routes/rbac.py +0 -1
- package/src/superlocalmemory/server/routes/tiers.py +42 -30
- package/src/superlocalmemory/server/routes/v3_api.py +67 -77
- package/src/superlocalmemory/server/unified_daemon.py +200 -31
- package/src/superlocalmemory/server/write_identity.py +22 -4
- package/src/superlocalmemory/storage/database.py +109 -19
- package/src/superlocalmemory/storage/deferred_writes.py +153 -0
- package/src/superlocalmemory/storage/embedding_migrator.py +19 -0
- package/src/superlocalmemory/storage/memory_write.py +119 -0
- package/src/superlocalmemory/storage/migration_runner.py +7 -0
- package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +113 -78
- package/src/superlocalmemory/storage/migrations/M031_dead_letter_operations.py +80 -0
- package/src/superlocalmemory/storage/write_lock.py +88 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com
|
|
4
|
+
|
|
5
|
+
"""Process-level per-path write-lock registry for memory.db.
|
|
6
|
+
|
|
7
|
+
ALL code that writes to a given SQLite file MUST acquire the lock returned
|
|
8
|
+
by ``get_write_lock(db_path)`` BEFORE opening a sqlite3 connection for
|
|
9
|
+
writing. This serialises writes at the Python layer so that only ONE
|
|
10
|
+
sqlite3 connection holds the SQLite WAL write lock at any instant, which
|
|
11
|
+
eliminates all SQLITE_BUSY retries within the process.
|
|
12
|
+
|
|
13
|
+
Invariant
|
|
14
|
+
---------
|
|
15
|
+
Every memory.db write path in the process acquires the same RLock before
|
|
16
|
+
touching sqlite3. Because SQLite WAL mode allows one writer at a time, a
|
|
17
|
+
Python-level RLock gives us the same serialisation guarantee while
|
|
18
|
+
completely avoiding the SQLITE_BUSY / busy_timeout retry loop.
|
|
19
|
+
|
|
20
|
+
Lock ordering rule (must never be violated)
|
|
21
|
+
-------------------------------------------
|
|
22
|
+
get_write_lock(memory.db) ← OUTERMOST
|
|
23
|
+
↳ VectorStore._lock (inner — VectorStore in-memory state)
|
|
24
|
+
↳ sqlite3 write transaction (BEGIN … COMMIT)
|
|
25
|
+
|
|
26
|
+
Re-entrancy
|
|
27
|
+
-----------
|
|
28
|
+
``threading.RLock`` is used so that the same thread can re-acquire the
|
|
29
|
+
lock without deadlocking. This is required by the self-heal backfill
|
|
30
|
+
pattern::
|
|
31
|
+
|
|
32
|
+
with db._lock: # db._lock IS get_write_lock(memory.db)
|
|
33
|
+
vs.upsert(...) # also calls get_write_lock → re-entrant OK
|
|
34
|
+
|
|
35
|
+
Usage
|
|
36
|
+
-----
|
|
37
|
+
from superlocalmemory.storage.write_lock import get_write_lock
|
|
38
|
+
|
|
39
|
+
with get_write_lock(db_path):
|
|
40
|
+
conn = sqlite3.connect(str(db_path))
|
|
41
|
+
conn.execute("INSERT INTO ...")
|
|
42
|
+
conn.commit()
|
|
43
|
+
conn.close()
|
|
44
|
+
"""
|
|
45
|
+
from __future__ import annotations
|
|
46
|
+
|
|
47
|
+
import threading
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
|
|
50
|
+
# Registry: resolved absolute path string → RLock.
|
|
51
|
+
# Protected by its own Lock so the registry itself is thread-safe.
|
|
52
|
+
_registry: dict[str, threading.RLock] = {}
|
|
53
|
+
_registry_lock = threading.Lock()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_write_lock(db_path: str | Path) -> threading.RLock:
|
|
57
|
+
"""Return the process-level write-serialisation RLock for *db_path*.
|
|
58
|
+
|
|
59
|
+
Resolves the path to its canonical absolute form before hashing so
|
|
60
|
+
that relative paths, ``.`` components, and symlinks all map to the
|
|
61
|
+
same lock as their resolved target. Creates a new ``RLock`` on first
|
|
62
|
+
call for each unique resolved path. Thread-safe.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
db_path:
|
|
67
|
+
Path to the SQLite database file. The file need not exist yet.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
threading.RLock
|
|
72
|
+
The shared write-serialisation lock for *db_path*. All writers
|
|
73
|
+
of this file in the current process share the same object.
|
|
74
|
+
"""
|
|
75
|
+
p = Path(db_path)
|
|
76
|
+
try:
|
|
77
|
+
key = str(p.resolve())
|
|
78
|
+
except OSError:
|
|
79
|
+
# File doesn't exist yet; use absolute path as best-effort key.
|
|
80
|
+
key = str(p.absolute())
|
|
81
|
+
|
|
82
|
+
with _registry_lock:
|
|
83
|
+
if key not in _registry:
|
|
84
|
+
_registry[key] = threading.RLock()
|
|
85
|
+
return _registry[key]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
__all__ = ["get_write_lock"]
|