superlocalmemory 3.5.8 → 3.6.1

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 (72) hide show
  1. package/ATTRIBUTION.md +24 -0
  2. package/CHANGELOG.md +86 -0
  3. package/README.md +142 -35
  4. package/package.json +1 -1
  5. package/pyproject.toml +2 -1
  6. package/src/superlocalmemory/__init__.py +1 -1
  7. package/src/superlocalmemory/cli/cache_cmd.py +198 -0
  8. package/src/superlocalmemory/cli/commands.py +80 -2
  9. package/src/superlocalmemory/cli/compress_cmd.py +179 -0
  10. package/src/superlocalmemory/cli/help_cmd.py +197 -0
  11. package/src/superlocalmemory/cli/main.py +122 -0
  12. package/src/superlocalmemory/cli/optimize_cmd.py +178 -0
  13. package/src/superlocalmemory/cli/optimize_constants.py +31 -0
  14. package/src/superlocalmemory/cli/proxy_cmd.py +104 -0
  15. package/src/superlocalmemory/core/config.py +5 -0
  16. package/src/superlocalmemory/core/engine.py +23 -0
  17. package/src/superlocalmemory/core/mcp_embedder_proxy.py +89 -0
  18. package/src/superlocalmemory/llm/backbone.py +10 -4
  19. package/src/superlocalmemory/mcp/server.py +34 -0
  20. package/src/superlocalmemory/mcp/tools_v3.py +6 -2
  21. package/src/superlocalmemory/optimize/NOTICE +11 -0
  22. package/src/superlocalmemory/optimize/__init__.py +0 -0
  23. package/src/superlocalmemory/optimize/adapters/__init__.py +68 -0
  24. package/src/superlocalmemory/optimize/adapters/_agent_registry.py +120 -0
  25. package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +115 -0
  26. package/src/superlocalmemory/optimize/adapters/openai_adapter.py +125 -0
  27. package/src/superlocalmemory/optimize/adapters/wrap.py +218 -0
  28. package/src/superlocalmemory/optimize/cache/__init__.py +31 -0
  29. package/src/superlocalmemory/optimize/cache/boundary_store.py +455 -0
  30. package/src/superlocalmemory/optimize/cache/centroid_store.py +158 -0
  31. package/src/superlocalmemory/optimize/cache/context_key.py +67 -0
  32. package/src/superlocalmemory/optimize/cache/exact.py +85 -0
  33. package/src/superlocalmemory/optimize/cache/invalidation.py +36 -0
  34. package/src/superlocalmemory/optimize/cache/key_builder.py +98 -0
  35. package/src/superlocalmemory/optimize/cache/manager.py +452 -0
  36. package/src/superlocalmemory/optimize/cache/semantic.py +568 -0
  37. package/src/superlocalmemory/optimize/cache/stampede.py +50 -0
  38. package/src/superlocalmemory/optimize/compress/__init__.py +17 -0
  39. package/src/superlocalmemory/optimize/compress/align.py +153 -0
  40. package/src/superlocalmemory/optimize/compress/ccr.py +157 -0
  41. package/src/superlocalmemory/optimize/compress/extractive_code.py +311 -0
  42. package/src/superlocalmemory/optimize/compress/extractive_json.py +72 -0
  43. package/src/superlocalmemory/optimize/compress/prose_llmlingua.py +77 -0
  44. package/src/superlocalmemory/optimize/compress/router.py +548 -0
  45. package/src/superlocalmemory/optimize/config/__init__.py +35 -0
  46. package/src/superlocalmemory/optimize/config/defaults.py +48 -0
  47. package/src/superlocalmemory/optimize/config/schema.py +255 -0
  48. package/src/superlocalmemory/optimize/config/store.py +209 -0
  49. package/src/superlocalmemory/optimize/metrics/__init__.py +8 -0
  50. package/src/superlocalmemory/optimize/metrics/counters.py +138 -0
  51. package/src/superlocalmemory/optimize/metrics/estimator.py +90 -0
  52. package/src/superlocalmemory/optimize/metrics/exporters.py +77 -0
  53. package/src/superlocalmemory/optimize/metrics/persistence.py +115 -0
  54. package/src/superlocalmemory/optimize/proxy/__init__.py +28 -0
  55. package/src/superlocalmemory/optimize/proxy/_helpers.py +257 -0
  56. package/src/superlocalmemory/optimize/proxy/anthropic_surface.py +171 -0
  57. package/src/superlocalmemory/optimize/proxy/gemini_surface.py +121 -0
  58. package/src/superlocalmemory/optimize/proxy/lifecycle.py +126 -0
  59. package/src/superlocalmemory/optimize/proxy/openai_surface.py +125 -0
  60. package/src/superlocalmemory/optimize/proxy/server.py +151 -0
  61. package/src/superlocalmemory/optimize/storage/__init__.py +0 -0
  62. package/src/superlocalmemory/optimize/storage/db.py +1016 -0
  63. package/src/superlocalmemory/optimize/storage/schema.py +184 -0
  64. package/src/superlocalmemory/server/routes/optimize.py +167 -0
  65. package/src/superlocalmemory/server/routes/v3_api.py +63 -1
  66. package/src/superlocalmemory/server/unified_daemon.py +105 -0
  67. package/src/superlocalmemory/ui/index.html +98 -0
  68. package/src/superlocalmemory/ui/js/ng-shell.js +5 -1
  69. package/src/superlocalmemory/ui/js/optimize.js +173 -0
  70. package/src/superlocalmemory.egg-info/PKG-INFO +144 -36
  71. package/src/superlocalmemory.egg-info/SOURCES.txt +51 -0
  72. package/src/superlocalmemory.egg-info/requires.txt +1 -0
@@ -64,6 +64,36 @@ def _cmd_escape_rotate_token(args: Namespace) -> None:
64
64
  cmd_rotate_token(args)
65
65
 
66
66
 
67
+ # ---- SLM v3.6 Optimize dispatch functions (additive) ----
68
+
69
+ def _cmd_optimize(args: Namespace) -> None:
70
+ from superlocalmemory.cli.optimize_cmd import cmd_optimize
71
+ cmd_optimize(args)
72
+
73
+
74
+ def _cmd_cache(args: Namespace) -> None:
75
+ from superlocalmemory.cli.cache_cmd import cmd_cache
76
+ cmd_cache(args)
77
+
78
+
79
+ def _cmd_compress(args: Namespace) -> None:
80
+ from superlocalmemory.cli.compress_cmd import cmd_compress
81
+ cmd_compress(args)
82
+
83
+
84
+ def _cmd_proxy(args: Namespace) -> None:
85
+ from superlocalmemory.cli.proxy_cmd import cmd_proxy
86
+ cmd_proxy(args)
87
+
88
+
89
+ def _cmd_help_optimize(args: Namespace) -> None:
90
+ from superlocalmemory.cli.help_cmd import cmd_help_optimize
91
+ cmd_help_optimize(args)
92
+
93
+
94
+ # ---- end SLM v3.6 Optimize dispatch functions ----
95
+
96
+
67
97
  def dispatch(args: Namespace) -> None:
68
98
  """Route CLI command to the appropriate handler."""
69
99
  # Auto-install/upgrade hooks on version change (single file read, ~0.1ms)
@@ -126,6 +156,14 @@ def dispatch(args: Namespace) -> None:
126
156
  "reconfigure": _cmd_escape_reconfigure,
127
157
  "benchmark": _cmd_escape_benchmark,
128
158
  "rotate-token": _cmd_escape_rotate_token,
159
+ # LLD-06 — `slm wrap <agent> [args...]` activates the Optimize proxy.
160
+ "wrap": _cmd_wrap,
161
+ # V3.6 Optimize subcommands (additive)
162
+ "optimize": _cmd_optimize,
163
+ "cache": _cmd_cache,
164
+ "compress": _cmd_compress,
165
+ "proxy": _cmd_proxy,
166
+ "help-optimize": _cmd_help_optimize,
129
167
  }
130
168
  handler = handlers.get(args.command)
131
169
  if handler:
@@ -135,6 +173,39 @@ def dispatch(args: Namespace) -> None:
135
173
  sys.exit(1)
136
174
 
137
175
 
176
+ def _cmd_wrap(args: Namespace) -> None:
177
+ """LLD-06 §6.6 — `slm wrap <agent> [args...]` activates the Optimize proxy.
178
+
179
+ Routes the Optimize layer's per-agent launch/activation. See
180
+ optimize.adapters._agent_registry for the full agent table.
181
+ """
182
+ if getattr(args, "list", False):
183
+ from superlocalmemory.optimize.adapters.wrap import list_agents
184
+ from superlocalmemory.optimize.adapters._agent_registry import AGENT_REGISTRY
185
+ print("Registered agents for `slm wrap`:")
186
+ for key in list_agents():
187
+ spec = AGENT_REGISTRY.get(key, {})
188
+ mech = spec.get("mechanism", "unknown")
189
+ print(f" {key:20s} mechanism={mech}")
190
+ return
191
+
192
+ agent = getattr(args, "agent", None)
193
+ if not agent:
194
+ print("Usage: slm wrap <agent> [args...]\n"
195
+ " slm wrap --list\n"
196
+ " slm wrap --help")
197
+ sys.exit(2)
198
+
199
+ agent_args = list(getattr(args, "agent_args", []) or [])
200
+ persistent = bool(getattr(args, "persistent", False))
201
+ dry_run = bool(getattr(args, "dry_run", False))
202
+
203
+ from superlocalmemory.optimize.adapters.wrap import wrap_agent
204
+ rc = wrap_agent(agent, agent_args, persistent=persistent, dry_run=dry_run)
205
+ if rc:
206
+ sys.exit(rc)
207
+
208
+
138
209
  # -- Daemon serve mode (V3.3.21) ------------------------------------------
