superlocalmemory 3.4.19 → 3.4.22
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 +24 -0
- package/README.md +42 -34
- package/bin/slm +11 -0
- package/bin/slm.bat +12 -0
- package/package.json +4 -3
- package/pyproject.toml +4 -3
- package/scripts/build-slm-hook.ps1 +40 -0
- package/scripts/build-slm-hook.sh +45 -0
- package/scripts/build_entry.py +452 -0
- package/scripts/ci/stage5b_gate.sh +50 -0
- package/scripts/postinstall/validation.js +187 -0
- package/scripts/postinstall-interactive.js +756 -0
- package/scripts/postinstall_binary.js +287 -0
- package/scripts/release_manifest.py +273 -0
- package/scripts/slm-hook.spec +56 -0
- package/skills/slm-build-graph/SKILL.md +423 -0
- package/skills/slm-list-recent/SKILL.md +348 -0
- package/skills/slm-recall/SKILL.md +343 -0
- package/skills/slm-remember/SKILL.md +194 -0
- package/skills/slm-show-patterns/SKILL.md +224 -0
- package/skills/slm-status/SKILL.md +363 -0
- package/skills/slm-switch-profile/SKILL.md +442 -0
- package/src/superlocalmemory/cli/commands.py +254 -79
- package/src/superlocalmemory/cli/context_commands.py +192 -0
- package/src/superlocalmemory/cli/daemon.py +15 -1
- package/src/superlocalmemory/cli/db_migrate.py +80 -0
- package/src/superlocalmemory/cli/escape_hatch.py +220 -0
- package/src/superlocalmemory/cli/main.py +72 -1
- package/src/superlocalmemory/core/context_cache.py +397 -0
- package/src/superlocalmemory/core/engine.py +38 -2
- package/src/superlocalmemory/core/engine_wiring.py +1 -1
- package/src/superlocalmemory/core/ram_lock.py +111 -0
- package/src/superlocalmemory/core/recall_pipeline.py +433 -3
- package/src/superlocalmemory/core/recall_worker.py +8 -3
- package/src/superlocalmemory/core/security_primitives.py +635 -0
- package/src/superlocalmemory/core/shadow_router.py +319 -0
- package/src/superlocalmemory/core/slm_disabled.py +87 -0
- package/src/superlocalmemory/core/slmignore.py +125 -0
- package/src/superlocalmemory/core/topic_signature.py +143 -0
- package/src/superlocalmemory/core/worker_pool.py +14 -3
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +2 -2
- package/src/superlocalmemory/evolution/budget.py +321 -0
- package/src/superlocalmemory/evolution/llm_dispatch.py +508 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +144 -94
- package/src/superlocalmemory/hooks/_outcome_common.py +506 -0
- package/src/superlocalmemory/hooks/adapter_base.py +317 -0
- package/src/superlocalmemory/hooks/antigravity_adapter.py +192 -0
- package/src/superlocalmemory/hooks/claude_code_hooks.py +33 -1
- package/src/superlocalmemory/hooks/context_payload.py +312 -0
- package/src/superlocalmemory/hooks/copilot_adapter.py +154 -0
- package/src/superlocalmemory/hooks/cross_platform_connector.py +90 -0
- package/src/superlocalmemory/hooks/cursor_adapter.py +195 -0
- package/src/superlocalmemory/hooks/hook_handlers.py +109 -8
- package/src/superlocalmemory/hooks/ide_connector.py +25 -2
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +165 -0
- package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +223 -0
- package/src/superlocalmemory/hooks/prewarm_auth.py +170 -0
- package/src/superlocalmemory/hooks/session_registry.py +186 -0
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +134 -0
- package/src/superlocalmemory/hooks/sync_loop.py +114 -0
- package/src/superlocalmemory/hooks/user_prompt_hook.py +128 -0
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +202 -0
- package/src/superlocalmemory/infra/backup.py +3 -3
- package/src/superlocalmemory/infra/cloud_backup.py +2 -2
- package/src/superlocalmemory/infra/event_bus.py +2 -2
- package/src/superlocalmemory/infra/webhook_dispatcher.py +3 -3
- package/src/superlocalmemory/learning/arm_catalog.py +99 -0
- package/src/superlocalmemory/learning/bandit.py +526 -0
- package/src/superlocalmemory/learning/bandit_cache.py +133 -0
- package/src/superlocalmemory/learning/behavioral.py +53 -1
- package/src/superlocalmemory/learning/consolidation_cycle.py +381 -0
- package/src/superlocalmemory/learning/consolidation_worker.py +188 -520
- package/src/superlocalmemory/learning/database.py +256 -0
- package/src/superlocalmemory/learning/dedup_hnsw.py +413 -0
- package/src/superlocalmemory/learning/ensemble.py +300 -0
- package/src/superlocalmemory/learning/fact_outcome_joins.py +207 -0
- package/src/superlocalmemory/learning/forgetting_scheduler.py +55 -0
- package/src/superlocalmemory/learning/hnsw_dedup.py +69 -0
- package/src/superlocalmemory/learning/labeler.py +87 -0
- package/src/superlocalmemory/learning/legacy_migration.py +277 -0
- package/src/superlocalmemory/learning/memory_merge.py +160 -0
- package/src/superlocalmemory/learning/model_cache.py +269 -0
- package/src/superlocalmemory/learning/model_rollback.py +278 -0
- package/src/superlocalmemory/learning/outcome_queue.py +284 -0
- package/src/superlocalmemory/learning/pattern_miner.py +415 -0
- package/src/superlocalmemory/learning/pattern_miner_constants.py +47 -0
- package/src/superlocalmemory/learning/ranker.py +225 -81
- package/src/superlocalmemory/learning/ranker_common.py +163 -0
- package/src/superlocalmemory/learning/ranker_retrain_legacy.py +202 -0
- package/src/superlocalmemory/learning/ranker_retrain_online.py +411 -0
- package/src/superlocalmemory/learning/reward.py +777 -0
- package/src/superlocalmemory/learning/reward_archive.py +210 -0
- package/src/superlocalmemory/learning/reward_boost.py +201 -0
- package/src/superlocalmemory/learning/reward_proxy.py +326 -0
- package/src/superlocalmemory/learning/shadow_test.py +524 -0
- package/src/superlocalmemory/learning/signal_worker.py +270 -0
- package/src/superlocalmemory/learning/signals.py +314 -0
- package/src/superlocalmemory/learning/trigram_index.py +547 -0
- package/src/superlocalmemory/mcp/server.py +5 -5
- package/src/superlocalmemory/mcp/tools_context.py +183 -0
- package/src/superlocalmemory/mcp/tools_core.py +92 -27
- package/src/superlocalmemory/parameterization/soft_prompt_generator.py +13 -0
- package/src/superlocalmemory/retrieval/engine.py +52 -0
- package/src/superlocalmemory/server/api.py +2 -2
- package/src/superlocalmemory/server/bandit_loops.py +140 -0
- package/src/superlocalmemory/server/middleware/__init__.py +11 -0
- package/src/superlocalmemory/server/middleware/security_headers.py +144 -0
- package/src/superlocalmemory/server/routes/backup.py +36 -13
- package/src/superlocalmemory/server/routes/behavioral.py +50 -19
- package/src/superlocalmemory/server/routes/brain.py +1234 -0
- package/src/superlocalmemory/server/routes/data_io.py +4 -4
- package/src/superlocalmemory/server/routes/events.py +2 -2
- package/src/superlocalmemory/server/routes/helpers.py +1 -1
- package/src/superlocalmemory/server/routes/learning.py +192 -7
- package/src/superlocalmemory/server/routes/memories.py +189 -1
- package/src/superlocalmemory/server/routes/prewarm.py +171 -0
- package/src/superlocalmemory/server/routes/profiles.py +3 -3
- package/src/superlocalmemory/server/routes/token.py +88 -0
- package/src/superlocalmemory/server/routes/ws.py +5 -5
- package/src/superlocalmemory/server/security_middleware.py +13 -7
- package/src/superlocalmemory/server/ui.py +2 -2
- package/src/superlocalmemory/server/unified_daemon.py +335 -3
- package/src/superlocalmemory/skills/slm-build-graph/SKILL.md +423 -0
- package/src/superlocalmemory/skills/slm-list-recent/SKILL.md +348 -0
- package/src/superlocalmemory/skills/slm-recall/SKILL.md +343 -0
- package/src/superlocalmemory/skills/slm-remember/SKILL.md +194 -0
- package/src/superlocalmemory/skills/slm-show-patterns/SKILL.md +224 -0
- package/src/superlocalmemory/skills/slm-status/SKILL.md +363 -0
- package/src/superlocalmemory/skills/slm-switch-profile/SKILL.md +442 -0
- package/src/superlocalmemory/storage/migration_runner.py +545 -0
- package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +67 -0
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +132 -0
- package/src/superlocalmemory/storage/migrations/M003_migration_log.py +38 -0
- package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +46 -0
- package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +75 -0
- package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +75 -0
- package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +63 -0
- package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +54 -0
- package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +75 -0
- package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +87 -0
- package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +72 -0
- package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +55 -0
- package/src/superlocalmemory/storage/migrations/__init__.py +81 -0
- package/src/superlocalmemory/storage/models.py +4 -0
- package/src/superlocalmemory/ui/css/brain.css +409 -0
- package/src/superlocalmemory/ui/css/legacy-dashboard.css +645 -0
- package/src/superlocalmemory/ui/index.html +459 -1345
- package/src/superlocalmemory/ui/js/brain.js +1321 -0
- package/src/superlocalmemory/ui/js/clusters.js +123 -4
- package/src/superlocalmemory/ui/js/init.js +48 -39
- package/src/superlocalmemory/ui/js/memories.js +88 -2
- package/src/superlocalmemory/ui/js/modal.js +71 -1
- package/src/superlocalmemory/ui/js/ng-shell.js +101 -88
- package/src/superlocalmemory/ui/js/trust-dashboard.js +168 -25
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +2018 -0
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +7 -0
- package/src/superlocalmemory/ui/vendor/bootstrap.min.css +6 -0
- package/src/superlocalmemory/ui/vendor/d3.v7.min.js +2 -0
- package/src/superlocalmemory/ui/vendor/graphology-library.min.js +2 -0
- package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +2 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +8 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/sigma.min.js +1 -0
- package/src/superlocalmemory/ui/js/behavioral.js +0 -447
- package/src/superlocalmemory/ui/js/graph-core.js +0 -447
- package/src/superlocalmemory/ui/js/graph-interactions.js +0 -351
- package/src/superlocalmemory/ui/js/learning.js +0 -435
- package/src/superlocalmemory/ui/js/patterns.js +0 -93
- package/src/superlocalmemory.egg-info/PKG-INFO +0 -647
- package/src/superlocalmemory.egg-info/SOURCES.txt +0 -335
- package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
- package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
- package/src/superlocalmemory.egg-info/requires.txt +0 -58
- package/src/superlocalmemory.egg-info/top_level.txt +0 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory v3.4.22 — LLD-06 §7.2
|
|
4
|
+
|
|
5
|
+
"""CLI handler for ``slm db migrate``.
|
|
6
|
+
|
|
7
|
+
LLD reference: ``.backup/active-brain/lld/LLD-06-windows-binary-and-legacy-migration.md``
|
|
8
|
+
Section 7.2 (slm db migrate CLI).
|
|
9
|
+
|
|
10
|
+
Thin wrapper over the canonical runner in
|
|
11
|
+
``superlocalmemory.storage.migration_runner``. This module owns only
|
|
12
|
+
the user-facing surface (stdout formatting + exit codes). All DDL +
|
|
13
|
+
runner logic lives in LLD-07 territory — per H15, no migration schema
|
|
14
|
+
is defined or duplicated here.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from argparse import Namespace
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Canonical paths — match LLD-01 / LLD-07 layout. Callers can override
|
|
23
|
+
# via the ``learning_db_path`` / ``memory_db_path`` attributes on args
|
|
24
|
+
# (tests rely on this to point at fixture DBs).
|
|
25
|
+
DEFAULT_HOME = Path.home() / ".superlocalmemory"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _resolve_paths(args: Namespace) -> tuple[Path, Path]:
|
|
29
|
+
learning = getattr(args, "learning_db_path", None)
|
|
30
|
+
memory = getattr(args, "memory_db_path", None)
|
|
31
|
+
if learning is None:
|
|
32
|
+
learning = DEFAULT_HOME / "learning.db"
|
|
33
|
+
if memory is None:
|
|
34
|
+
memory = DEFAULT_HOME / "memory.db"
|
|
35
|
+
return Path(learning), Path(memory)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def cmd_db_migrate(args: Namespace) -> int:
|
|
39
|
+
"""Apply pending migrations or report status.
|
|
40
|
+
|
|
41
|
+
Behaviour:
|
|
42
|
+
- ``--status`` prints the per-migration status recorded in each
|
|
43
|
+
DB's ``migration_log``. Exit 0 unless reading fails.
|
|
44
|
+
- ``--dry-run`` runs the runner in dry-run mode (no writes).
|
|
45
|
+
- Default: runs ``apply_all``.
|
|
46
|
+
|
|
47
|
+
Exit codes (also returned for tests that capture return value):
|
|
48
|
+
- 0 on success (no failed migrations).
|
|
49
|
+
- 1 if any migration is reported as ``failed``.
|
|
50
|
+
"""
|
|
51
|
+
from superlocalmemory.storage.migration_runner import apply_all, status
|
|
52
|
+
|
|
53
|
+
learning_db, memory_db = _resolve_paths(args)
|
|
54
|
+
|
|
55
|
+
if getattr(args, "status", False):
|
|
56
|
+
report = status(learning_db, memory_db)
|
|
57
|
+
if not report:
|
|
58
|
+
print("(no migrations registered)")
|
|
59
|
+
else:
|
|
60
|
+
for name, state in report.items():
|
|
61
|
+
print(f" {name}: {state}")
|
|
62
|
+
return 0
|
|
63
|
+
|
|
64
|
+
dry_run = bool(getattr(args, "dry_run", False))
|
|
65
|
+
result = apply_all(learning_db, memory_db, dry_run=dry_run)
|
|
66
|
+
applied = result.get("applied", [])
|
|
67
|
+
skipped = result.get("skipped", [])
|
|
68
|
+
failed = result.get("failed", [])
|
|
69
|
+
print(
|
|
70
|
+
f"Applied={len(applied)} Skipped={len(skipped)} Failed={len(failed)}"
|
|
71
|
+
)
|
|
72
|
+
if failed:
|
|
73
|
+
details = result.get("details", {})
|
|
74
|
+
for name in failed:
|
|
75
|
+
print(f" FAILED {name}: {details.get(name, '(no detail)')}")
|
|
76
|
+
return 1
|
|
77
|
+
return 0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
__all__ = ("cmd_db_migrate", "DEFAULT_HOME")
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory v3.4.22 — Stage 8 SB-5
|
|
4
|
+
|
|
5
|
+
"""CLI escape-hatch commands.
|
|
6
|
+
|
|
7
|
+
Implements the user-facing kill switches and reset commands promised
|
|
8
|
+
by MASTER-PLAN §8 that were previously advertised but missing:
|
|
9
|
+
|
|
10
|
+
- ``slm disable`` — write ``~/.superlocalmemory/.disabled`` marker
|
|
11
|
+
and stop the daemon. Hooks and MCP tools no-op until re-enabled.
|
|
12
|
+
- ``slm enable`` — remove the marker; prompt user to start daemon.
|
|
13
|
+
- ``slm clear-cache`` — wipe cache-only databases (preserves memory.db
|
|
14
|
+
— user memories are NEVER deleted here).
|
|
15
|
+
- ``slm reconfigure`` — invoke the interactive postinstall with the
|
|
16
|
+
``--reconfigure`` flag so users can change profile/knobs safely.
|
|
17
|
+
- ``slm benchmark`` — run the evo-memory benchmark harness against
|
|
18
|
+
an isolated tmp DB (never touches ``~/.superlocalmemory``).
|
|
19
|
+
|
|
20
|
+
All handlers are stdlib-only at the command boundary; import heavier
|
|
21
|
+
modules lazily inside each function so CLI help stays snappy.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import os
|
|
27
|
+
import shutil
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
from argparse import Namespace
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def cmd_disable(args: Namespace) -> None:
|
|
35
|
+
"""Write the ``.disabled`` marker and stop the daemon."""
|
|
36
|
+
from superlocalmemory.core.slm_disabled import write_marker, is_disabled
|
|
37
|
+
|
|
38
|
+
reason = getattr(args, "reason", "") or ""
|
|
39
|
+
marker = write_marker(reason)
|
|
40
|
+
print(f"SLM disabled. Marker: {marker}")
|
|
41
|
+
|
|
42
|
+
# Best-effort daemon stop — non-fatal.
|
|
43
|
+
try:
|
|
44
|
+
from superlocalmemory.cli.daemon import stop_daemon
|
|
45
|
+
if stop_daemon():
|
|
46
|
+
print("Daemon stopped.")
|
|
47
|
+
except Exception as exc: # pragma: no cover — defensive
|
|
48
|
+
print(f"(daemon stop skipped: {exc})", file=sys.stderr)
|
|
49
|
+
|
|
50
|
+
# Sanity check
|
|
51
|
+
if not is_disabled(): # pragma: no cover
|
|
52
|
+
print("warning: disable marker wrote but is_disabled() returned False",
|
|
53
|
+
file=sys.stderr)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def cmd_enable(args: Namespace) -> None:
|
|
57
|
+
"""Remove the ``.disabled`` marker. Daemon is NOT auto-started —
|
|
58
|
+
print the one-liner so the user can start it when ready."""
|
|
59
|
+
from superlocalmemory.core.slm_disabled import remove_marker, marker_path
|
|
60
|
+
|
|
61
|
+
removed = remove_marker()
|
|
62
|
+
if removed:
|
|
63
|
+
print("SLM enabled. To start the daemon: slm serve start")
|
|
64
|
+
else:
|
|
65
|
+
print(f"SLM was already enabled (no marker at {marker_path()}).")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
_CACHE_DBS = (
|
|
69
|
+
"active_brain_cache.db",
|
|
70
|
+
"context_cache.db",
|
|
71
|
+
"entity_trigram_cache.db",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def cmd_clear_cache(args: Namespace) -> None:
|
|
76
|
+
"""Delete cache-only DBs. Preserves ``memory.db`` and ``learning.db``.
|
|
77
|
+
|
|
78
|
+
This is an explicitly non-destructive command — user memories live
|
|
79
|
+
in ``memory.db`` which is NEVER touched here. Only regenerable
|
|
80
|
+
caches are wiped so SLM can rebuild them on next daemon start.
|
|
81
|
+
"""
|
|
82
|
+
from superlocalmemory.core.slm_disabled import _slm_home
|
|
83
|
+
|
|
84
|
+
home = _slm_home()
|
|
85
|
+
removed: list[str] = []
|
|
86
|
+
missing: list[str] = []
|
|
87
|
+
protected = {"memory.db", "learning.db", "audit.db", "audit_chain.db",
|
|
88
|
+
"pending.db"}
|
|
89
|
+
for name in _CACHE_DBS:
|
|
90
|
+
if name in protected: # pragma: no cover — defensive belt
|
|
91
|
+
continue
|
|
92
|
+
path = home / name
|
|
93
|
+
try:
|
|
94
|
+
path.unlink()
|
|
95
|
+
removed.append(name)
|
|
96
|
+
except FileNotFoundError:
|
|
97
|
+
missing.append(name)
|
|
98
|
+
except OSError as exc:
|
|
99
|
+
print(f" skip {name}: {exc}", file=sys.stderr)
|
|
100
|
+
|
|
101
|
+
if removed:
|
|
102
|
+
print("Removed cache DBs:")
|
|
103
|
+
for name in removed:
|
|
104
|
+
print(f" - {name}")
|
|
105
|
+
else:
|
|
106
|
+
print("No cache DBs present — nothing to do.")
|
|
107
|
+
print("memory.db / learning.db preserved (user memories are never "
|
|
108
|
+
"touched by clear-cache).")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def cmd_reconfigure(args: Namespace) -> None:
|
|
112
|
+
"""Re-run the interactive postinstall with ``--reconfigure``.
|
|
113
|
+
|
|
114
|
+
Backs up the existing ``config.toml`` to ``config.toml.bak`` before
|
|
115
|
+
writing the new one.
|
|
116
|
+
"""
|
|
117
|
+
script = _find_postinstall_script()
|
|
118
|
+
if script is None:
|
|
119
|
+
print("postinstall-interactive.js not found; reinstall the npm "
|
|
120
|
+
"package to run this command.", file=sys.stderr)
|
|
121
|
+
sys.exit(2)
|
|
122
|
+
|
|
123
|
+
cmd = ["node", str(script), "--reconfigure"]
|
|
124
|
+
# Pass through any extra CLI flags untouched.
|
|
125
|
+
extras = getattr(args, "extras", None) or []
|
|
126
|
+
cmd.extend(extras)
|
|
127
|
+
result = subprocess.run(cmd, check=False)
|
|
128
|
+
sys.exit(result.returncode)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _find_postinstall_script() -> Path | None:
|
|
132
|
+
"""Locate ``scripts/postinstall-interactive.js`` next to the package."""
|
|
133
|
+
# 1. Walk up from this file.
|
|
134
|
+
here = Path(__file__).resolve()
|
|
135
|
+
for parent in here.parents:
|
|
136
|
+
candidate = parent / "scripts" / "postinstall-interactive.js"
|
|
137
|
+
if candidate.is_file():
|
|
138
|
+
return candidate
|
|
139
|
+
# 2. npm global-install layout — sibling of the bin dir.
|
|
140
|
+
bin_path = shutil.which("slm")
|
|
141
|
+
if bin_path:
|
|
142
|
+
bin_dir = Path(bin_path).resolve().parent
|
|
143
|
+
candidate = bin_dir.parent / "lib" / "node_modules" / \
|
|
144
|
+
"superlocalmemory" / "scripts" / "postinstall-interactive.js"
|
|
145
|
+
if candidate.is_file():
|
|
146
|
+
return candidate
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def cmd_benchmark(args: Namespace) -> None:
|
|
151
|
+
"""Run the evo-memory benchmark harness against an isolated tmp DB.
|
|
152
|
+
|
|
153
|
+
The benchmark refuses to touch the user's ``~/.superlocalmemory`` —
|
|
154
|
+
it spins up its own tmp_path DB, runs day-0 → day-30 simulation,
|
|
155
|
+
prints MRR / Recall / lift tiers, and exits. CI-safe.
|
|
156
|
+
"""
|
|
157
|
+
# Import locally — keeps the CLI top-level light.
|
|
158
|
+
try:
|
|
159
|
+
# The harness lives in the test tree so we add it to sys.path lazily.
|
|
160
|
+
repo_root = Path(__file__).resolve().parents[3]
|
|
161
|
+
tests_dir = repo_root / "tests" / "test_benchmarks"
|
|
162
|
+
if tests_dir.is_dir() and str(tests_dir) not in sys.path:
|
|
163
|
+
sys.path.insert(0, str(tests_dir))
|
|
164
|
+
from evo_memory import EvoMemoryBenchmark # type: ignore
|
|
165
|
+
except ImportError as exc:
|
|
166
|
+
print(f"evo-memory harness not available in this install "
|
|
167
|
+
f"(bench fixture excluded from binary wheels): {exc}",
|
|
168
|
+
file=sys.stderr)
|
|
169
|
+
sys.exit(2)
|
|
170
|
+
|
|
171
|
+
import json
|
|
172
|
+
import tempfile
|
|
173
|
+
as_json = bool(getattr(args, "json", False))
|
|
174
|
+
|
|
175
|
+
with tempfile.TemporaryDirectory(prefix="slm-bench-") as d:
|
|
176
|
+
bench = EvoMemoryBenchmark(profile_id="bench_v1", data_dir=Path(d))
|
|
177
|
+
result = bench.run_full_30_day_simulation()
|
|
178
|
+
|
|
179
|
+
if as_json:
|
|
180
|
+
print(json.dumps(result, default=str))
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
print("== Evo-Memory Benchmark ==")
|
|
184
|
+
print(f"fixture: {result.get('fixture_version', 'v1')}")
|
|
185
|
+
print(f"wall_seconds: {result.get('wall_seconds'):.2f}")
|
|
186
|
+
cmp = result.get("comparison", {})
|
|
187
|
+
print(f"day_1 MRR@10: {cmp.get('day_1_mrr', 0):.4f}")
|
|
188
|
+
print(f"day_30 MRR@10: {cmp.get('day_n_mrr', 0):.4f}")
|
|
189
|
+
print(f"lift: {cmp.get('mrr_lift_pct', 0):.2f}% "
|
|
190
|
+
f"(gate: {'STABLE' if cmp.get('passes_10pct_gate') else 'DRAFT'})")
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def cmd_rotate_token(args: Namespace) -> None:
|
|
194
|
+
"""S-M07: rotate the install token.
|
|
195
|
+
|
|
196
|
+
Prints the new token's last-4 suffix for operator audit + a line
|
|
197
|
+
reminding the user to restart the daemon so HMAC marker caches
|
|
198
|
+
converge on the new token.
|
|
199
|
+
"""
|
|
200
|
+
from superlocalmemory.core.security_primitives import rotate_install_token
|
|
201
|
+
old, new = rotate_install_token()
|
|
202
|
+
if not new:
|
|
203
|
+
print("install-token rotation failed (check permissions on "
|
|
204
|
+
"~/.superlocalmemory/.install_token)")
|
|
205
|
+
return
|
|
206
|
+
old_tail = old[-4:] if old else "(absent)"
|
|
207
|
+
new_tail = new[-4:]
|
|
208
|
+
print(f"install-token rotated: ...{old_tail} -> ...{new_tail}")
|
|
209
|
+
print("NOTE: restart the daemon so HMAC marker caches pick up "
|
|
210
|
+
"the new token (run: slm restart).")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
__all__ = (
|
|
214
|
+
"cmd_disable",
|
|
215
|
+
"cmd_enable",
|
|
216
|
+
"cmd_clear_cache",
|
|
217
|
+
"cmd_reconfigure",
|
|
218
|
+
"cmd_benchmark",
|
|
219
|
+
"cmd_rotate_token",
|
|
220
|
+
)
|
|
@@ -129,6 +129,22 @@ def main() -> None:
|
|
|
129
129
|
"--rollback", action="store_true", help="Rollback migration",
|
|
130
130
|
)
|
|
131
131
|
|
|
132
|
+
# LLD-06 §7.2 — `slm db migrate` wraps LLD-07's additive schema migrations.
|
|
133
|
+
db_p = sub.add_parser("db", help="Database maintenance commands (v3.4.22)")
|
|
134
|
+
db_sub = db_p.add_subparsers(dest="db_command", title="db subcommands")
|
|
135
|
+
db_mig_p = db_sub.add_parser(
|
|
136
|
+
"migrate",
|
|
137
|
+
help="Apply additive schema migrations (LLD-07)",
|
|
138
|
+
)
|
|
139
|
+
db_mig_p.add_argument(
|
|
140
|
+
"--status", action="store_true",
|
|
141
|
+
help="Print migration status from migration_log; no writes",
|
|
142
|
+
)
|
|
143
|
+
db_mig_p.add_argument(
|
|
144
|
+
"--dry-run", action="store_true",
|
|
145
|
+
help="Report what would change without applying",
|
|
146
|
+
)
|
|
147
|
+
|
|
132
148
|
# -- Memory Operations ---------------------------------------------
|
|
133
149
|
remember_p = sub.add_parser("remember", help="Store a memory (extracts facts, builds graph)")
|
|
134
150
|
remember_p.add_argument("content", help="Content to remember")
|
|
@@ -169,6 +185,10 @@ def main() -> None:
|
|
|
169
185
|
# -- Diagnostics ---------------------------------------------------
|
|
170
186
|
status_p = sub.add_parser("status", help="System status (mode, profile, DB size)")
|
|
171
187
|
status_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
|
|
188
|
+
status_p.add_argument(
|
|
189
|
+
"--verbose", "-v", action="store_true",
|
|
190
|
+
help="Show extended status: migration log, daemon port, disabled marker, last version",
|
|
191
|
+
)
|
|
172
192
|
|
|
173
193
|
health_p = sub.add_parser("health", help="Math layer health (Fisher-Rao, Sheaf, Langevin)")
|
|
174
194
|
health_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
|
|
@@ -181,6 +201,10 @@ def main() -> None:
|
|
|
181
201
|
# -- Diagnostics (continued) ----------------------------------------
|
|
182
202
|
doctor_p = sub.add_parser("doctor", help="Pre-flight check: deps, embedding worker, connectivity")
|
|
183
203
|
doctor_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
|
|
204
|
+
doctor_p.add_argument(
|
|
205
|
+
"--quick", action="store_true",
|
|
206
|
+
help="Run only the fast checks (deps + config); skip daemon/embedding probes",
|
|
207
|
+
)
|
|
184
208
|
|
|
185
209
|
# -- Services ------------------------------------------------------
|
|
186
210
|
sub.add_parser("mcp", help="Start MCP server (stdio transport for IDE integration)")
|
|
@@ -333,6 +357,50 @@ def main() -> None:
|
|
|
333
357
|
evolve_p.add_argument("--session", default="", help="Session ID to process")
|
|
334
358
|
evolve_p.add_argument("--profile", default="default", help="Profile ID")
|
|
335
359
|
|
|
360
|
+
# v3.4.22 — MASTER-PLAN §8 escape hatches (Stage 8 SB-5).
|
|
361
|
+
disable_p = sub.add_parser(
|
|
362
|
+
"disable",
|
|
363
|
+
help="Disable SLM globally (writes ~/.superlocalmemory/.disabled, stops daemon)",
|
|
364
|
+
)
|
|
365
|
+
disable_p.add_argument(
|
|
366
|
+
"--reason", default="",
|
|
367
|
+
help="Optional reason string written into the marker for audit",
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
sub.add_parser(
|
|
371
|
+
"enable",
|
|
372
|
+
help="Remove the .disabled marker; print command to start daemon",
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
sub.add_parser(
|
|
376
|
+
"clear-cache",
|
|
377
|
+
help="Wipe regenerable caches (memory.db + learning.db are preserved)",
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
recon_p = sub.add_parser(
|
|
381
|
+
"reconfigure",
|
|
382
|
+
help="Re-run the interactive postinstall (changes profile/knobs)",
|
|
383
|
+
)
|
|
384
|
+
recon_p.add_argument(
|
|
385
|
+
"extras", nargs="*", default=[],
|
|
386
|
+
help="Extra flags passed to postinstall-interactive.js",
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
bench_p = sub.add_parser(
|
|
390
|
+
"benchmark",
|
|
391
|
+
help="Run evo-memory benchmark against an isolated tmp DB (never touches user data)",
|
|
392
|
+
)
|
|
393
|
+
bench_p.add_argument(
|
|
394
|
+
"--json", action="store_true",
|
|
395
|
+
help="Emit JSON result instead of human-readable summary",
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
# S-M07: install-token rotation.
|
|
399
|
+
sub.add_parser(
|
|
400
|
+
"rotate-token",
|
|
401
|
+
help="Rotate the SLM install token (run `slm restart` afterwards)",
|
|
402
|
+
)
|
|
403
|
+
|
|
336
404
|
args = parser.parse_args()
|
|
337
405
|
|
|
338
406
|
if not args.command:
|
|
@@ -348,7 +416,10 @@ def main() -> None:
|
|
|
348
416
|
# Cross-platform: macOS + Windows + Linux.
|
|
349
417
|
_NO_DAEMON_COMMANDS = {
|
|
350
418
|
"setup", "mode", "provider", "connect", "migrate", "mcp", "warmup",
|
|
351
|
-
"config", "evolve",
|
|
419
|
+
"config", "evolve", "db",
|
|
420
|
+
# v3.4.22 escape hatches — never auto-start the daemon on these.
|
|
421
|
+
"disable", "enable", "clear-cache", "reconfigure", "benchmark",
|
|
422
|
+
"rotate-token",
|
|
352
423
|
}
|
|
353
424
|
if args.command not in _NO_DAEMON_COMMANDS:
|
|
354
425
|
try:
|