superlocalmemory 3.8.3 → 3.8.6

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 (125) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +3 -2
  3. package/package.json +1 -1
  4. package/plugin/.claude-plugin/plugin.json +1 -1
  5. package/plugin/CLAUDE.md +3 -3
  6. package/plugin/agents/slm-governance-advisor.md +1 -1
  7. package/plugin/agents/slm-loop-runner.md +1 -1
  8. package/plugin/agents/slm-memory-advisor.md +1 -1
  9. package/plugin/agents/slm-optimize-advisor.md +1 -1
  10. package/plugin/requirements.txt +1 -1
  11. package/plugin/skills/slm-cache/SKILL.md +1 -1
  12. package/plugin/skills/slm-compress/SKILL.md +1 -1
  13. package/plugin/skills/slm-governance/SKILL.md +1 -1
  14. package/plugin/skills/slm-graph/SKILL.md +1 -1
  15. package/plugin/skills/slm-loop/SKILL.md +1 -1
  16. package/plugin/skills/slm-mesh/SKILL.md +1 -1
  17. package/plugin/skills/slm-profile/SKILL.md +1 -1
  18. package/plugin/skills/slm-recall/SKILL.md +1 -1
  19. package/plugin/skills/slm-remember/SKILL.md +1 -1
  20. package/plugin/skills/slm-scope/SKILL.md +1 -1
  21. package/plugin/skills/slm-session/SKILL.md +1 -1
  22. package/plugin/skills/slm-status/SKILL.md +1 -1
  23. package/plugin-src/rules/AGENTS.md +1 -1
  24. package/plugin-src/skills/slm-cache/SKILL.md +1 -1
  25. package/plugin-src/skills/slm-compress/SKILL.md +1 -1
  26. package/plugin-src/skills/slm-graph/SKILL.md +1 -1
  27. package/plugin-src/skills/slm-recall/SKILL.md +1 -1
  28. package/plugin-src/skills/slm-remember/SKILL.md +1 -1
  29. package/plugin-src/skills/slm-session/SKILL.md +1 -1
  30. package/plugin-src/skills/slm-status/SKILL.md +1 -1
  31. package/pyproject.toml +9 -4
  32. package/src/superlocalmemory/__init__.py +1 -1
  33. package/src/superlocalmemory/access/rbac.py +68 -76
  34. package/src/superlocalmemory/cli/commands.py +158 -404
  35. package/src/superlocalmemory/cli/ingest_cmd.py +11 -1
  36. package/src/superlocalmemory/cli/main.py +30 -0
  37. package/src/superlocalmemory/cli/pending_store.py +39 -14
  38. package/src/superlocalmemory/core/backend_orchestrator.py +93 -0
  39. package/src/superlocalmemory/core/component_registry.py +4 -2
  40. package/src/superlocalmemory/core/config.py +78 -0
  41. package/src/superlocalmemory/core/consolidation_engine.py +79 -73
  42. package/src/superlocalmemory/core/embeddings.py +33 -6
  43. package/src/superlocalmemory/core/engine.py +186 -60
  44. package/src/superlocalmemory/core/engine_ingestion.py +150 -63
  45. package/src/superlocalmemory/core/fact_consolidator.py +148 -30
  46. package/src/superlocalmemory/core/graph_pruner.py +436 -39
  47. package/src/superlocalmemory/core/ingestion_command.py +273 -32
  48. package/src/superlocalmemory/core/maintenance_scheduler.py +61 -1
  49. package/src/superlocalmemory/core/mutations.py +32 -10
  50. package/src/superlocalmemory/core/recall_pipeline.py +111 -74
  51. package/src/superlocalmemory/core/registry.py +5 -1
  52. package/src/superlocalmemory/core/remember_admission.py +152 -0
  53. package/src/superlocalmemory/core/remember_runtime.py +712 -0
  54. package/src/superlocalmemory/core/remote_mode.py +3 -1
  55. package/src/superlocalmemory/core/scale_engine.py +41 -18
  56. package/src/superlocalmemory/core/store_pipeline.py +18 -4
  57. package/src/superlocalmemory/encoding/entity_resolver.py +18 -11
  58. package/src/superlocalmemory/graph/cozo_backend.py +5 -5
  59. package/src/superlocalmemory/hooks/_outcome_common.py +9 -2
  60. package/src/superlocalmemory/hooks/adapter_base.py +58 -44
  61. package/src/superlocalmemory/hooks/ide_connector.py +26 -8
  62. package/src/superlocalmemory/hooks/portable_kit.py +105 -9
  63. package/src/superlocalmemory/hooks/prewarm_auth.py +21 -2
  64. package/src/superlocalmemory/infra/auth_middleware.py +3 -1
  65. package/src/superlocalmemory/infra/cloud_backup.py +26 -27
  66. package/src/superlocalmemory/infra/event_bus.py +250 -88
  67. package/src/superlocalmemory/learning/bandit.py +50 -1
  68. package/src/superlocalmemory/learning/consolidation_cycle.py +33 -16
  69. package/src/superlocalmemory/learning/entity_compiler.py +148 -132
  70. package/src/superlocalmemory/learning/memory_merge.py +97 -82
  71. package/src/superlocalmemory/learning/reward_archive.py +98 -90
  72. package/src/superlocalmemory/learning/reward_boost.py +40 -30
  73. package/src/superlocalmemory/learning/source_quality.py +38 -35
  74. package/src/superlocalmemory/mcp/_daemon_proxy.py +38 -15
  75. package/src/superlocalmemory/mcp/http_transport.py +335 -3
  76. package/src/superlocalmemory/mcp/tools_active.py +4 -41
  77. package/src/superlocalmemory/mcp/tools_core.py +26 -87
  78. package/src/superlocalmemory/mcp/tools_evolution.py +5 -10
  79. package/src/superlocalmemory/optimize/proxy/capture.py +196 -8
  80. package/src/superlocalmemory/retrieval/engine.py +15 -4
  81. package/src/superlocalmemory/retrieval/entity_channel.py +25 -1
  82. package/src/superlocalmemory/retrieval/reranker.py +130 -22
  83. package/src/superlocalmemory/retrieval/spreading_activation.py +20 -12
  84. package/src/superlocalmemory/retrieval/vector_store.py +84 -69
  85. package/src/superlocalmemory/server/loopback.py +85 -0
  86. package/src/superlocalmemory/server/origin.py +9 -4
  87. package/src/superlocalmemory/server/profile_runtime.py +14 -0
  88. package/src/superlocalmemory/server/routes/abstraction.py +2 -4
  89. package/src/superlocalmemory/server/routes/agents.py +3 -5
  90. package/src/superlocalmemory/server/routes/backup.py +6 -2
  91. package/src/superlocalmemory/server/routes/behavioral.py +11 -25
  92. package/src/superlocalmemory/server/routes/brain.py +6 -9
  93. package/src/superlocalmemory/server/routes/compliance.py +20 -23
  94. package/src/superlocalmemory/server/routes/config_api.py +83 -0
  95. package/src/superlocalmemory/server/routes/entity.py +3 -7
  96. package/src/superlocalmemory/server/routes/evolution.py +3 -5
  97. package/src/superlocalmemory/server/routes/helpers.py +57 -25
  98. package/src/superlocalmemory/server/routes/insights.py +2 -4
  99. package/src/superlocalmemory/server/routes/learning.py +2 -5
  100. package/src/superlocalmemory/server/routes/lifecycle.py +2 -4
  101. package/src/superlocalmemory/server/routes/memories.py +119 -98
  102. package/src/superlocalmemory/server/routes/mesh.py +7 -2
  103. package/src/superlocalmemory/server/routes/profiles.py +20 -21
  104. package/src/superlocalmemory/server/routes/rbac.py +0 -1
  105. package/src/superlocalmemory/server/routes/tiers.py +28 -35
  106. package/src/superlocalmemory/server/routes/timeline.py +2 -4
  107. package/src/superlocalmemory/server/routes/v3_api.py +85 -93
  108. package/src/superlocalmemory/server/unified_daemon.py +400 -140
  109. package/src/superlocalmemory/server/write_identity.py +22 -4
  110. package/src/superlocalmemory/storage/admission_codec.py +119 -0
  111. package/src/superlocalmemory/storage/admission_journal.py +728 -0
  112. package/src/superlocalmemory/storage/database.py +168 -19
  113. package/src/superlocalmemory/storage/deferred_writes.py +209 -0
  114. package/src/superlocalmemory/storage/embedding_migrator.py +19 -0
  115. package/src/superlocalmemory/storage/memory_write.py +115 -0
  116. package/src/superlocalmemory/storage/migration_runner.py +44 -0
  117. package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +113 -78
  118. package/src/superlocalmemory/storage/migrations/M031_dead_letter_operations.py +80 -0
  119. package/src/superlocalmemory/storage/migrations/M032_write_coordinator_admission.py +188 -0
  120. package/src/superlocalmemory/storage/read_connection.py +115 -0
  121. package/src/superlocalmemory/storage/write_coordinator.py +756 -0
  122. package/src/superlocalmemory/storage/write_lock.py +88 -0
  123. package/src/superlocalmemory/ui/index.html +1 -1
  124. package/src/superlocalmemory/ui/js/auto-settings.js +14 -1
  125. package/src/superlocalmemory/ui/js/od-settings.js +9 -3
@@ -0,0 +1,115 @@
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
+ """Physically read-only SQLite snapshots for canonical ``memory.db``.
6
+
7
+ The factory is deliberately small: a query path must receive a connection
8
+ which SQLite itself refuses to mutate. This is the storage half of the
9
+ Command-Query Separation contract; higher layers must not use it to perform
10
+ telemetry, access tracking, or any other side effect.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import sqlite3
15
+ from contextlib import AbstractContextManager, contextmanager
16
+ from pathlib import Path
17
+ from typing import Iterator
18
+
19
+
20
+ class ReadConnectionError(RuntimeError):
21
+ """Raised when a read snapshot cannot be opened safely."""
22
+
23
+
24
+ class ReadConnectionFactory:
25
+ """Open short-lived query-only snapshots of one canonical database path."""
26
+
27
+ def __init__(self, memory_db: str | Path, timeout_ms: int = 250) -> None:
28
+ if timeout_ms < 0:
29
+ raise ValueError("timeout_ms must be greater than or equal to zero")
30
+ self._memory_db = Path(memory_db).expanduser().resolve()
31
+ self._timeout_ms = timeout_ms
32
+
33
+ @property
34
+ def memory_db(self) -> Path:
35
+ """Return the resolved canonical database path."""
36
+ return self._memory_db
37
+
38
+ @contextmanager
39
+ def snapshot(self) -> Iterator[sqlite3.Connection]:
40
+ """Yield a SQLite connection that cannot issue a write statement.
41
+
42
+ ``immutable=1`` is intentionally not used: a live WAL database may
43
+ have valid state in its WAL file. ``mode=ro`` retains normal WAL
44
+ visibility while prohibiting a writable open, and ``query_only`` is a
45
+ second SQLite-enforced guard against accidental DML or DDL.
46
+ """
47
+ if not self._memory_db.exists():
48
+ raise ReadConnectionError(f"canonical database does not exist: {self._memory_db}")
49
+
50
+ uri = f"{self._memory_db.as_uri()}?mode=ro"
51
+ try:
52
+ conn = sqlite3.connect(
53
+ uri,
54
+ uri=True,
55
+ timeout=self._timeout_ms / 1000.0,
56
+ )
57
+ except sqlite3.Error as exc:
58
+ raise ReadConnectionError(
59
+ f"could not open read-only snapshot for {self._memory_db}"
60
+ ) from exc
61
+
62
+ try:
63
+ conn.row_factory = sqlite3.Row
64
+ conn.execute("PRAGMA query_only=ON")
65
+ conn.execute("PRAGMA foreign_keys=ON")
66
+ conn.execute(f"PRAGMA busy_timeout={self._timeout_ms}")
67
+ yield conn
68
+ finally:
69
+ conn.close()
70
+
71
+ def open(self) -> "ReadConnectionLease":
72
+ """Return a manually-closeable read-only lease for legacy query code.
73
+
74
+ New code should use :meth:`snapshot`; the lease is a small compatibility
75
+ bridge for client paths that still use ``try/finally: conn.close()``.
76
+ Closing it exits this same context manager, preserving both ``mode=ro``
77
+ and ``PRAGMA query_only`` rather than reopening SQLite directly.
78
+ """
79
+ return ReadConnectionLease(self.snapshot())
80
+
81
+
82
+ class ReadConnectionLease:
83
+ """A legacy-compatible facade around one read-only snapshot."""
84
+
85
+ def __init__(self, snapshot: AbstractContextManager[sqlite3.Connection]) -> None:
86
+ object.__setattr__(self, "_snapshot", snapshot)
87
+ object.__setattr__(self, "_connection", snapshot.__enter__())
88
+ object.__setattr__(self, "_closed", False)
89
+
90
+ def __getattr__(self, name: str):
91
+ return getattr(self._connection, name)
92
+
93
+ def __setattr__(self, name: str, value: object) -> None:
94
+ if name.startswith("_"):
95
+ object.__setattr__(self, name, value)
96
+ else:
97
+ setattr(self._connection, name, value)
98
+
99
+ def __enter__(self) -> sqlite3.Connection:
100
+ return self._connection
101
+
102
+ def __exit__(self, exc_type, exc, traceback) -> None:
103
+ self._close(exc_type, exc, traceback)
104
+
105
+ def close(self) -> None:
106
+ """Close this lease once, including its context-manager cleanup."""
107
+ self._close(None, None, None)
108
+
109
+ def _close(self, exc_type, exc, traceback) -> None:
110
+ if not self._closed:
111
+ object.__setattr__(self, "_closed", True)
112
+ self._snapshot.__exit__(exc_type, exc, traceback)
113
+
114
+
115
+ __all__ = ["ReadConnectionError", "ReadConnectionFactory", "ReadConnectionLease"]