139
210
 
140
211
  def cmd_serve(args: Namespace) -> None:
@@ -2573,6 +2644,11 @@ def cmd_reap(args: Namespace) -> None:
2573
2644
  """Find and kill orphaned SLM processes."""
2574
2645
  use_json = getattr(args, "json", False)
2575
2646
  dry_run = not getattr(args, "force", False)
2647
+ # V3.5.9: --all bypasses orphan detection and kills every slm mcp process
2648
+ # except the current one. Use after switching IDEs to clear stale sessions.
2649
+ use_force_all = getattr(args, "all", False)
2650
+ if use_force_all:
2651
+ dry_run = False # --all always kills; --force is implied
2576
2652
 
2577
2653
  try:
2578
2654
  from superlocalmemory.infra.process_reaper import (
@@ -2581,7 +2657,7 @@ def cmd_reap(args: Namespace) -> None:
2581
2657
  )
2582
2658
 
2583
2659
  config = ReaperConfig()
2584
- result = cleanup_all_orphans(config, dry_run=dry_run)
2660
+ result = cleanup_all_orphans(config, dry_run=dry_run, force=use_force_all)
2585
2661
  except Exception as exc:
2586
2662
  if use_json:
2587
2663
  from superlocalmemory.cli.json_output import json_print
@@ -2600,7 +2676,8 @@ def cmd_reap(args: Namespace) -> None:
2600
2676
  "killed": result.get("killed", 0),
2601
2677
  "skipped": result.get("skipped", 0),
2602
2678
  }, next_actions=[
2603
- {"command": "slm reap --force --json", "description": "Kill orphans"},
2679
+ {"command": "slm reap --force --json", "description": "Kill orphan processes"},
2680
+ {"command": "slm reap --all --json", "description": "Kill ALL slm mcp sessions (IDE switch)"},
2604
2681
  {"command": "slm status --json", "description": "Check status"},
2605
2682
  ])
2606
2683
  return
@@ -2620,3 +2697,4 @@ def cmd_reap(args: Namespace) -> None:
2620
2697
  print(f" Skipped: {skipped}")
2621
2698
  if dry_run and orphans > 0:
2622
2699
  print("\n Use --force to kill orphaned processes.")
