superlocalmemory 3.4.18 → 3.4.21

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 (172) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +42 -34
  3. package/bin/slm +11 -0
  4. package/bin/slm.bat +12 -0
  5. package/package.json +4 -3
  6. package/pyproject.toml +3 -2
  7. package/scripts/build-slm-hook.ps1 +40 -0
  8. package/scripts/build-slm-hook.sh +45 -0
  9. package/scripts/build_entry.py +452 -0
  10. package/scripts/ci/stage5b_gate.sh +50 -0
  11. package/scripts/postinstall/validation.js +187 -0
  12. package/scripts/postinstall-interactive.js +756 -0
  13. package/scripts/postinstall_binary.js +287 -0
  14. package/scripts/release_manifest.py +273 -0
  15. package/scripts/slm-hook.spec +56 -0
  16. package/skills/slm-build-graph/SKILL.md +423 -0
  17. package/skills/slm-list-recent/SKILL.md +348 -0
  18. package/skills/slm-recall/SKILL.md +343 -0
  19. package/skills/slm-remember/SKILL.md +194 -0
  20. package/skills/slm-show-patterns/SKILL.md +224 -0
  21. package/skills/slm-status/SKILL.md +363 -0
  22. package/skills/slm-switch-profile/SKILL.md +442 -0
  23. package/src/superlocalmemory/cli/commands.py +219 -79
  24. package/src/superlocalmemory/cli/context_commands.py +192 -0
  25. package/src/superlocalmemory/cli/daemon.py +15 -1
  26. package/src/superlocalmemory/cli/db_migrate.py +80 -0
  27. package/src/superlocalmemory/cli/escape_hatch.py +220 -0
  28. package/src/superlocalmemory/cli/main.py +72 -1
  29. package/src/superlocalmemory/core/context_cache.py +397 -0
  30. package/src/superlocalmemory/core/embeddings.py +8 -2
  31. package/src/superlocalmemory/core/engine.py +38 -2
  32. package/src/superlocalmemory/core/engine_wiring.py +1 -1
  33. package/src/superlocalmemory/core/ram_lock.py +111 -0
  34. package/src/superlocalmemory/core/recall_pipeline.py +433 -3
  35. package/src/superlocalmemory/core/recall_worker.py +8 -3
  36. package/src/superlocalmemory/core/security_primitives.py +635 -0
  37. package/src/superlocalmemory/core/shadow_router.py +319 -0
  38. package/src/superlocalmemory/core/slm_disabled.py +87 -0
  39. package/src/superlocalmemory/core/slmignore.py +125 -0
  40. package/src/superlocalmemory/core/topic_signature.py +143 -0
  41. package/src/superlocalmemory/core/worker_pool.py +14 -3
  42. package/src/superlocalmemory/encoding/cognitive_consolidator.py +2 -2
  43. package/src/superlocalmemory/evolution/budget.py +321 -0
  44. package/src/superlocalmemory/evolution/llm_dispatch.py +508 -0
  45. package/src/superlocalmemory/evolution/skill_evolver.py +144 -94
  46. package/src/superlocalmemory/hooks/_outcome_common.py +506 -0
  47. package/src/superlocalmemory/hooks/adapter_base.py +317 -0
  48. package/src/superlocalmemory/hooks/antigravity_adapter.py +192 -0
  49. package/src/superlocalmemory/hooks/claude_code_hooks.py +33 -1
  50. package/src/superlocalmemory/hooks/context_payload.py +312 -0
  51. package/src/superlocalmemory/hooks/copilot_adapter.py +154 -0
  52. package/src/superlocalmemory/hooks/cross_platform_connector.py +90 -0
  53. package/src/superlocalmemory/hooks/cursor_adapter.py +195 -0
  54. package/src/superlocalmemory/hooks/hook_handlers.py +109 -8
  55. package/src/superlocalmemory/hooks/ide_connector.py +25 -2
  56. package/src/superlocalmemory/hooks/post_tool_async_hook.py +165 -0
  57. package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +223 -0
  58. package/src/superlocalmemory/hooks/prewarm_auth.py +170 -0
  59. package/src/superlocalmemory/hooks/session_registry.py +186 -0
  60. package/src/superlocalmemory/hooks/stop_outcome_hook.py +134 -0
  61. package/src/superlocalmemory/hooks/sync_loop.py +114 -0
  62. package/src/superlocalmemory/hooks/user_prompt_hook.py +128 -0
  63. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +202 -0
  64. package/src/superlocalmemory/infra/backup.py +3 -3
  65. package/src/superlocalmemory/infra/cloud_backup.py +2 -2
  66. package/src/superlocalmemory/infra/event_bus.py +2 -2
  67. package/src/superlocalmemory/infra/webhook_dispatcher.py +3 -3
  68. package/src/superlocalmemory/learning/arm_catalog.py +99 -0
  69. package/src/superlocalmemory/learning/bandit.py +526 -0
  70. package/src/superlocalmemory/learning/bandit_cache.py +133 -0
  71. package/src/superlocalmemory/learning/behavioral.py +53 -1
  72. package/src/superlocalmemory/learning/consolidation_cycle.py +381 -0
  73. package/src/superlocalmemory/learning/consolidation_worker.py +188 -520
  74. package/src/superlocalmemory/learning/database.py +256 -0
  75. package/src/superlocalmemory/learning/dedup_hnsw.py +413 -0
  76. package/src/superlocalmemory/learning/ensemble.py +300 -0
  77. package/src/superlocalmemory/learning/fact_outcome_joins.py +207 -0
  78. package/src/superlocalmemory/learning/forgetting_scheduler.py +55 -0
  79. package/src/superlocalmemory/learning/hnsw_dedup.py +69 -0
  80. package/src/superlocalmemory/learning/labeler.py +87 -0
  81. package/src/superlocalmemory/learning/legacy_migration.py +277 -0
  82. package/src/superlocalmemory/learning/memory_merge.py +160 -0
  83. package/src/superlocalmemory/learning/model_cache.py +269 -0
  84. package/src/superlocalmemory/learning/model_rollback.py +278 -0
  85. package/src/superlocalmemory/learning/outcome_queue.py +284 -0
  86. package/src/superlocalmemory/learning/pattern_miner.py +415 -0
  87. package/src/superlocalmemory/learning/pattern_miner_constants.py +47 -0
  88. package/src/superlocalmemory/learning/ranker.py +225 -81
  89. package/src/superlocalmemory/learning/ranker_common.py +163 -0
  90. package/src/superlocalmemory/learning/ranker_retrain_legacy.py +202 -0
  91. package/src/superlocalmemory/learning/ranker_retrain_online.py +411 -0
  92. package/src/superlocalmemory/learning/reward.py +777 -0
  93. package/src/superlocalmemory/learning/reward_archive.py +210 -0
  94. package/src/superlocalmemory/learning/reward_boost.py +201 -0
  95. package/src/superlocalmemory/learning/reward_proxy.py +326 -0
  96. package/src/superlocalmemory/learning/shadow_test.py +524 -0
  97. package/src/superlocalmemory/learning/signal_worker.py +270 -0
  98. package/src/superlocalmemory/learning/signals.py +314 -0
  99. package/src/superlocalmemory/learning/trigram_index.py +547 -0
  100. package/src/superlocalmemory/mcp/server.py +5 -5
  101. package/src/superlocalmemory/mcp/tools_context.py +183 -0
  102. package/src/superlocalmemory/mcp/tools_core.py +92 -27
  103. package/src/superlocalmemory/parameterization/soft_prompt_generator.py +13 -0
  104. package/src/superlocalmemory/retrieval/engine.py +52 -0
  105. package/src/superlocalmemory/retrieval/reranker.py +4 -2
  106. package/src/superlocalmemory/server/api.py +2 -2
  107. package/src/superlocalmemory/server/bandit_loops.py +140 -0
  108. package/src/superlocalmemory/server/middleware/__init__.py +11 -0
  109. package/src/superlocalmemory/server/middleware/security_headers.py +144 -0
  110. package/src/superlocalmemory/server/routes/backup.py +36 -13
  111. package/src/superlocalmemory/server/routes/behavioral.py +50 -19
  112. package/src/superlocalmemory/server/routes/brain.py +1234 -0
  113. package/src/superlocalmemory/server/routes/data_io.py +4 -4
  114. package/src/superlocalmemory/server/routes/events.py +2 -2
  115. package/src/superlocalmemory/server/routes/helpers.py +1 -1
  116. package/src/superlocalmemory/server/routes/learning.py +192 -7
  117. package/src/superlocalmemory/server/routes/memories.py +189 -1
  118. package/src/superlocalmemory/server/routes/prewarm.py +171 -0
  119. package/src/superlocalmemory/server/routes/profiles.py +3 -3
  120. package/src/superlocalmemory/server/routes/token.py +88 -0
  121. package/src/superlocalmemory/server/routes/ws.py +5 -5
  122. package/src/superlocalmemory/server/security_middleware.py +13 -7
  123. package/src/superlocalmemory/server/ui.py +2 -2
  124. package/src/superlocalmemory/server/unified_daemon.py +335 -3
  125. package/src/superlocalmemory/storage/migration_runner.py +545 -0
  126. package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +67 -0
  127. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +132 -0
  128. package/src/superlocalmemory/storage/migrations/M003_migration_log.py +38 -0
  129. package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +46 -0
  130. package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +75 -0
  131. package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +75 -0
  132. package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +63 -0
  133. package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +54 -0
  134. package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +75 -0
  135. package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +87 -0
  136. package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +72 -0
  137. package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +55 -0
  138. package/src/superlocalmemory/storage/migrations/__init__.py +81 -0
  139. package/src/superlocalmemory/storage/models.py +4 -0
  140. package/src/superlocalmemory/ui/css/brain.css +409 -0
  141. package/src/superlocalmemory/ui/css/legacy-dashboard.css +645 -0
  142. package/src/superlocalmemory/ui/index.html +459 -1345
  143. package/src/superlocalmemory/ui/js/brain.js +1321 -0
  144. package/src/superlocalmemory/ui/js/clusters.js +123 -4
  145. package/src/superlocalmemory/ui/js/init.js +48 -39
  146. package/src/superlocalmemory/ui/js/memories.js +88 -2
  147. package/src/superlocalmemory/ui/js/modal.js +71 -1
  148. package/src/superlocalmemory/ui/js/ng-shell.js +101 -88
  149. package/src/superlocalmemory/ui/js/trust-dashboard.js +168 -25
  150. package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +2018 -0
  151. package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
  152. package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
  153. package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +7 -0
  154. package/src/superlocalmemory/ui/vendor/bootstrap.min.css +6 -0
  155. package/src/superlocalmemory/ui/vendor/d3.v7.min.js +2 -0
  156. package/src/superlocalmemory/ui/vendor/graphology-library.min.js +2 -0
  157. package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +2 -0
  158. package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +8 -0
  159. package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
  160. package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
  161. package/src/superlocalmemory/ui/vendor/sigma.min.js +1 -0
  162. package/src/superlocalmemory/ui/js/behavioral.js +0 -447
  163. package/src/superlocalmemory/ui/js/graph-core.js +0 -447
  164. package/src/superlocalmemory/ui/js/graph-interactions.js +0 -351
  165. package/src/superlocalmemory/ui/js/learning.js +0 -435
  166. package/src/superlocalmemory/ui/js/patterns.js +0 -93
  167. package/src/superlocalmemory.egg-info/PKG-INFO +0 -647
  168. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -335
  169. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  170. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  171. package/src/superlocalmemory.egg-info/requires.txt +0 -58
  172. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -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.21 — 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.21)")
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.21 — 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.21 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: