superlocalmemory 3.6.16 → 3.6.18

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 (57) hide show
  1. package/CHANGELOG.md +25 -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-memory-advisor.md +1 -1
  7. package/plugin/agents/slm-optimize-advisor.md +1 -1
  8. package/plugin/requirements.txt +1 -1
  9. package/plugin/skills/slm-cache/SKILL.md +1 -1
  10. package/plugin/skills/slm-compress/SKILL.md +1 -1
  11. package/plugin/skills/slm-graph/SKILL.md +1 -1
  12. package/plugin/skills/slm-recall/SKILL.md +1 -1
  13. package/plugin/skills/slm-remember/SKILL.md +1 -1
  14. package/plugin/skills/slm-session/SKILL.md +1 -1
  15. package/plugin/skills/slm-status/SKILL.md +1 -1
  16. package/plugin-src/agents/slm-memory-advisor.md +1 -1
  17. package/plugin-src/agents/slm-optimize-advisor.md +1 -1
  18. package/plugin-src/manifest.json +1 -1
  19. package/plugin-src/requirements.txt +1 -1
  20. package/plugin-src/rules/AGENTS.md +1 -1
  21. package/plugin-src/rules/CLAUDE.md.fragment +3 -3
  22. package/plugin-src/skills/slm-cache/SKILL.md +1 -1
  23. package/plugin-src/skills/slm-compress/SKILL.md +1 -1
  24. package/plugin-src/skills/slm-graph/SKILL.md +1 -1
  25. package/plugin-src/skills/slm-recall/SKILL.md +1 -1
  26. package/plugin-src/skills/slm-remember/SKILL.md +1 -1
  27. package/plugin-src/skills/slm-session/SKILL.md +1 -1
  28. package/plugin-src/skills/slm-status/SKILL.md +1 -1
  29. package/pyproject.toml +3 -2
  30. package/scripts/build-plugin.js +1 -1
  31. package/scripts/postinstall-interactive.js +94 -7
  32. package/src/superlocalmemory/__init__.py +1 -1
  33. package/src/superlocalmemory/cli/setup_wizard.py +34 -0
  34. package/src/superlocalmemory/core/embeddings.py +5 -0
  35. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +4 -0
  36. package/src/superlocalmemory/hooks/adapter_base.py +10 -3
  37. package/src/superlocalmemory/hooks/claude_code_hooks.py +40 -4
  38. package/src/superlocalmemory/hooks/copilot_adapter.py +78 -9
  39. package/src/superlocalmemory/hooks/hook_handlers.py +59 -1
  40. package/src/superlocalmemory/hooks/memory_protocol.py +102 -0
  41. package/src/superlocalmemory/hooks/post_tool_async_hook.py +23 -5
  42. package/src/superlocalmemory/infra/event_bus.py +4 -0
  43. package/src/superlocalmemory/learning/feedback.py +59 -0
  44. package/src/superlocalmemory/learning/outcome_queue.py +10 -2
  45. package/src/superlocalmemory/llm/backbone.py +8 -1
  46. package/src/superlocalmemory/retrieval/reranker.py +5 -0
  47. package/src/superlocalmemory/server/routes/learning.py +2 -0
  48. package/src/superlocalmemory/server/routes/v3_api.py +11 -0
  49. package/src/superlocalmemory/server/unified_daemon.py +78 -0
  50. package/src/superlocalmemory/storage/database.py +34 -7
  51. package/src/superlocalmemory/storage/migrations/M017_ccq_scope_column.py +79 -0
  52. package/src/superlocalmemory.egg-info/PKG-INFO +4 -3
  53. package/src/superlocalmemory.egg-info/SOURCES.txt +2 -0
  54. package/plugin-src/commands/slm-optimize.md +0 -22
  55. package/plugin-src/commands/slm-recall.md +0 -16
  56. package/plugin-src/commands/slm-remember.md +0 -16
  57. package/plugin-src/commands/slm-status.md +0 -15