2700
+ print(" Use --all to kill ALL slm mcp sessions (after IDE switch).")
@@ -0,0 +1,179 @@
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 | https://varunpratap.com
4
+
5
+ """Handlers for ``slm compress status|mode|code|prose|ccr``."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import dataclasses
10
+ import json
11
+ import sys
12
+ from argparse import Namespace
13
+
14
+ from superlocalmemory.cli.optimize_constants import AGGRESSIVE_MODE_WARNING
15
+
16
+
17
+ def _get_store():
18
+ from superlocalmemory.optimize.config.store import ConfigStore
19
+ return ConfigStore()
20
+
21
+
22
+ def _get_cache_db():
23
+ from superlocalmemory.optimize.storage.db import CacheDB
24
+ return CacheDB()
25
+
26
+
27
+ def _write_config(**fields) -> None:
28
+ """5-step immutable config-write."""
29
+ store = _get_store()
30
+ cfg = store.get()
31
+ try:
32
+ cfg = dataclasses.replace(cfg, **fields)
33
+ store.save(cfg)
34
+ except ValueError as e:
35
+ print(f"Error: {e}", file=sys.stderr)
36
+ sys.exit(1)
37
+ except OSError as e:
38
+ print(f"Error writing config: {e}", file=sys.stderr)
39
+ sys.exit(1)
40
+
41
+
42
+ def cmd_compress(args: Namespace) -> None:
43
+ """Top-level dispatcher for ``slm compress <subcommand>``."""
44
+ sub = getattr(args, "compress_command", None)
45
+ _dispatch = {
46
+ "status": cmd_compress_status,
47
+ "mode": cmd_compress_mode,
48
+ "code": cmd_compress_code,
49
+ "prose": cmd_compress_prose,
50
+ "ccr": cmd_compress_ccr,
51
+ "align": cmd_compress_align,
52
+ }
53
+ handler = _dispatch.get(sub or "")
54
+ if handler:
55
+ handler(args)
56
+ else:
57
+ print("Usage: slm compress status|mode|code|prose|ccr [options]")
58
+ sys.exit(0)
59
+
60
+
61
+ def cmd_compress_status(args: Namespace) -> None:
62
+ """Print compression status."""
63
+ use_json = getattr(args, "json", False)
64
+ cfg = _get_store().get()
65
+
66
+ if use_json:
67
+ data = {
68
+ "status": "ok",
69
+ "compress_enabled": cfg.compress_enabled,
70
+ "compress_mode": cfg.compress_mode,
71
+ "compress_code": cfg.compress_code,
72
+ "compress_prose": cfg.compress_prose,
73
+ "compress_ccr": cfg.compress_ccr,
74
+ }
75
+ print(json.dumps(data, indent=2))
76
+ return
77
+
78
+ print("Compression status:")
79
+ print(f" Enabled: {'yes' if cfg.compress_enabled else 'no'}")
80
+ print(f" Mode: {cfg.compress_mode}")
81
+ print(f" Code: {'ON' if cfg.compress_code else 'OFF'}"
82
+ " (extractive JSON/code — lossless structure)")
83
+ print(f" Prose: {'ON' if cfg.compress_prose else 'OFF'}")
84
+ print(f" CCR: {'ON' if cfg.compress_ccr else 'OFF'}"
85
+ " (reversible context retrieval)")
86
+
87
+
88
+ def cmd_compress_mode(args: Namespace) -> None:
89
+ """Set compression mode to safe or aggressive."""
90
+ use_json = getattr(args, "json", False)
91
+ mode_value = getattr(args, "mode_value", "safe")
92
+
93
+ if mode_value == "aggressive":
94
+ print(AGGRESSIVE_MODE_WARNING)
95
+
96
+ _write_config(compress_mode=mode_value)
97
+
98
+ if use_json:
99
+ print(json.dumps({"status": "ok", "compress_mode": mode_value}))
100
+ return
101
+
102
+ print(f"Compression mode set to: {mode_value}.")
103
+ print("Daemon hot-reload: active within 2s. No restart required.")
104
+
105
+
106
+ def cmd_compress_code(args: Namespace) -> None:
107
+ """Enable or disable code/JSON compression."""
108
+ use_json = getattr(args, "json", False)
109
+ value = getattr(args, "code_value", "on")
110
+
111
+ _write_config(compress_code=(value == "on"))
112
+
113
+ if use_json:
114
+ print(json.dumps({"status": "ok", "compress_code": value == "on"}))
115
+ return
116
+
117
+ print(f"Code compression: {'ENABLED' if value == 'on' else 'DISABLED'}.")
118
+ print("Daemon hot-reload: active within 2s.")
119
+
120
+
121
+ def cmd_compress_prose(args: Namespace) -> None:
122
+ """Enable or disable prose compression."""
123
+ use_json = getattr(args, "json", False)
124
+ value = getattr(args, "prose_value", "off")
125
+
126
+ store = _get_store()
127
+ cfg = store.get()
128
+
129
+ fields: dict = {"compress_prose": (value == "on")}
130
+ if value == "on" and not cfg.compress_enabled:
131
+ fields["compress_enabled"] = True
132
+
133
+ try:
134
+ cfg = dataclasses.replace(cfg, **fields)
135
+ store.save(cfg)
136
+ except (ValueError, OSError) as e:
137
+ print(f"Error: {e}", file=sys.stderr)
138
+ sys.exit(1)
139
+
140
+ if use_json:
141
+ print(json.dumps({"status": "ok", "compress_prose": value == "on"}))
142
+ return
143
+
144
+ print(f"Prose compression: {'ENABLED' if value == 'on' else 'DISABLED'}.")
145
+ if value == "on" and "compress_enabled" in fields:
146
+ print(" (also enabled global compress)")
147
+ print("Daemon hot-reload: active within 2s.")
148
+
149
+
150
+ def cmd_compress_align(args: Namespace) -> None:
151
+ """Enable or disable alignment compression."""
152
+ use_json = getattr(args, "json", False)
153
+ value = getattr(args, "align_value", "on")
154
+
155
+ _write_config(compress_align=(value == "on"))
156
+
157
+ if use_json:
158
+ print(json.dumps({"status": "ok", "compress_align": value == "on"}))
159
+ return
160
+
161
+ print(f"Alignment compression: {'ENABLED' if value == 'on' else 'DISABLED'}.")
162
+ print("Daemon hot-reload: active within 2s.")
163
+
164
+
165
+ def cmd_compress_ccr(args: Namespace) -> None:
166
+ """Enable or disable CCR (Compressed Context Retrieval)."""
167
+ use_json = getattr(args, "json", False)
168
+ value = getattr(args, "ccr_value", "off")
169
+
170
+ _write_config(compress_ccr=(value == "on"))
171
+
172
+ if use_json:
173
+ print(json.dumps({"status": "ok", "compress_ccr": value == "on"}))
174
+ return
175
+
176
+ print(f"CCR (Compressed Context Retrieval): {'ENABLED' if value == 'on' else 'DISABLED'}.")
177
+ if value == "on":
178
+ print("Originals stored in llmcache.db for reversible retrieval.")
179
+ print("Daemon hot-reload: active within 2s.")
@@ -0,0 +1,197 @@
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 | https://varunpratap.com
4
+
5
+ """Handler for ``slm help-optimize``."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import sys
10
+ from argparse import Namespace
11
+
12
+ _HELP_SECTIONS: dict[str, str] = {
13
+ "header": """\
14
+ SLM v3.6 Optimize — Developer Reference
15
+ ========================================
16
+ Every feature is configurable via CLI. UI provides the same controls for
17
+ non-technical users. All CLI commands write config at runtime — daemon
18
+ hot-reloads within 2 seconds. No restart required.
19
+ """,
20
+ "optimize": """\
21
+ slm optimize — Optimize module control
22
+ ---------------------------------------
23
+ slm optimize status Show all Optimize settings
24
+ slm optimize on Enable cache + compress
25
+ slm optimize off Disable cache + compress (proxy keeps running)
26
+ slm optimize savings [--since N] Token/cost savings report (default: 7 days)
27
+ --since N Days to look back (integer, default 7)
28
+ --provider P Filter by: anthropic|openai|gemini
29
+ All: --json Machine-readable JSON output
30
+ """,
31
+ "cache": """\
32
+ slm cache — Cache control
33
+ --------------------------
34
+ slm cache status Entry count, DB size, TTLs, hit rate
35
+ slm cache clear Delete all entries for this tenant
36
+ slm cache invalidate --tag <t> Delete entries whose tag array contains <t>
37
+ slm cache ttl --set <s> Set exact-cache TTL (seconds)
38
+ --semantic <s> Set semantic-cache TTL (seconds)
39
+ slm cache semantic on|off Enable/disable semantic cache
40
+ All: --json --tenant <id>
41
+
42
+ TTL examples:
43
+ slm cache ttl --set 3600 # 1 hour exact cache
44
+ slm cache ttl --set 86400 # 24 hour exact cache (default)
45
+ slm cache ttl --semantic 7200 # 2 hour semantic cache
46
+ """,
47
+ "compress": """\
48
+ slm compress — Compression control
49
+ -----------------------------------
50
+ slm compress status Show compression mode, per-channel state
51
+ slm compress mode safe|aggressive Set compression aggressiveness
52
+ slm compress code on|off Enable/disable code/JSON compression
53
+ slm compress prose on|off Enable/disable prose compression
54
+ slm compress ccr on|off Enable/disable Compressed Context Retrieval
55
+ All: --json
56
+ """,
57
+ "safety": """\
58
+ COMPRESSION SAFETY WARNING
59
+ ---------------------------
60
+ Safe mode (default):
61
+ - Code/JSON compression: extractive, structure-preserving, lossless.
62
+ - Prose compression: DISABLED in safe mode. Enable manually.
63
+ - CCR: DISABLED by default. Originals stored for reversible retrieval.
64
+ - This mode is production-safe for all use cases.
65
+
66
+ Aggressive mode:
67
+ !! RISK: May reduce output fidelity. Use with caution. !!
68
+ - Prose compression: LLMLingua-2-style extractive summarization.
69
+ - May omit nuance, hedges, or low-salience context.
70
+ - DO NOT use for:
71
+ - Code generation or code review
72
+ - Legal, compliance, or regulatory text
73
+ - Math, formulas, or structured data generation
74
+ - Any task requiring exact reproduction of input
75
+ - Suitable for:
76
+ - Open-ended brainstorming
77
+ - Summarization of long documents
78
+ - Casual conversation and exploration
79
+ - To revert: slm compress mode safe
80
+ """,
81
+ "proxy": """\
82
+ slm proxy — Optimization proxy
83
+ --------------------------------
84
+ slm proxy [--port P] [--provider anthropic|openai|gemini]
85
+ [--no-compress] [--semantic] [--json]
86
+
87
+ Starts the SLM proxy (or reports existing). Proxy intercepts LLM calls,
88
+ applies cache lookup, and optionally compresses context before forwarding.
89
+
90
+ Default port: 8765
91
+ Anthropic surface: http://127.0.0.1:8765
92
+ OpenAI surface: http://127.0.0.1:8765/v1
93
+ """,
94
+ "agents": """\
95
+ PER-AGENT SETUP RECIPES
96
+ ------------------------
97
+
98
+ --- Claude Code (ANTHROPIC_BASE_URL) ---
99
+ The simplest redirect. Set this env var before launching Claude Code.
100
+
101
+ Option A — environment variable (per-session):
102
+ export ANTHROPIC_BASE_URL=http://127.0.0.1:8765
103
+ claude # Claude Code picks up the env var
104
+
105
+ Option B — slm wrap (one command, recommended):
106
+ slm wrap claude # starts proxy + sets env + launches claude
107
+
108
+ Option C — permanent (add to ~/.zshrc or ~/.bashrc):
109
+ echo 'export ANTHROPIC_BASE_URL=http://127.0.0.1:8765' >> ~/.zshrc
110
+ source ~/.zshrc
111
+
112
+ Verify: slm optimize status -> look for "proxy: running on :8765"
113
+
114
+ --- Antigravity (config.toml base_url) ---
115
+ Antigravity reads base_url from its config.toml.
116
+ Default config location: ~/.config/antigravity/config.toml
117
+
118
+ Add or update this line under the [api] section:
119
+ [api]
120
+ base_url = "http://127.0.0.1:8765"
121
+
122
+ Or use slm wrap (if supported in your version):
123
+ slm wrap antigravity
124
+
125
+ Verify: antigravity --debug -> look for "base_url: http://127.0.0.1:8765"
126
+
127
+ --- Generic OpenAI-compatible clients (Cline, Cursor, Aider, OpenCode) ---
128
+ Any client that accepts an OpenAI base_url can use the /v1 surface:
129
+ base_url = http://127.0.0.1:8765/v1
130
+ api_key = (use your real provider key — proxy forwards it)
131
+
132
+ Aider:
133
+ aider --openai-api-base http://127.0.0.1:8765/v1
134
+
135
+ Cline (VS Code settings.json):
136
+ "cline.openAiBaseUrl": "http://127.0.0.1:8765/v1"
137
+
138
+ Cursor (Settings > Models > Base URL):
139
+ http://127.0.0.1:8765/v1
140
+
141
+ OpenCode / other CLI tools:
142
+ OPENAI_BASE_URL=http://127.0.0.1:8765/v1 opencode
143
+
144
+ Or use slm wrap:
145
+ slm wrap aider [-- <aider args>]
146
+ slm wrap cursor
147
+ slm wrap opencode
148
+
149
+ --- SDK adapters (Python) ---
150
+ from superlocalmemory.optimize.adapters.openai_adapter import withSLM
151
+ from openai import OpenAI
152
+ client = withSLM(OpenAI()) # same interface as OpenAI() — zero API change
153
+
154
+ from superlocalmemory.optimize.adapters.anthropic_adapter import withSLM
155
+ from anthropic import Anthropic
156
+ client = withSLM(Anthropic())
157
+
158
+ NOTE: withSLM() is a pass-through when optimize is OFF.
159
+ No behavioral change until you run: slm optimize on
160
+ """,
161
+ "footer": """\
162
+ More commands:
163
+ slm help-optimize cache Cache subcommand reference
164
+ slm help-optimize compress Compress reference + safety warning
165
+ slm help-optimize agents Per-agent setup recipes
166
+ slm help-optimize safety Compression safety warning only
167
+
168
+ Documentation: https://superlocalmemory.com
169
+ GitHub: https://github.com/qualixar/superlocalmemory
170
+ AI Reliability Engineering by @varunPbhardwaj — https://qualixar.com
171
+ """,
172
+ }
173
+
174
+
175
+ def cmd_help_optimize(args: Namespace) -> None:
176
+ """Print the full slm help-optimize page or a topic-specific section."""
177
+ topic = getattr(args, "topic", None)
178
+ no_pager = getattr(args, "no_pager", False)
179
+
180
+ if topic and topic not in _HELP_SECTIONS:
181
+ print(f"Unknown topic: {topic}."
182
+ f" Topics: {' '.join(k for k in _HELP_SECTIONS if k != 'footer')}")
183
+ sys.exit(1)
184
+
185
+ if topic:
186
+ text = _HELP_SECTIONS[topic]
187
+ else:
188
+ text = "\n".join(_HELP_SECTIONS.values())
189
+
190
+ if no_pager or not sys.stdout.isatty():
191
+ print(text)
192
+ else:
193
+ try:
194
+ import pydoc
195
+ pydoc.pager(text)
196
+ except Exception:
197
+ print(text)
@@ -240,6 +240,28 @@ def main() -> None:
240
240
  help="Run only the fast checks (deps + config); skip daemon/embedding probes",
241
241
  )
242
242
 
243
+ # LLD-06 §6.6 — `slm wrap <agent> [args...]` activates the Optimize
244
+ # proxy for a specific agent. Supported agents: claude, claude-settings,
245
+ # codex, aider, cline, generic, etc. See optimize.adapters._agent_registry.
246
+ wrap_p = sub.add_parser(
247
+ "wrap",
248
+ help="Activate Optimize proxy for a specific agent (claude, codex, aider, ...)",
249
+ )
250
+ wrap_p.add_argument(
251
+ "--list", action="store_true",
252
+ help="List all registered agents and their mechanisms",
253
+ )
254
+ wrap_p.add_argument(
255
+ "--persistent", action="store_true",
256
+ help="Persist env vars to the agent's config file (~/.claude/settings.json) instead of launching",
257
+ )
258
+ wrap_p.add_argument(
259
+ "--dry-run", action="store_true",
260
+ help="Print the action that would be taken without executing it",
261
+ )
262
+ wrap_p.add_argument("agent", nargs="?", default=None, help="Agent key (run `slm wrap --list` to see all)")
263
+ wrap_p.add_argument("agent_args", nargs=argparse.REMAINDER, help="Args passed to the agent binary")
264
+
243
265
  # -- Services ------------------------------------------------------