package/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to SuperLocalMemory V3 will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.6.17] - 2026-06-21 — Community PR round + dashboard-feedback fix + SQLite tuning
9
+
10
+ Eight community pull requests merged after line-by-line review, plus fixes for the open issues. Every change was validated against the full test suite under the real 3.12 runtime; default single-machine behavior is unchanged.
11
+
12
+ ### Added
13
+
14
+ - **HTTP write-path observability** (PR #52, @barrygfox). The HTTP fast paths (`/observe`, `/remember`, the AutoCapture pipeline, the materializer) now emit `EventBus` events tagged `source_protocol="http"`, so the dashboard event stream is no longer structurally empty. New event types: `memory.observed`, `memory.captured`, `memory.dropped`, `memory.queued`. Emission is best-effort and never affects the caller's response.
15
+ - **Marker-bounded adapter writes** (PR #54, @barrygfox). `CopilotAdapter` now wraps its content in `<!-- SLM-START -->` / `<!-- SLM-END -->` markers and merges into `.github/copilot-instructions.md` instead of overwriting it, preserving user- and agent-curated content. `disable()` strips the SLM block instead of deleting the file. New `hooks/memory_protocol.py` is the shared single source of truth for the marker contract.
16
+
17
+ ### Fixed
18
+
19
+ - **Dashboard feedback was completely broken** (issues #53/#59). The dashboard thumbs-up/down/pin and dwell handlers called `FeedbackCollector.record_dashboard_feedback()` — a method that did not exist, so every write raised `AttributeError` (caught by the route, so no lock leak, but the feature was dead). Implemented the method, mapping the dashboard vocabulary onto stored `(signal_type, value)` pairs; the raw query is hashed, never stored.
20
+ - **NULL columns reloaded as `[]` instead of `None`** (PR #50, @barrygfox). `_jl()` collapsed "no default" and explicit `default=None`, defeating downstream `is None` guards and causing `Mean of empty slice` warnings in the Fisher–Langevin coupling. Fixed with a `_MISSING` sentinel + an empty-array guard.
21
+ - **Lifecycle hooks hard-coded daemon port `:8765`** (PR #51, @barrygfox). Hooks now resolve the port from the per-user `~/.superlocalmemory/daemon.port` file; the non-loopback SSRF guard on `SLM_HOOK_DAEMON_URL` is preserved.
22
+ - **`atomic_write` honored a stale sync-log skip** (PR #55, @barrygfox). The on-disk file is re-hashed before a durable skip, so an out-of-band edit (`git restore`, manual edit) is no longer silently ignored.
23
+ - **Embedding/reranker workers ran single-threaded** (PR #56, @barrygfox). `OMP_NUM_THREADS` is restored in those subprocess workers (which load torch but never lightgbm, so the libomp SIGSEGV cannot occur).
24
+ - **Anthropic provider ignored `api_base`** (PR #57, @barrygfox). The Anthropic backbone now honors a configured base URL (Anthropic-compatible proxy), mirroring the OpenAI provider.
25
+ - **Dashboard screenshot committed as a raw binary** (PR #58, @MelleKoning). Converted to a Git LFS pointer per the existing `.gitattributes` rule.
26
+ - **"Test Connection" blocked for remote dashboards** (issue #40 residue). In `SLM_REMOTE` mode, an allowlisted LAN client may probe its own LAN LLM endpoint, exactly like the loopback dashboard. The SSRF guard is not relaxed for any non-allowlisted caller.
27
+
28
+ ### Changed
29
+
30
+ - **SQLite endurance knobs are env-tunable** (issue #53). `SLM_DB_BUSY_TIMEOUT_MS`, `SLM_DB_MAX_RETRIES`, and `SLM_DB_RETRY_BASE_DELAY` override the defaults for operators on slow/contended I/O. Unset env is byte-identical to the prior hard-coded constants.
31
+ - **`outcome_queue` polling backs off when idle** (issue #53). The drain worker now relaxes its 0.25s poll (doubling, capped at 2s) when the queue drains empty and snaps back to 0.25s the instant there is work, reducing idle contention on the shared SQLite file.
32
+
8
33
  ## [3.6.14] - 2026-06-18 — Audit-hardened: memory bounds, cross-tenant cache isolation, atomic credentials
9
34
 
10
35
  Shipped through two adversarial audit passes (Qualixar Iron Pattern Stages 8–9), validated against a green 5933-test suite under the real 3.12 runtime. Default single-machine behavior is unchanged.
package/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
  <img src="https://superlocalmemory.com/assets/logo-mark.png" alt="SuperLocalMemory" width="200"/>
3
3
  </p>
4
4
 
5
- <h1 align="center">SuperLocalMemory V3.6.16</h1>
5
+ <h1 align="center">SuperLocalMemory V3.6.18</h1>
6
6
  <p align="center"><strong>Cache. Compress. Remember. Three surfaces — proxy, MCP tools, or skill. Every setup covered.</strong><br/>
7
7
  <em>To the best of our knowledge, the only zero-cloud agent memory that beats Mem0's zero-LLM score on LoCoMo. Mode A: 74.8% vs Mem0 64.2% — no GPU, no API key, on CPU.</em></p>
8
- <p align="center"><code>v3.6.16</code> — <strong>Plugin-native. Profile-aware. Distributed-ready.</strong><br/>
8
+ <p align="center"><code>v3.6.18</code> — <strong>Plugin-native. Profile-aware. Distributed-ready.</strong><br/>
9
9
  Proxy: <code>slm wrap claude</code> &nbsp;·&nbsp; MCP: add <code>slm_compress</code> to your config &nbsp;·&nbsp; Skill: zero-config</p>
10
10
  <p align="center"><strong>3 published research papers</strong> (arXiv preprints + Zenodo-archived) · <a href="https://arxiv.org/abs/2603.02240">arXiv:2603.02240</a> · <a href="https://arxiv.org/abs/2603.14588">arXiv:2603.14588</a> · <a href="https://arxiv.org/abs/2604.04514">arXiv:2604.04514</a></p>
11
11
 
@@ -307,6 +307,7 @@ slm dashboard # Opens at http://localhost:8765
307
307
 
308
308
  | Version | Codename | Key Features |
309
309
  |---|---|---|
310
+ | **v3.6.17** | Community | 8 contributor PRs (observability events, marker-bounded adapter writes, daemon port discovery, anthropic `api_base`, OpenMP workers, atomic-write rehash, `_jl` sentinel, LFS pointer); dashboard-feedback fix (#53/#59); env-tunable SQLite knobs + idle backoff; remote LLM test-probe (#40) |
310
311
  | **v3.6.16** | Docs | Corrected Claude Code plugin install — adds the required `/plugin marketplace add` step; clarifies plugin vs pip/npm delivery |
311
312
  | **v3.6.15** | Multi-scope | **Opt-in [shared memory](docs/shared-memory.md)** (personal/shared/global, off by default), default-deny scope at every read path, recall scope-race fix, contributor PRs #42/#43/#44, fixes #46–#49 |
312
313
  | **v3.6.14** | Plugin-native | Claude Code Plugin (WP-06), MCP profiles (WP-01), IDE connect (WP-08), asset consolidation, UI polish (WP-12) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "superlocalmemory",
3
- "version": "3.6.16",
3
+ "version": "3.6.18",
4
4
  "description": "Information-geometric agent memory with mathematical guarantees. 4-channel retrieval, Fisher-Rao similarity, zero-LLM mode, EU AI Act compliant. Works with Claude, Cursor, Windsurf, and 17+ AI tools.",
5
5
  "keywords": [
6
6
  "ai-memory",
@@ -16,5 +16,5 @@
16
16
  "mcpServers": "./.mcp.json",
17
17
  "name": "superlocalmemory",
18
18
  "repository": "https://github.com/qualixar/superlocalmemory",
19
- "version": "3.6.16"
19
+ "version": "3.6.18"
20
20
  }
package/plugin/CLAUDE.md CHANGED
@@ -1,4 +1,4 @@
1
- <!-- BEGIN SuperLocalMemory v3.6.16 -->
1
+ <!-- BEGIN SuperLocalMemory v3.6.18 -->
2
2
 
3
3
  ## SuperLocalMemory (SLM) — Agent Rules
4
4
 
@@ -39,6 +39,6 @@ slm-recall · slm-remember · slm-session · slm-status · slm-cache · slm-comp
39
39
  ### Subagents
40
40
  slm-memory-advisor (memory decisions, session hygiene) · slm-optimize-advisor (context compression + KV cache)
41
41
 
42
- <!-- END SuperLocalMemory v3.6.16 -->
42
+ <!-- END SuperLocalMemory v3.6.18 -->
43
43
 
44
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
44
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -41,4 +41,4 @@ recall→`slm recall "<q>" --limit N` (add `--include-global`/`--include-shared`
41
41
  # What NOT to do
42
42
  Never session_init twice; never forget dry_run=False without reporting preview; never dump a whole file into remember; never invent a memory; never claim "saved" without success:true / clean CLI exit.
43
43
 
44
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
44
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -35,4 +35,4 @@ stats→`slm optimize status`/`savings` · compress→`slm compress` · cache→
35
35
  # What NOT to do
36
36
  Never compress code-for-edit/JSON-to-parse/<500 chars; never store secrets/ccr_ids; never let optimize failure block/alter the task; never claim a specific savings %.
37
37
 
38
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
38
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -1 +1 @@
1
- superlocalmemory==3.6.16
1
+ superlocalmemory==3.6.18
@@ -137,4 +137,4 @@ These subcommands control daemon-level cache settings. They do not read or write
137
137
 
138
138
  ---
139
139
 
140
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
140
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -140,4 +140,4 @@ Content over 1 MB (1 000 000 bytes UTF-8) is processed but `reversible` is force
140
140
 
141
141
  ---
142
142
 
143
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
143
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -297,4 +297,4 @@ Without this, the six graph tools are not registered and will appear as unknown
297
297
 
298
298
  ---
299
299
 
300
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
300
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -201,4 +201,4 @@ trusts that what you surface came from the store.
201
201
 
202
202
  ---
203
203
 
204
- *SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later*
204
+ *SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later*
@@ -191,4 +191,4 @@ slm remember "<content>" --scope shared --shared-with alice,bob
191
191
 
192
192
  ---
193
193
 
194
- *SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later*
194
+ *SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later*
@@ -204,4 +204,4 @@ slm doctor [--json] # preflight check including daemon and embedding worker
204
204
 
205
205
  ---
206
206
 
207
- *SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later*
207
+ *SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later*
@@ -146,4 +146,4 @@ Note: the `slm optimize` subcommands have known pre-existing parse-test failures
146
146
 
147
147
  ---
148
148
 
149
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
149
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -41,4 +41,4 @@ recall→`slm recall "<q>" --limit N` (add `--include-global`/`--include-shared`
41
41
  # What NOT to do
42
42
  Never session_init twice; never forget dry_run=False without reporting preview; never dump a whole file into remember; never invent a memory; never claim "saved" without success:true / clean CLI exit.
43
43
 
44
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
44
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -35,4 +35,4 @@ stats→`slm optimize status`/`savings` · compress→`slm compress` · cache→
35
35
  # What NOT to do
36
36
  Never compress code-for-edit/JSON-to-parse/<500 chars; never store secrets/ccr_ids; never let optimize failure block/alter the task; never claim a specific savings %.
37
37
 
38
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
38
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.6.16",
2
+ "version": "3.6.18",
3
3
  "pluginName": "superlocalmemory",
4
4
  "displayName": "SuperLocalMemory",
5
5
  "repository": "https://github.com/qualixar/superlocalmemory",
@@ -1 +1 @@
1
- superlocalmemory==3.6.16
1
+ superlocalmemory==3.6.18
@@ -88,4 +88,4 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
88
88
  | `slm_cache_get` | `key` | KV cache get; returns hit, value |
89
89
  | `slm_optimize_stats` | `()` | Returns compress_runs, tokens_saved_compress, cache_kv_hits |
90
90
 
91
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
91
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -1,4 +1,4 @@
1
- <!-- BEGIN SuperLocalMemory v3.6.16 -->
1
+ <!-- BEGIN SuperLocalMemory v3.6.18 -->
2
2
 
3
3
  ## SuperLocalMemory (SLM) — Agent Rules
4
4
 
@@ -39,6 +39,6 @@ slm-recall · slm-remember · slm-session · slm-status · slm-cache · slm-comp
39
39
  ### Subagents
40
40
  slm-memory-advisor (memory decisions, session hygiene) · slm-optimize-advisor (context compression + KV cache)
41
41
 
42
- <!-- END SuperLocalMemory v3.6.16 -->
42
+ <!-- END SuperLocalMemory v3.6.18 -->
43
43
 
44
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
44
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -137,4 +137,4 @@ These subcommands control daemon-level cache settings. They do not read or write
137
137
 
138
138
  ---
139
139
 
140
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
140
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -140,4 +140,4 @@ Content over 1 MB (1 000 000 bytes UTF-8) is processed but `reversible` is force
140
140
 
141
141
  ---
142
142
 
143
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
143
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -297,4 +297,4 @@ Without this, the six graph tools are not registered and will appear as unknown
297
297
 
298
298
  ---
299
299
 
300
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
300
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
@@ -201,4 +201,4 @@ trusts that what you surface came from the store.
201
201
 
202
202
  ---
203
203
 
204
- *SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later*
204
+ *SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later*
@@ -191,4 +191,4 @@ slm remember "<content>" --scope shared --shared-with alice,bob
191
191
 
192
192
  ---
193
193
 
194
- *SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later*
194
+ *SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later*
@@ -204,4 +204,4 @@ slm doctor [--json] # preflight check including daemon and embedding worker
204
204
 
205
205
  ---
206
206
 
207
- *SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later*
207
+ *SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later*
@@ -146,4 +146,4 @@ Note: the `slm optimize` subcommands have known pre-existing parse-test failures
146
146
 
147
147
  ---
148
148
 
149
- SuperLocalMemory v3.6.16 · Qualixar · AGPL-3.0-or-later
149
+ SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "superlocalmemory"
3
- version = "3.6.16"
3
+ version = "3.6.18"
4
4
  description = "Information-geometric agent memory with mathematical guarantees"
5
5
  readme = "README.md"
6
6
  license = {text = "AGPL-3.0-or-later"}
@@ -146,8 +146,9 @@ superlocalmemory = ["ui/**/*"]
146
146
  [tool.pytest.ini_options]
147
147
  testpaths = ["tests"]
148
148
  pythonpath = ["src"]
149
- addopts = "-m 'not slow and not ollama and not benchmark'"
149
+ addopts = "-p no:cacheprovider -p no:subtests -m 'not slow and not ollama and not benchmark'"
150
150
  asyncio_mode = "auto"
151
+ faulthandler_timeout = 0
151
152
  markers = [
152
153
  "slow: marks tests as slow — real engine/model loading (run with: pytest -m slow)",
153
154
  "ollama: marks tests that require a running Ollama instance",
@@ -30,7 +30,7 @@ import process from 'node:process';
30
30
  // ---------------------------------------------------------------------------
31
31
  // Constants
32
32
  // ---------------------------------------------------------------------------
33
- const VERSION = '3.6.16';
33
+ const VERSION = '3.6.18';
34
34
  const MANIFEST_REL = 'plugin-src/manifest.json';
35
35
  const GENERATED_BANNER = `# _GENERATED — DO NOT HAND-EDIT
36
36
 
@@ -489,19 +489,99 @@ async function runInteractiveFlow(rl, recommendedProfile) {
489
489
  // under 60 LOC per Stage-8 G2 scope.
490
490
  function printLivingBrainDelta() {
491
491
  console.log('');
492
- console.log('What\'s new in v3.4.21 FINAL:');
493
- console.log(' + Engagement reward model (action_outcomes populated)');
494
- console.log(' + Online LightGBM retrain (shadow-tested, auto-rollback)');
495
- console.log(' + Real consolidation (hnswlib, reversible merges)');
496
- console.log(' + Inline entity detection (<2 ms trigram lookup)');
497
- console.log(' + Opt-in skill evolution (Haiku 4.5 default)');
498
- console.log(' + Evo-Memory public benchmark');
492
+ console.log('What\'s new in v3.6.18:');
493
+ console.log(' + session_init mandate hook Claude calls ToolSearch→session_init first, every session');
494
+ console.log(' + Plugin auto-install on npm/pip install — skills, agents, hooks wired automatically');
495
+ console.log(' + M017 migration — ccq_consolidated_blocks gets scope column (no more silent CCQ scope drop)');
496
+ console.log(' + GC-safe test flags baked into pyproject.toml + Makefile (no more macOS ARM SIGSEGV)');
499
497
  console.log('What\'s unchanged:');
500
498
  console.log(' * Your memory.db — zero deletes, zero rewrites');
501
499
  console.log(' * Your profile settings');
502
500
  console.log(' * All CLI commands you already use');
503
501
  }
504
502
 
503
+ // T1-B: Auto-install the Claude Code plugin after pip/npm install.
504
+ // Best-effort: never fails the installer, never blocks the main flow.
505
+ // Checks for `claude` CLI, then runs:
506
+ // 1. claude plugin marketplace add qualixar/superlocalmemory
507
+ // 2. claude plugin install superlocalmemory@qualixar
508
+ // 3. slm hooks install
509
+ async function tryInstallClaudePlugin() {
510
+ const { execFile } = require('child_process');
511
+ const { promisify } = require('util');
512
+ const execFileAsync = promisify(execFile);
513
+
514
+ // Find claude binary — try PATH first, then common install locations.
515
+ const claudeCandidates = ['claude'];
516
+ if (process.platform !== 'win32') {
517
+ claudeCandidates.push(
518
+ '/usr/local/bin/claude',
519
+ process.env.HOME + '/.npm-global/bin/claude',
520
+ process.env.HOME + '/.local/bin/claude',
521
+ );
522
+ }
523
+
524
+ let claudeBin = null;
525
+ for (const candidate of claudeCandidates) {
526
+ try {
527
+ await execFileAsync(candidate, ['--version'], { timeout: 5000 });
528
+ claudeBin = candidate;
529
+ break;
530
+ } catch (_e) { /* keep looking */ }
531
+ }
532
+
533
+ if (!claudeBin) {
534
+ // Claude Code not installed — print guidance and skip.
535
+ console.log('SLM: Claude Code CLI not found — skipping plugin auto-install.');
536
+ console.log('SLM: To install the plugin manually after installing Claude Code:');
537
+ console.log('SLM: claude plugin marketplace add qualixar/superlocalmemory');
538
+ console.log('SLM: claude plugin install superlocalmemory@qualixar');
539
+ console.log('SLM: slm hooks install');
540
+ return;
541
+ }
542
+
543
+ console.log('SLM: Claude Code found — installing SLM plugin...');
544
+
545
+ // Step 1: Add marketplace
546
+ try {
547
+ await execFileAsync(claudeBin,
548
+ ['plugin', 'marketplace', 'add', 'qualixar/superlocalmemory'],
549
+ { timeout: 30000 });
550
+ console.log('SLM: marketplace added (qualixar/superlocalmemory)');
551
+ } catch (e) {
552
+ // "already exists" or network error — not fatal
553
+ console.log('SLM: marketplace add note: ' + (e.stderr || e.message || String(e)).trim().split('\n')[0]);
554
+ }
555
+
556
+ // Step 2: Install plugin
557
+ try {
558
+ await execFileAsync(claudeBin,
559
+ ['plugin', 'install', 'superlocalmemory@qualixar'],
560
+ { timeout: 30000 });
561
+ console.log('SLM: plugin installed (superlocalmemory@qualixar)');
562
+ } catch (e) {
563
+ console.log('SLM: plugin install note: ' + (e.stderr || e.message || String(e)).trim().split('\n')[0]);
564
+ }
565
+
566
+ // Step 3: Install hooks (only if not already current — avoids needless writes)
567
+ // `slm hooks install` uses atomic tmp-then-rename and only touches the SLM
568
+ // section of settings.json; all other Claude Code settings are preserved.
569
+ try {
570
+ const statusResult = await execFileAsync('slm', ['hooks', 'status', '--json'],
571
+ { timeout: 10000 }).catch(() => null);
572
+ const alreadyCurrent = statusResult &&
573
+ (() => { try { const s = JSON.parse(statusResult.stdout); return s.installed && !s.needs_upgrade; } catch { return false; } })();
574
+ if (!alreadyCurrent) {
575
+ await execFileAsync('slm', ['hooks', 'install'], { timeout: 15000 });
576
+ console.log('SLM: hooks installed into Claude Code settings');
577
+ } else {
578
+ console.log('SLM: hooks already current — skipped');
579
+ }
580
+ } catch (e) {
581
+ console.log('SLM: hooks install note: ' + (e.stderr || e.message || String(e)).trim().split('\n')[0]);
582
+ }
583
+ }
584
+
505
585
  function printFirstRunChecklist(config) {
506
586
  console.log('');
507
587
  console.log('SuperLocalMemory is configured.');
@@ -692,6 +772,13 @@ async function main() {
692
772
 
693
773
  // UX-G2: show the one-screen delta banner so upgraders see what shipped.
694
774
  printLivingBrainDelta();
775
+
776
+ // T1-B: Auto-install Claude Code plugin + hooks. Best-effort, non-blocking.
777
+ // Only runs on npm install (not --dry-run), when claude CLI is present.
778
+ if (!args.dryRun) {
779
+ await tryInstallClaudePlugin();
780
+ }
781
+
695
782
  printFirstRunChecklist(config);
696
783
  return 0;
697
784
  }
@@ -32,7 +32,7 @@ if "OMP_NUM_THREADS" not in os.environ:
32
32
  os.environ["OMP_NUM_THREADS"] = "2"
33
33
  # ---------------------------------------------------------------------------
34
34
 
35
- __version__ = "3.6.16"
35
+ __version__ = "3.6.18"
36
36
 
37
37
  _REQUIRED_VERSIONS = {
38
38
  "sentence_transformers": "5.3.0",
@@ -789,6 +789,40 @@ def _maybe_install_hooks_on_first_use() -> None:
789
789
  # Best-effort: parity-fallback, never block CLI.
790
790
  pass
791
791
 
792
+ # T1-B: Auto-install Claude Code plugin (skills, agents, hooks).
793
+ # Runs after hooks install, best-effort — never blocks CLI startup.
794
+ _try_install_claude_plugin()
795
+
796
+
797
+ def _try_install_claude_plugin() -> None:
798
+ """Auto-install the Claude Code plugin on first pip/uvx SLM install.
799
+
800
+ Runs ``claude plugin marketplace add qualixar/superlocalmemory`` then
801
+ ``claude plugin install superlocalmemory@qualixar`` if the ``claude``
802
+ CLI is found in PATH. Silent on any error — plugin install is a
803
+ convenience, not a hard requirement for SLM to function.
804
+ """
805
+ import shutil
806
+ import subprocess
807
+
808
+ claude = shutil.which("claude")
809
+ if not claude:
810
+ return # Claude Code not in PATH — skip silently
811
+
812
+ _run = lambda cmd: subprocess.run( # noqa: E731
813
+ cmd, capture_output=True, timeout=30, check=False
814
+ )
815
+
816
+ try:
817
+ _run([claude, "plugin", "marketplace", "add", "qualixar/superlocalmemory"])
818
+ except Exception:
819
+ pass
820
+
821
+ try:
822
+ _run([claude, "plugin", "install", "superlocalmemory@qualixar"])
823
+ except Exception:
824
+ pass
825
+
792
826
 
793
827
  # ---------------------------------------------------------------------------
794
828
  # Mode C provider config (preserved from original)
@@ -473,6 +473,11 @@ class EmbeddingService:
473
473
  "TOKENIZERS_PARALLELISM": "false",
474
474
  "TORCH_DEVICE": "cpu",
475
475
  "ORT_DISABLE_COREML": "1",
476
+ # Restore parallel OpenMP. The package caps OMP_NUM_THREADS
477
+ # globally to avoid a torch+lightgbm libomp SIGSEGV in the
478
+ # main process. This worker loads torch but never lightgbm,
479
+ # so there is no collision risk and full parallelism is safe.
480
+ "OMP_NUM_THREADS": str(os.cpu_count() or 4),
476
481
  }
477
482
  from superlocalmemory.core.platform_utils import popen_platform_kwargs
478
483
  self._worker_proc = subprocess.Popen(
@@ -111,6 +111,8 @@ class FisherLangevinCoupling:
111
111
  CouplingState with derived temperature, direction, and weight.
112
112
  """
113
113
  var_arr = np.asarray(fisher_variance, dtype=np.float64)
114
+ if var_arr.size == 0:
115
+ return CouplingState()
114
116
 
115
117
  # Step 1: Fisher confidence from variance
116
118
  # Low variance = high confidence (memory is well-characterized)
@@ -203,6 +205,8 @@ class FisherLangevinCoupling:
203
205
  return self._base_temp
204
206
 
205
207
  var_arr = np.asarray(fisher_variance, dtype=np.float64)
208
+ if var_arr.size == 0:
209
+ return self._base_temp
206
210
  avg_var = float(np.mean(np.clip(var_arr, 1e-8, None)))
207
211
  fisher_conf = min(1.0, 1.0 / (1.0 + avg_var) + min(access_count * 0.02, 0.2))
208
212
  return self._base_temp / (fisher_conf + self._epsilon)
@@ -217,9 +217,16 @@ def atomic_write(
217
217
  prev = sync_log_last_content_sha256(sync_log_db, adapter_name, target_sha)
218
218
 
219
219
  if prev == new_hash and resolved_path.exists():
220
- # Durable skip no write, no new sync-log row (the prior row still
221
- # reflects on-disk truth).
222
- return WriteResult(wrote=False, bytes_written=0, content_sha256=new_hash)
220
+ # Durable skip only if the on-disk content also matches the new hash.
221
+ # The sync-log row alone is not authoritative: the file may have been
222
+ # mutated out-of-band (e.g. ``git restore``, manual edit) since the
223
+ # last sync. Re-hash the file and re-write if it diverges.
224
+ try:
225
+ disk_hash = hashlib.sha256(resolved_path.read_bytes()).hexdigest()
226
+ except OSError:
227
+ disk_hash = None
228
+ if disk_hash == new_hash:
229
+ return WriteResult(wrote=False, bytes_written=0, content_sha256=new_hash)
223
230
 
224
231
  resolved_path.parent.mkdir(parents=True, exist_ok=True)
225
232
  tmp = resolved_path.with_suffix(resolved_path.suffix + ".slm-tmp")
@@ -21,6 +21,7 @@ from __future__ import annotations
21
21
 
22
22
  import json
23
23
  import logging
24
+ import os
24
25
  import sys
25
26
  import tempfile
26
27
  from pathlib import Path
@@ -31,7 +32,7 @@ CLAUDE_SETTINGS = Path.home() / ".claude" / "settings.json"
31
32
  VERSION_DIR = Path.home() / ".superlocalmemory" / "hooks"
32
33
  VERSION_FILE = VERSION_DIR / ".version"
33
34
  DISABLED_FILE = VERSION_DIR / ".hooks-disabled"
34
- HOOKS_VERSION = "3.4.43"
35
+ HOOKS_VERSION = "3.6.18"
35
36
 
36
37
  # Cross-platform temp dir and marker paths
37
38
  _TMP = tempfile.gettempdir()
@@ -92,6 +93,19 @@ def _hook_definitions(include_gate: bool = False) -> dict[str, list]:
92
93
  """
93
94
  defs: dict[str, list] = {
94
95
  "SessionStart": [
96
+ # v3.6.18: mandate fires FIRST so session_init is never skipped.
97
+ # mcp__superlocalmemory__session_init is DEFERRED — Claude must call
98
+ # ToolSearch before it can invoke the tool. Without this hook,
99
+ # Claude responds before loading the schema → no 6-channel memory.
100
+ {
101
+ "hooks": [
102
+ {
103
+ "type": "command",
104
+ "command": _wrap_python_cmd("mandate"),
105
+ "timeout": 5000,
106
+ }
107
+ ]
108
+ },
95
109
  {
96
110
  "hooks": [
97
111
  {
@@ -100,7 +114,7 @@ def _hook_definitions(include_gate: bool = False) -> dict[str, list]:
100
114
  "timeout": 15000,
101
115
  }
102
116
  ]
103
- }
117
+ },
104
118
  ],
105
119
  "PostToolUse": [
106
120
  {
@@ -278,9 +292,31 @@ def _read_settings() -> dict:
278
292
 
279
293
 
280
294
  def _write_settings(settings: dict) -> None:
281
- """Write settings.json with pretty formatting."""
295
+ """Write settings.json atomically tmp file + rename.
296
+
297
+ Direct .write_text() would truncate the file on a crash mid-write,
298
+ destroying the user's entire Claude Code configuration. The tmp-then-rename
299
+ pattern is atomic on POSIX (os.replace) and near-atomic on Windows: either
300
+ the full new content lands or the original file is untouched.
301
+
302
+ Never overwrites non-SLM settings — _merge_hooks() guarantees that only
303
+ the SLM hooks entries change; all other keys are preserved from the read.
304
+ """
282
305
  CLAUDE_SETTINGS.parent.mkdir(parents=True, exist_ok=True)
283
- CLAUDE_SETTINGS.write_text(json.dumps(settings, indent=2) + "\n")
306
+ content = json.dumps(settings, indent=2) + "\n"
307
+ # Write to a sibling tmp file in the same directory so os.replace is atomic
308
+ # (cross-device rename would fail; same-dir rename is guaranteed atomic).
309
+ tmp_path = CLAUDE_SETTINGS.with_suffix(".json.slm_tmp")
310
+ try:
311
+ tmp_path.write_text(content, encoding="utf-8")
312
+ os.replace(tmp_path, CLAUDE_SETTINGS)
313
+ except Exception:
314
+ # Best-effort cleanup of the tmp file on failure
315
+ try:
316
+ tmp_path.unlink(missing_ok=True)
317
+ except Exception:
318
+ pass
319
+ raise
284
320
 
285
321
 
286
322
  # ---------------------------------------------------------------------------