244
266
  sub.add_parser("mcp", help="Start MCP server (stdio transport for IDE integration)")
245
267
  sub.add_parser("warmup", help="Pre-download embedding model (~500MB, one-time)")
@@ -349,6 +371,10 @@ def main() -> None:
349
371
  "--force", action="store_true",
350
372
  help="Kill orphans (default: dry run only)",
351
373
  )
374
+ reap_p.add_argument(
375
+ "--all", action="store_true", dest="all",
376
+ help="Kill ALL slm mcp processes regardless of orphan status (use after IDE switch)",
377
+ )
352
378
  reap_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
353
379
 
354
380
  # V3.4.3: Ingestion adapters
@@ -445,6 +471,95 @@ def main() -> None:
445
471
  help="Rotate the SLM install token (run `slm restart` afterwards)",
446
472
  )
447
473
 
474
+ # ---- SLM v3.6 Optimize subcommands (additive, never modify above) ----
475
+
476
+ # slm optimize status|on|off|savings
477
+ opt_p = sub.add_parser("optimize", help="Optimize module control (cache + compress)")
478
+ opt_sub = opt_p.add_subparsers(dest="opt_command", title="optimize subcommands")
479
+ opt_sub.add_parser("status", help="Show Optimize status")
480
+ opt_sub.add_parser("on", help="Enable cache + compress")
481
+ opt_sub.add_parser("off", help="Disable cache + compress")
482
+ savings_p = opt_sub.add_parser("savings", help="Token/cost savings report")
483
+ savings_p.add_argument("--since", type=int, default=7, help="Days to look back (default 7)")
484
+ savings_p.add_argument("--provider", default=None,
485
+ choices=["anthropic", "openai", "gemini"],
486
+ help="Filter by provider")
487
+ for _sp in opt_sub.choices.values():
488
+ if not any(a.option_strings == ["--json"] for a in _sp._actions):
489
+ _sp.add_argument("--json", action="store_true",
490
+ help="Output structured JSON (agent-native)")
491
+
492
+ # slm cache status|clear|invalidate|ttl|semantic
493
+ cache_p = sub.add_parser("cache", help="Cache control (TTL, clear, invalidate, semantic)")
494
+ cache_sub = cache_p.add_subparsers(dest="cache_command", title="cache subcommands")
495
+ cache_sub.add_parser("status", help="Show cache state")
496
+ cache_sub.add_parser("clear", help="Delete all entries for tenant")
497
+ cache_inv_p = cache_sub.add_parser("invalidate", help="Delete entries by tag")
498
+ cache_inv_p.add_argument("--tag", required=True, help="Tag string to match")
499
+ cache_ttl_p = cache_sub.add_parser("ttl", help="Set cache TTL in seconds")
500
+ cache_ttl_p.add_argument("--set", dest="ttl_set", type=int, default=None,
501
+ help="Exact-cache TTL (seconds, >0)")
502
+ cache_ttl_p.add_argument("--semantic", dest="ttl_semantic", type=int, default=None,
503
+ help="Semantic-cache TTL (seconds, >0)")
504
+ cache_sem_p = cache_sub.add_parser("semantic", help="Enable/disable semantic cache")
505
+ cache_sem_p.add_argument("semantic_value", choices=["on", "off"], help="on or off")
506
+ for _sp in cache_sub.choices.values():
507
+ if not any(a.option_strings == ["--json"] for a in _sp._actions):
508
+ _sp.add_argument("--json", action="store_true",
509
+ help="Output structured JSON (agent-native)")
510
+ if not any(a.option_strings == ["--tenant"] for a in _sp._actions):
511
+ _sp.add_argument("--tenant", default="default", help="Tenant ID (default: 'default')")
512
+
513
+ # slm compress status|mode|code|prose|ccr
514
+ compress_p = sub.add_parser("compress", help="Compression control (mode, code, prose, CCR)")
515
+ comp_sub = compress_p.add_subparsers(dest="compress_command", title="compress subcommands")
516
+ comp_sub.add_parser("status", help="Show compression state")
517
+ comp_mode_p = comp_sub.add_parser("mode", help="Set compression mode")
518
+ comp_mode_p.add_argument("mode_value", choices=["safe", "aggressive"],
519
+ help="safe (default) or aggressive")
520
+ comp_code_p = comp_sub.add_parser("code", help="Enable/disable code compression")
521
+ comp_code_p.add_argument("code_value", choices=["on", "off"], help="on or off")
522
+ comp_prose_p = comp_sub.add_parser("prose", help="Enable/disable prose compression")
523
+ comp_prose_p.add_argument("prose_value", choices=["on", "off"], help="on or off")
524
+ comp_ccr_p = comp_sub.add_parser("ccr", help="Enable/disable CCR")
525
+ comp_ccr_p.add_argument("ccr_value", choices=["on", "off"], help="on or off")
526
+ comp_align_p = comp_sub.add_parser("align", help="Enable/disable alignment compression")
527
+ comp_align_p.add_argument("align_value", choices=["on", "off"], help="on or off")
528
+ for _sp in comp_sub.choices.values():
529
+ if not any(a.option_strings == ["--json"] for a in _sp._actions):
530
+ _sp.add_argument("--json", action="store_true",
531
+ help="Output structured JSON (agent-native)")
532
+
533
+ # slm proxy
534
+ proxy_p = sub.add_parser("proxy", help="Start SLM optimization proxy (Anthropic + OpenAI)")
535
+ proxy_p.add_argument("--port", type=int, default=8765, help="Port (default: 8765)")
536
+ proxy_p.add_argument("--provider", default="anthropic",
537
+ choices=["anthropic", "openai", "gemini"],
538
+ help="Target provider (default: anthropic)")
539
+ proxy_p.add_argument("--no-compress", action="store_true", dest="no_compress",
540
+ help="Disable compression for this session")
541
+ proxy_p.add_argument("--semantic", action="store_true",
542
+ help="Enable semantic cache for this session")
543
+ proxy_p.add_argument("--json", action="store_true",
544
+ help="Output structured JSON (agent-native)")
545
+
546
+ # slm help-optimize
547
+ help_opt_p = sub.add_parser(
548
+ "help-optimize",
549
+ help="Full Optimize reference: subcommands + agent recipes + safety notes",
550
+ )
551
+ help_opt_p.add_argument(
552
+ "topic", nargs="?", default=None,
553
+ choices=["cache", "compress", "optimize", "proxy", "agents", "safety"],
554
+ help="Topic to display (default: all)",
555
+ )
556
+ help_opt_p.add_argument(
557
+ "--no-pager", action="store_true", dest="no_pager", default=False,
558
+ help="Print to stdout instead of piping through a pager",
559
+ )
560
+
561
+ # ---- end SLM v3.6 Optimize subcommands ----
562
+
448
563
  args = parser.parse_args()
449
564
 
450
565
  if not args.command:
@@ -464,6 +579,13 @@ def main() -> None:
464
579
  # v3.4.22 escape hatches — never auto-start the daemon on these.
465
580
  "disable", "enable", "clear-cache", "reconfigure", "benchmark",
466
581
  "rotate-token",
582
+ # LLD-06 — `slm wrap` may launch the agent binary directly without
583
+ # needing the daemon running (the agent will start the daemon on
584
+ # first LLM call, or the wrap command can be --dry-run).
585
+ "wrap",
586
+ # V3.6 Optimize commands that are config read/write only (no daemon needed)
587
+ "optimize", "cache", "compress", "help-optimize",
588
+ # NOTE: "proxy" NOT here — proxy needs daemon running
467
589
  }
468
590
  if args.command not in _NO_DAEMON_COMMANDS:
469
591
  try: