superlocalmemory 3.7.7 → 3.8.0

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 (262) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/ATTRIBUTION.md +1 -3
  3. package/CHANGELOG.md +85 -0
  4. package/README.md +199 -29
  5. package/package.json +4 -2
  6. package/plugin/.claude-plugin/plugin.json +2 -2
  7. package/plugin/CLAUDE.md +8 -8
  8. package/plugin/agents/slm-governance-advisor.md +80 -0
  9. package/plugin/agents/slm-loop-runner.md +71 -0
  10. package/plugin/agents/slm-memory-advisor.md +10 -5
  11. package/plugin/agents/slm-optimize-advisor.md +9 -3
  12. package/plugin/commands/slm-loop.md +31 -0
  13. package/plugin/hooks/hooks.json +79 -0
  14. package/plugin/requirements.txt +1 -1
  15. package/plugin/scripts/slm-launch +46 -7
  16. package/plugin/settings.json +9 -0
  17. package/plugin/skills/slm-cache/SKILL.md +9 -1
  18. package/plugin/skills/slm-compress/SKILL.md +8 -1
  19. package/plugin/skills/slm-governance/SKILL.md +248 -0
  20. package/plugin/skills/slm-graph/SKILL.md +17 -3
  21. package/plugin/skills/slm-loop/SKILL.md +99 -0
  22. package/plugin/skills/slm-mesh/SKILL.md +282 -0
  23. package/plugin/skills/slm-profile/SKILL.md +148 -0
  24. package/plugin/skills/slm-recall/SKILL.md +46 -10
  25. package/plugin/skills/slm-remember/SKILL.md +48 -1
  26. package/plugin/skills/slm-scope/SKILL.md +176 -0
  27. package/plugin/skills/slm-session/SKILL.md +24 -1
  28. package/plugin/skills/slm-status/SKILL.md +18 -1
  29. package/plugin-src/agents/slm-governance-advisor.md +80 -0
  30. package/plugin-src/agents/slm-loop-runner.md +71 -0
  31. package/plugin-src/agents/slm-memory-advisor.md +10 -5
  32. package/plugin-src/agents/slm-optimize-advisor.md +9 -3
  33. package/plugin-src/commands/slm-loop.md +31 -0
  34. package/plugin-src/hooks/hooks.json +79 -0
  35. package/plugin-src/manifest.json +7 -2
  36. package/plugin-src/requirements.txt +1 -1
  37. package/plugin-src/rules/AGENTS.md +57 -18
  38. package/plugin-src/rules/CLAUDE.md.fragment +8 -8
  39. package/plugin-src/scripts/slm-launch +46 -7
  40. package/plugin-src/settings.json +9 -0
  41. package/plugin-src/skills/slm-cache/SKILL.md +9 -1
  42. package/plugin-src/skills/slm-compress/SKILL.md +8 -1
  43. package/plugin-src/skills/slm-governance/SKILL.md +248 -0
  44. package/plugin-src/skills/slm-graph/SKILL.md +17 -3
  45. package/plugin-src/skills/slm-loop/SKILL.md +99 -0
  46. package/plugin-src/skills/slm-mesh/SKILL.md +282 -0
  47. package/plugin-src/skills/slm-profile/SKILL.md +148 -0
  48. package/plugin-src/skills/slm-recall/SKILL.md +46 -10
  49. package/plugin-src/skills/slm-remember/SKILL.md +48 -1
  50. package/plugin-src/skills/slm-scope/SKILL.md +176 -0
  51. package/plugin-src/skills/slm-session/SKILL.md +24 -1
  52. package/plugin-src/skills/slm-status/SKILL.md +18 -1
  53. package/pyproject.toml +1 -2
  54. package/scripts/postinstall/validation.js +2 -0
  55. package/scripts/postinstall-interactive.js +74 -2
  56. package/src/superlocalmemory/__init__.py +1 -1
  57. package/src/superlocalmemory/access/__init__.py +3 -0
  58. package/src/superlocalmemory/access/rbac.py +477 -0
  59. package/src/superlocalmemory/cli/commands.py +96 -12
  60. package/src/superlocalmemory/cli/compress_cmd.py +17 -7
  61. package/src/superlocalmemory/cli/loop_cmd.py +192 -0
  62. package/src/superlocalmemory/cli/main.py +39 -4
  63. package/src/superlocalmemory/cli/mesh_cmd.py +38 -0
  64. package/src/superlocalmemory/cli/optimize_cmd.py +3 -0
  65. package/src/superlocalmemory/cli/pending_store.py +49 -13
  66. package/src/superlocalmemory/cli/proxy_cmd.py +4 -0
  67. package/src/superlocalmemory/cli/scale_engine_cmd.py +6 -0
  68. package/src/superlocalmemory/cli/setup_wizard.py +22 -13
  69. package/src/superlocalmemory/compliance/audit.py +6 -0
  70. package/src/superlocalmemory/compliance/gdpr.py +128 -138
  71. package/src/superlocalmemory/compliance/retention.py +176 -45
  72. package/src/superlocalmemory/core/backend_orchestrator.py +5 -43
  73. package/src/superlocalmemory/core/community_summary.py +267 -0
  74. package/src/superlocalmemory/core/config.py +216 -3
  75. package/src/superlocalmemory/core/consolidation_engine.py +95 -22
  76. package/src/superlocalmemory/core/context_cache.py +61 -18
  77. package/src/superlocalmemory/core/embedding_worker.py +17 -2
  78. package/src/superlocalmemory/core/embeddings.py +12 -1
  79. package/src/superlocalmemory/core/engine.py +17 -1
  80. package/src/superlocalmemory/core/engine_ingestion.py +29 -0
  81. package/src/superlocalmemory/core/engine_wiring.py +13 -0
  82. package/src/superlocalmemory/core/entity_community.py +178 -0
  83. package/src/superlocalmemory/core/graph_analyzer.py +39 -2
  84. package/src/superlocalmemory/core/graph_pruner.py +13 -8
  85. package/src/superlocalmemory/core/key_expander.py +138 -0
  86. package/src/superlocalmemory/core/maintenance.py +23 -0
  87. package/src/superlocalmemory/core/modes.py +1 -1
  88. package/src/superlocalmemory/core/mutations.py +2 -2
  89. package/src/superlocalmemory/core/pii.py +105 -0
  90. package/src/superlocalmemory/core/progressive_abstraction.py +208 -0
  91. package/src/superlocalmemory/core/recall_pipeline.py +2 -0
  92. package/src/superlocalmemory/core/recall_worker.py +20 -6
  93. package/src/superlocalmemory/core/scale_engine.py +60 -1
  94. package/src/superlocalmemory/core/security_primitives.py +40 -2
  95. package/src/superlocalmemory/core/store_pipeline.py +35 -11
  96. package/src/superlocalmemory/core/worker_pool.py +21 -6
  97. package/src/superlocalmemory/encoding/entity_reflexion.py +200 -0
  98. package/src/superlocalmemory/encoding/entity_resolver.py +34 -24
  99. package/src/superlocalmemory/encoding/fact_extractor.py +26 -1
  100. package/src/superlocalmemory/encoding/temporal_validator.py +64 -1
  101. package/src/superlocalmemory/evolution/evolution_store.py +122 -45
  102. package/src/superlocalmemory/evolution/llm_dispatch.py +12 -1
  103. package/src/superlocalmemory/evolution/model_selection.py +160 -0
  104. package/src/superlocalmemory/evolution/mutation_generator.py +16 -0
  105. package/src/superlocalmemory/evolution/skill_evolver.py +127 -42
  106. package/src/superlocalmemory/evolution/triggers.py +22 -13
  107. package/src/superlocalmemory/graph/cozo_backend.py +43 -20
  108. package/src/superlocalmemory/hooks/adapter_base.py +5 -1
  109. package/src/superlocalmemory/hooks/auto_recall.py +13 -1
  110. package/src/superlocalmemory/hooks/claude_code_hooks.py +11 -0
  111. package/src/superlocalmemory/hooks/codex_assets.py +64 -5
  112. package/src/superlocalmemory/hooks/hook_daemon.py +20 -3
  113. package/src/superlocalmemory/hooks/memory_protocol.py +54 -0
  114. package/src/superlocalmemory/hooks/portable_kit.py +114 -1
  115. package/src/superlocalmemory/infra/auth_middleware.py +28 -0
  116. package/src/superlocalmemory/infra/backup.py +12 -1
  117. package/src/superlocalmemory/infra/daemon_identity.py +40 -4
  118. package/src/superlocalmemory/infra/data_root.py +43 -4
  119. package/src/superlocalmemory/infra/event_bus.py +107 -24
  120. package/src/superlocalmemory/infra/rate_limiter.py +93 -0
  121. package/src/superlocalmemory/ingestion/adapter_manager.py +4 -1
  122. package/src/superlocalmemory/ingestion/credentials.py +1 -1
  123. package/src/superlocalmemory/learning/cross_project.py +28 -19
  124. package/src/superlocalmemory/learning/reward_proxy.py +42 -9
  125. package/src/superlocalmemory/loops/__init__.py +56 -0
  126. package/src/superlocalmemory/loops/budget.py +58 -0
  127. package/src/superlocalmemory/loops/engine.py +164 -0
  128. package/src/superlocalmemory/loops/ledger.py +243 -0
  129. package/src/superlocalmemory/loops/models.py +152 -0
  130. package/src/superlocalmemory/loops/rules.py +52 -0
  131. package/src/superlocalmemory/mcp/_daemon_proxy.py +3 -0
  132. package/src/superlocalmemory/mcp/_pool_adapter.py +2 -0
  133. package/src/superlocalmemory/mcp/profiles.py +103 -0
  134. package/src/superlocalmemory/mcp/server.py +21 -49
  135. package/src/superlocalmemory/mcp/tools_active.py +4 -7
  136. package/src/superlocalmemory/mcp/tools_code_graph.py +51 -5
  137. package/src/superlocalmemory/mcp/tools_core.py +50 -5
  138. package/src/superlocalmemory/mcp/tools_evolution.py +6 -3
  139. package/src/superlocalmemory/mcp/tools_loops.py +300 -0
  140. package/src/superlocalmemory/mcp/tools_mesh.py +140 -4
  141. package/src/superlocalmemory/mcp/tools_optimize.py +15 -8
  142. package/src/superlocalmemory/mesh/broker.py +237 -129
  143. package/src/superlocalmemory/mesh/remote_sync.py +50 -8
  144. package/src/superlocalmemory/optimize/NOTICE +1 -6
  145. package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +1 -4
  146. package/src/superlocalmemory/optimize/adapters/openai_adapter.py +1 -4
  147. package/src/superlocalmemory/optimize/cache/semantic.py +27 -19
  148. package/src/superlocalmemory/optimize/compress/align.py +32 -26
  149. package/src/superlocalmemory/optimize/compress/ccr.py +14 -71
  150. package/src/superlocalmemory/optimize/compress/router.py +105 -22
  151. package/src/superlocalmemory/optimize/config/defaults.py +1 -1
  152. package/src/superlocalmemory/optimize/config/schema.py +87 -4
  153. package/src/superlocalmemory/optimize/metrics/counters.py +13 -4
  154. package/src/superlocalmemory/optimize/metrics/estimator.py +0 -3
  155. package/src/superlocalmemory/optimize/proxy/_helpers.py +31 -4
  156. package/src/superlocalmemory/optimize/storage/db.py +38 -9
  157. package/src/superlocalmemory/optimize/storage/schema.py +10 -0
  158. package/src/superlocalmemory/parameterization/pattern_extractor.py +6 -3
  159. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  160. package/src/superlocalmemory/retrieval/bm25_channel.py +68 -10
  161. package/src/superlocalmemory/retrieval/engine.py +168 -26
  162. package/src/superlocalmemory/retrieval/entity_channel.py +7 -5
  163. package/src/superlocalmemory/retrieval/hopfield_channel.py +9 -2
  164. package/src/superlocalmemory/retrieval/semantic_channel.py +114 -21
  165. package/src/superlocalmemory/retrieval/spreading_activation.py +11 -2
  166. package/src/superlocalmemory/retrieval/temporal_channel.py +48 -9
  167. package/src/superlocalmemory/retrieval/temporal_frame.py +102 -0
  168. package/src/superlocalmemory/retrieval/temporal_validity_filter.py +135 -0
  169. package/src/superlocalmemory/retrieval/time_window.py +181 -0
  170. package/src/superlocalmemory/server/api.py +21 -4
  171. package/src/superlocalmemory/server/profile_runtime.py +125 -8
  172. package/src/superlocalmemory/server/rbac_enforce.py +142 -0
  173. package/src/superlocalmemory/server/recall_health.py +24 -3
  174. package/src/superlocalmemory/server/recall_serializer.py +19 -1
  175. package/src/superlocalmemory/server/routes/abstraction.py +115 -0
  176. package/src/superlocalmemory/server/routes/agents.py +128 -38
  177. package/src/superlocalmemory/server/routes/backup.py +34 -10
  178. package/src/superlocalmemory/server/routes/behavioral.py +13 -12
  179. package/src/superlocalmemory/server/routes/brain.py +21 -5
  180. package/src/superlocalmemory/server/routes/chat.py +72 -16
  181. package/src/superlocalmemory/server/routes/compliance.py +171 -21
  182. package/src/superlocalmemory/server/routes/config_api.py +436 -0
  183. package/src/superlocalmemory/server/routes/data_io.py +30 -8
  184. package/src/superlocalmemory/server/routes/entity.py +9 -4
  185. package/src/superlocalmemory/server/routes/events.py +24 -8
  186. package/src/superlocalmemory/server/routes/evolution.py +135 -17
  187. package/src/superlocalmemory/server/routes/helpers.py +16 -1
  188. package/src/superlocalmemory/server/routes/ingest.py +7 -4
  189. package/src/superlocalmemory/server/routes/insights.py +3 -3
  190. package/src/superlocalmemory/server/routes/learning.py +14 -14
  191. package/src/superlocalmemory/server/routes/lifecycle.py +59 -8
  192. package/src/superlocalmemory/server/routes/memories.py +221 -49
  193. package/src/superlocalmemory/server/routes/mesh.py +95 -15
  194. package/src/superlocalmemory/server/routes/optimize.py +33 -1
  195. package/src/superlocalmemory/server/routes/prewarm.py +2 -0
  196. package/src/superlocalmemory/server/routes/profiles.py +63 -17
  197. package/src/superlocalmemory/server/routes/ratelimit.py +124 -0
  198. package/src/superlocalmemory/server/routes/rbac.py +367 -0
  199. package/src/superlocalmemory/server/routes/stats.py +13 -6
  200. package/src/superlocalmemory/server/routes/tiers.py +11 -9
  201. package/src/superlocalmemory/server/routes/v3_api.py +194 -81
  202. package/src/superlocalmemory/server/routes/ws.py +5 -2
  203. package/src/superlocalmemory/server/security_middleware.py +12 -5
  204. package/src/superlocalmemory/server/ui.py +30 -5
  205. package/src/superlocalmemory/server/unified_daemon.py +431 -75
  206. package/src/superlocalmemory/server/write_identity.py +38 -8
  207. package/src/superlocalmemory/storage/database.py +265 -53
  208. package/src/superlocalmemory/storage/migration_runner.py +53 -0
  209. package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +108 -0
  210. package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +86 -0
  211. package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +194 -0
  212. package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +87 -0
  213. package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +90 -0
  214. package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +136 -0
  215. package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +163 -0
  216. package/src/superlocalmemory/storage/models.py +4 -0
  217. package/src/superlocalmemory/storage/schema.py +87 -0
  218. package/src/superlocalmemory/storage/schema_v32.py +0 -9
  219. package/src/superlocalmemory/storage/schema_v343.py +24 -12
  220. package/src/superlocalmemory/trust/gate.py +49 -8
  221. package/src/superlocalmemory/ui/assets/slm-icon-white.svg +64 -0
  222. package/src/superlocalmemory/ui/assets/slm-icon.svg +36 -0
  223. package/src/superlocalmemory/ui/css/design-system.css +621 -0
  224. package/src/superlocalmemory/ui/css/neural-glass.css +6 -0
  225. package/src/superlocalmemory/ui/css/od-bridge.css +158 -0
  226. package/src/superlocalmemory/ui/favicon.svg +35 -4
  227. package/src/superlocalmemory/ui/index.html +306 -173
  228. package/src/superlocalmemory/ui/js/brain.js +5 -20
  229. package/src/superlocalmemory/ui/js/core.js +47 -31
  230. package/src/superlocalmemory/ui/js/dashboard.js +314 -63
  231. package/src/superlocalmemory/ui/js/event-delegation.js +102 -0
  232. package/src/superlocalmemory/ui/js/knowledge-graph.js +11 -11
  233. package/src/superlocalmemory/ui/js/math-health.js +1 -1
  234. package/src/superlocalmemory/ui/js/memories.js +15 -4
  235. package/src/superlocalmemory/ui/js/memory-chat.js +7 -7
  236. package/src/superlocalmemory/ui/js/ng-entities.js +6 -8
  237. package/src/superlocalmemory/ui/js/ng-ingestion.js +4 -4
  238. package/src/superlocalmemory/ui/js/ng-mesh.js +4 -9
  239. package/src/superlocalmemory/ui/js/ng-shell.js +8 -8
  240. package/src/superlocalmemory/ui/js/ng-skills.js +54 -2
  241. package/src/superlocalmemory/ui/js/od-agents.js +544 -0
  242. package/src/superlocalmemory/ui/js/od-auth-gate.js +257 -0
  243. package/src/superlocalmemory/ui/js/od-backup.js +780 -0
  244. package/src/superlocalmemory/ui/js/od-brain.js +779 -0
  245. package/src/superlocalmemory/ui/js/od-entities.js +579 -0
  246. package/src/superlocalmemory/ui/js/od-graph.js +593 -0
  247. package/src/superlocalmemory/ui/js/od-health.js +539 -0
  248. package/src/superlocalmemory/ui/js/od-mcp.js +508 -0
  249. package/src/superlocalmemory/ui/js/od-memories.js +887 -0
  250. package/src/superlocalmemory/ui/js/od-mesh.js +539 -0
  251. package/src/superlocalmemory/ui/js/od-operations.js +1250 -0
  252. package/src/superlocalmemory/ui/js/od-optimize.js +787 -0
  253. package/src/superlocalmemory/ui/js/od-settings.js +1053 -0
  254. package/src/superlocalmemory/ui/js/od-shell.js +593 -0
  255. package/src/superlocalmemory/ui/js/od-skills.js +573 -0
  256. package/src/superlocalmemory/ui/js/od-team.js +258 -0
  257. package/src/superlocalmemory/ui/js/profiles.js +159 -46
  258. package/src/superlocalmemory/ui/js/settings.js +2 -2
  259. package/src/superlocalmemory/ui/js/timeline.js +34 -5
  260. package/src/superlocalmemory/ui/js/trust-dashboard.js +2 -2
  261. package/src/superlocalmemory/vector/lancedb_backend.py +8 -6
  262. package/src/superlocalmemory/learning/behavioral_listener.py +0 -94
@@ -0,0 +1,508 @@
1
+ // Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar — AGPL-3.0
2
+ // od-mcp.js — MCP & Integrations dashboard pane for SuperLocalMemory.
3
+ //
4
+ // Exposes: window.odRenderMcp(pane)
5
+ // Called by the od() shell after it clears the target pane.
6
+ //
7
+ // Endpoint: GET /api/v3/mcp/profiles
8
+ // {
9
+ // current: "core",
10
+ // profiles: {
11
+ // core: { count: 14, tools: [...], description: "..." },
12
+ // code: { count: 24, tools: [...], description: "..." },
13
+ // full: { count: 42, tools: [...], description: "..." },
14
+ // power: { count: 54, tools: [...], description: "..." },
15
+ // mesh: { count: 8, tools: [...], description: "..." },
16
+ // },
17
+ // aliases: { "code21": "code", ... },
18
+ // total_tools: <int>
19
+ // }
20
+ //
21
+ // CSP-safe: no eval(), no on*= attributes, no innerHTML for API data.
22
+ // All user-controlled strings → textContent (XSS-safe).
23
+ // Only static SVG strings use innerHTML (auditable, no API data).
24
+ // Immutable style: EL() always creates new nodes.
25
+
26
+ /* global window, document, slmFetch */
27
+
28
+ (function () {
29
+ 'use strict';
30
+
31
+ // =========================================================================
32
+ // Tiny DOM factory — mirrors od-brain.js EL() pattern
33
+ // =========================================================================
34
+
35
+ function EL(tag, props, kids) {
36
+ var e = document.createElement(tag);
37
+ var p = props || {};
38
+ Object.keys(p).forEach(function (k) {
39
+ if (k === 'className') { e.className = String(p[k]); }
40
+ else if (k === 'text') { e.textContent = p[k] == null ? '' : String(p[k]); }
41
+ else { e.setAttribute(k, String(p[k])); }
42
+ });
43
+ (kids || []).forEach(function (c) { if (c != null) e.appendChild(c); });
44
+ return e;
45
+ }
46
+
47
+ // Inject a child node and return parent (fluent helper)
48
+ function app(parent, child) { parent.appendChild(child); return parent; }
49
+
50
+ // CSS injection — scoped styles for this pane only
51
+ var _stylesId = 'od-mcp-styles';
52
+ function injectStyles() {
53
+ if (document.getElementById(_stylesId)) return;
54
+ var s = document.createElement('style');
55
+ s.id = _stylesId;
56
+ s.textContent = [
57
+ '.od-mcp-intro{font-size:13px;color:var(--fg-2);margin:0 0 16px;line-height:1.55}',
58
+ '.od-mcp-chip{display:inline-flex;align-items:center;',
59
+ 'font-size:11.5px;font-family:var(--mono,monospace);',
60
+ 'background:var(--card-2);border:1px solid var(--border);',
61
+ 'border-radius:6px;padding:2px 8px;margin:3px;color:var(--fg-1)}',
62
+ '.od-mcp-chip-wrap{display:flex;flex-wrap:wrap;margin:-3px;margin-top:8px}',
63
+ '.od-mcp-profile-row{display:flex;align-items:flex-start;gap:12px;',
64
+ 'padding:12px 0;border-bottom:1px solid var(--border)}',
65
+ '.od-mcp-profile-row:last-child{border-bottom:0}',
66
+ '.od-mcp-profile-name{font-weight:650;font-size:14px;min-width:58px}',
67
+ '.od-mcp-profile-desc{font-size:12.5px;color:var(--fg-2);',
68
+ 'flex:1;line-height:1.45;padding-top:1px}',
69
+ '.od-mcp-details{margin-top:6px}',
70
+ '.od-mcp-details summary{font-size:11.5px;color:var(--violet);',
71
+ 'cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:4px}',
72
+ '.od-mcp-details summary::-webkit-details-marker{display:none}',
73
+ '.od-mcp-code{font-family:var(--mono,monospace);font-size:12px;',
74
+ 'background:var(--card-2);border:1px solid var(--border);border-radius:8px;',
75
+ 'padding:10px 14px;margin:8px 0;overflow-x:auto;white-space:pre;',
76
+ 'color:var(--fg-1)}',
77
+ '.od-mcp-step{display:flex;gap:10px;margin:8px 0;align-items:flex-start}',
78
+ '.od-mcp-step-num{width:22px;height:22px;border-radius:50%;',
79
+ 'background:var(--violet);color:#fff;font-size:11px;font-weight:700;',
80
+ 'display:grid;place-items:center;flex-shrink:0;margin-top:1px}',
81
+ '.od-mcp-step-body{font-size:13px;color:var(--fg-1);line-height:1.5;flex:1}',
82
+ '.od-mcp-highlight{color:var(--violet);font-weight:600}',
83
+ '.od-mcp-warn{font-size:12px;color:var(--warn);margin-top:8px;',
84
+ 'display:flex;align-items:flex-start;gap:6px}',
85
+ '.od-mcp-err{padding:20px;text-align:center;color:var(--fg-3);font-size:13px}',
86
+ '.od-mcp-loading{padding:24px;text-align:center;color:var(--fg-3);font-size:13px}',
87
+ ].join('');
88
+ document.head.appendChild(s);
89
+ }
90
+
91
+ // =========================================================================
92
+ // Fetch
93
+ // =========================================================================
94
+
95
+ function apiFetch(path) {
96
+ var fetcher = typeof slmFetch === 'function' ? slmFetch : fetch;
97
+ return fetcher(path, { credentials: 'same-origin' })
98
+ .then(function (r) {
99
+ if (!r.ok) throw new Error('HTTP ' + r.status);
100
+ return r.json();
101
+ });
102
+ }
103
+
104
+ // =========================================================================
105
+ // Helpers
106
+ // =========================================================================
107
+
108
+ // Map profile name → badge class
109
+ var _BADGE_CLASS = {
110
+ core: 'badge',
111
+ code: 'badge ok',
112
+ full: 'badge warn',
113
+ power: 'badge danger',
114
+ mesh: 'badge',
115
+ };
116
+
117
+ function profileBadge(name, count) {
118
+ var b = EL('span', { text: name + ' · ' + count + ' tools' });
119
+ b.className = _BADGE_CLASS[name] || 'badge';
120
+ return b;
121
+ }
122
+
123
+ function toolChips(tools) {
124
+ var wrap = EL('div');
125
+ wrap.className = 'od-mcp-chip-wrap';
126
+ (tools || []).forEach(function (t) {
127
+ var chip = EL('span', { text: t });
128
+ chip.className = 'od-mcp-chip';
129
+ wrap.appendChild(chip);
130
+ });
131
+ return wrap;
132
+ }
133
+
134
+ // Static "plug" SVG icon (no API data, safe for innerHTML)
135
+ var PLUG_SVG = '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" ' +
136
+ 'stroke="currentColor" stroke-width="1.75" stroke-linecap="round" ' +
137
+ 'stroke-linejoin="round" aria-hidden="true">' +
138
+ '<path d="M12 22V12M5 12V2l3 3 4-4 4 4 3-3v10"/>' +
139
+ '<path d="M5 12a7 7 0 0 0 14 0"/></svg>';
140
+
141
+ var SETTINGS_SVG = '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" ' +
142
+ 'stroke="currentColor" stroke-width="1.75" stroke-linecap="round" ' +
143
+ 'stroke-linejoin="round" aria-hidden="true">' +
144
+ '<circle cx="12" cy="12" r="3"/>' +
145
+ '<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06' +
146
+ 'a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09' +
147
+ 'A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06' +
148
+ 'A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09' +
149
+ 'A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06' +
150
+ 'A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09' +
151
+ 'a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06' +
152
+ 'A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09' +
153
+ 'a1.65 1.65 0 0 0-1.51 1z"/></svg>';
154
+
155
+ // =========================================================================
156
+ // Build: intro paragraph
157
+ // =========================================================================
158
+
159
+ function buildIntro() {
160
+ var p = EL('p');
161
+ p.className = 'od-mcp-intro';
162
+ p.textContent =
163
+ 'MCP tools are what your AI agents (Claude Code, Codex, Cursor, Windsurf, …) ' +
164
+ 'can call. Your active profile controls how many tools are exposed over the ' +
165
+ 'MCP connection. Fewer tools keeps context lean; more tools gives agents ' +
166
+ 'deeper capabilities.';
167
+ return p;
168
+ }
169
+
170
+ // =========================================================================
171
+ // Build: current profile card
172
+ // =========================================================================
173
+
174
+ function buildCurrentCard(data) {
175
+ var current = data.current || 'core';
176
+ var info = (data.profiles || {})[current] || {};
177
+ var count = info.count || 0;
178
+ var tools = info.tools || [];
179
+ var desc = info.description || '';
180
+
181
+ var wrap = EL('div');
182
+ wrap.className = 'card';
183
+ wrap.style.marginBottom = '16px';
184
+
185
+ // card-head
186
+ var head = EL('div');
187
+ head.className = 'card-head';
188
+ var ic = EL('span');
189
+ ic.style.cssText = 'color:var(--violet);width:18px;height:18px;display:flex;flex-shrink:0';
190
+ ic.innerHTML = PLUG_SVG; // static SVG, no API data
191
+ head.appendChild(ic);
192
+ head.appendChild(EL('h3', { text: 'Active MCP profile' }));
193
+ head.appendChild(profileBadge(current, count));
194
+ wrap.appendChild(head);
195
+
196
+ // card-pad
197
+ var body = EL('div');
198
+ body.className = 'card-pad';
199
+
200
+ var descRow = EL('p', { text: desc });
201
+ descRow.style.cssText = 'font-size:13px;color:var(--fg-2);margin:0 0 6px';
202
+ body.appendChild(descRow);
203
+
204
+ var envNote = EL('p');
205
+ envNote.className = 'muted';
206
+ envNote.style.fontSize = '12px';
207
+ // Build using textContent + appendChild to keep CSP-safe
208
+ var envLabel = document.createTextNode('Set via ');
209
+ var envCode = EL('code', { text: 'SLM_MCP_PROFILE=' + current });
210
+ envCode.style.cssText = 'font-family:var(--mono,monospace);' +
211
+ 'background:var(--card-2);padding:1px 5px;border-radius:4px;font-size:11.5px';
212
+ var envSuffix = document.createTextNode(' in your IDE\'s MCP config.');
213
+ envNote.appendChild(envLabel);
214
+ envNote.appendChild(envCode);
215
+ envNote.appendChild(envSuffix);
216
+ body.appendChild(envNote);
217
+
218
+ if (tools.length > 0) {
219
+ var toolLabel = EL('div', { text: count + ' tools in this profile:' });
220
+ toolLabel.style.cssText = 'font-size:11.5px;color:var(--fg-3);margin-top:10px;margin-bottom:2px';
221
+ body.appendChild(toolLabel);
222
+ body.appendChild(toolChips(tools));
223
+ }
224
+
225
+ wrap.appendChild(body);
226
+ return wrap;
227
+ }
228
+
229
+ // =========================================================================
230
+ // Build: available profiles comparison card
231
+ // =========================================================================
232
+
233
+ var _PROFILE_ORDER = ['core', 'code', 'full', 'power', 'mesh'];
234
+
235
+ function buildProfilesCard(data) {
236
+ var profiles = data.profiles || {};
237
+ var current = data.current || 'core';
238
+
239
+ var wrap = EL('div');
240
+ wrap.className = 'card';
241
+ wrap.style.marginBottom = '16px';
242
+
243
+ // card-head
244
+ var head = EL('div');
245
+ head.className = 'card-head';
246
+ var ic = EL('span');
247
+ ic.style.cssText = 'color:var(--violet);width:18px;height:18px;display:flex;flex-shrink:0';
248
+ ic.innerHTML = SETTINGS_SVG; // static SVG, no API data
249
+ head.appendChild(ic);
250
+ head.appendChild(EL('h3', { text: 'Available profiles' }));
251
+ var totalBadge = EL('span', { text: String(data.total_tools || 0) + ' total tools' });
252
+ totalBadge.className = 'badge';
253
+ head.appendChild(totalBadge);
254
+ wrap.appendChild(head);
255
+
256
+ // card-pad: one row per profile
257
+ var body = EL('div');
258
+ body.className = 'card-pad';
259
+
260
+ _PROFILE_ORDER.forEach(function (name) {
261
+ var info = profiles[name];
262
+ if (!info) return;
263
+
264
+ var row = EL('div');
265
+ row.className = 'od-mcp-profile-row';
266
+
267
+ // Name + active indicator
268
+ var nameWrap = EL('div');
269
+ nameWrap.style.minWidth = '76px';
270
+ var nameEl = EL('span', { text: name });
271
+ nameEl.className = 'od-mcp-profile-name';
272
+ nameWrap.appendChild(nameEl);
273
+ if (name === current) {
274
+ var activeTag = EL('span', { text: 'active' });
275
+ activeTag.className = 'badge ok';
276
+ activeTag.style.cssText = 'font-size:10px;margin-left:4px;vertical-align:middle';
277
+ nameWrap.appendChild(activeTag);
278
+ }
279
+ row.appendChild(nameWrap);
280
+
281
+ // Description + collapsible tool list
282
+ var rightCol = EL('div');
283
+ rightCol.style.flex = '1';
284
+
285
+ var descEl = EL('div', { text: info.description || '' });
286
+ descEl.className = 'od-mcp-profile-desc';
287
+ rightCol.appendChild(descEl);
288
+
289
+ // Count badge
290
+ var countBadge = EL('span', { text: String(info.count) + ' tools' });
291
+ countBadge.className = 'badge';
292
+ countBadge.style.cssText = 'font-size:10.5px;margin:4px 0 2px;display:inline-flex';
293
+ rightCol.appendChild(countBadge);
294
+
295
+ // Expandable tool list — native <details> (CSP-safe, no JS needed)
296
+ if (info.tools && info.tools.length > 0) {
297
+ var det = document.createElement('details');
298
+ det.className = 'od-mcp-details';
299
+ var summ = document.createElement('summary');
300
+ // Arrow text nodes: collapsed = ▶, expanded via CSS :open won't work here,
301
+ // use a text node that we update via the toggle event (CSP-safe)
302
+ var summText = document.createTextNode('Show tools ▾');
303
+ summ.appendChild(summText);
304
+ det.appendChild(summ);
305
+ det.appendChild(toolChips(info.tools));
306
+ det.addEventListener('toggle', function () {
307
+ summText.nodeValue = det.open ? 'Hide tools ▴' : 'Show tools ▾';
308
+ });
309
+ rightCol.appendChild(det);
310
+ }
311
+
312
+ row.appendChild(rightCol);
313
+ body.appendChild(row);
314
+ });
315
+
316
+ wrap.appendChild(body);
317
+ return wrap;
318
+ }
319
+
320
+ // =========================================================================
321
+ // Build: how-to-change card
322
+ // =========================================================================
323
+
324
+ function buildHowToCard() {
325
+ var wrap = EL('div');
326
+ wrap.className = 'card';
327
+ wrap.style.marginBottom = '16px';
328
+
329
+ var head = EL('div');
330
+ head.className = 'card-head';
331
+ head.appendChild(EL('h3', { text: 'How to change your profile' }));
332
+ wrap.appendChild(head);
333
+
334
+ var body = EL('div');
335
+ body.className = 'card-pad';
336
+
337
+ // Step 1
338
+ var step1 = EL('div');
339
+ step1.className = 'od-mcp-step';
340
+ var num1 = EL('div', { text: '1' });
341
+ num1.className = 'od-mcp-step-num';
342
+ var body1 = EL('div');
343
+ body1.className = 'od-mcp-step-body';
344
+ var b1text1 = document.createTextNode('Open your IDE\'s MCP server config (usually ');
345
+ var b1code = EL('code', { text: '.mcp.json' });
346
+ b1code.style.cssText = 'font-family:var(--mono,monospace);' +
347
+ 'background:var(--card-2);padding:1px 5px;border-radius:4px;font-size:11.5px';
348
+ var b1text2 = document.createTextNode(' or the MCP settings panel).');
349
+ body1.appendChild(b1text1);
350
+ body1.appendChild(b1code);
351
+ body1.appendChild(b1text2);
352
+ step1.appendChild(num1);
353
+ step1.appendChild(body1);
354
+ body.appendChild(step1);
355
+
356
+ // Step 2 with example snippets for all profiles
357
+ var step2 = EL('div');
358
+ step2.className = 'od-mcp-step';
359
+ var num2 = EL('div', { text: '2' });
360
+ num2.className = 'od-mcp-step-num';
361
+ var body2 = EL('div');
362
+ body2.className = 'od-mcp-step-body';
363
+ body2.appendChild(document.createTextNode(
364
+ 'Add or update the environment variable for the superlocalmemory server entry:'
365
+ ));
366
+
367
+ var codeBlock = EL('div');
368
+ codeBlock.className = 'od-mcp-code';
369
+ // Use textContent — no API data, just static example strings
370
+ codeBlock.textContent =
371
+ '"env": {\n' +
372
+ ' "SLM_MCP_PROFILE": "core" // 14 tools — minimal\n' +
373
+ ' // "SLM_MCP_PROFILE": "code" // 24 tools — + code graph + loops\n' +
374
+ ' // "SLM_MCP_PROFILE": "full" // 42 tools — + mesh\n' +
375
+ ' // "SLM_MCP_PROFILE": "power" // 54 tools — + governance\n' +
376
+ ' // "SLM_MCP_PROFILE": "mesh" // 8 tools — mesh only\n' +
377
+ '}';
378
+ body2.appendChild(codeBlock);
379
+ step2.appendChild(num2);
380
+ step2.appendChild(body2);
381
+ body.appendChild(step2);
382
+
383
+ // Step 3
384
+ var step3 = EL('div');
385
+ step3.className = 'od-mcp-step';
386
+ var num3 = EL('div', { text: '3' });
387
+ num3.className = 'od-mcp-step-num';
388
+ var body3 = EL('div', {
389
+ text: 'Restart the IDE\'s MCP client (close and reopen the project, ' +
390
+ 'or use the IDE\'s "Reload MCP" command). The daemon itself does not ' +
391
+ 'need to restart.'
392
+ });
393
+ body3.className = 'od-mcp-step-body';
394
+ step3.appendChild(num3);
395
+ step3.appendChild(body3);
396
+ body.appendChild(step3);
397
+
398
+ // Honest caveat
399
+ var warn = EL('div');
400
+ warn.className = 'od-mcp-warn';
401
+ var warnIcon = EL('span', { text: '⚠️' });
402
+ warnIcon.setAttribute('aria-hidden', 'true');
403
+ var warnText = EL('span');
404
+ warnText.textContent =
405
+ 'Profile selection is per-IDE MCP config, not a live daemon toggle. ' +
406
+ 'Different IDEs (Claude Code, Cursor, Windsurf) each have their own ' +
407
+ 'MCP config and can use different profiles simultaneously.';
408
+ warn.appendChild(warnIcon);
409
+ warn.appendChild(warnText);
410
+ body.appendChild(warn);
411
+
412
+ // Docs link
413
+ var docsRow = EL('p');
414
+ docsRow.style.cssText = 'font-size:12.5px;margin-top:10px;color:var(--fg-2)';
415
+ var docsText = document.createTextNode('Full documentation: ');
416
+ var docsLink = EL('a', {
417
+ href: 'https://qualixar.com/docs/slm/mcp-profiles',
418
+ target: '_blank',
419
+ rel: 'noopener noreferrer',
420
+ text: 'qualixar.com/docs/slm/mcp-profiles'
421
+ });
422
+ docsLink.style.color = 'var(--violet)';
423
+ docsRow.appendChild(docsText);
424
+ docsRow.appendChild(docsLink);
425
+ body.appendChild(docsRow);
426
+
427
+ wrap.appendChild(body);
428
+ return wrap;
429
+ }
430
+
431
+ // =========================================================================
432
+ // Loading and error state helpers (self-contained — no containerId needed)
433
+ // =========================================================================
434
+
435
+ function buildLoading() {
436
+ var d = EL('div');
437
+ d.className = 'od-mcp-loading';
438
+ d.textContent = 'Loading MCP profile data…';
439
+ return d;
440
+ }
441
+
442
+ function buildError(message, onRetry) {
443
+ var d = EL('div');
444
+ d.className = 'od-mcp-err';
445
+ var icon = EL('div', { text: '⚠️' });
446
+ icon.style.fontSize = '24px';
447
+ d.appendChild(icon);
448
+ var msg = EL('p', { text: message || 'Could not load MCP profiles.' });
449
+ msg.style.margin = '8px 0';
450
+ d.appendChild(msg);
451
+ if (typeof onRetry === 'function') {
452
+ var btn = EL('button', { type: 'button', text: 'Retry' });
453
+ btn.className = 'btn ghost sm';
454
+ btn.addEventListener('click', onRetry);
455
+ d.appendChild(btn);
456
+ }
457
+ return d;
458
+ }
459
+
460
+ // =========================================================================
461
+ // Main render
462
+ // =========================================================================
463
+
464
+ window.odRenderMcp = function (pane) {
465
+ if (!pane) return;
466
+ injectStyles();
467
+
468
+ // Show loading state immediately
469
+ pane.textContent = '';
470
+ pane.appendChild(buildLoading());
471
+
472
+ apiFetch('/api/v3/mcp/profiles')
473
+ .then(function (data) {
474
+ pane.textContent = '';
475
+
476
+ // Root wrapper
477
+ var root = EL('div', { id: 'od-mcp-root' });
478
+ root.style.cssText = 'padding:26px;max-width:860px';
479
+
480
+ // Page heading
481
+ var pageHead = EL('div');
482
+ pageHead.className = 'page-head';
483
+ pageHead.appendChild(EL('h2', { text: 'MCP & Integrations' }));
484
+ root.appendChild(pageHead);
485
+
486
+ root.appendChild(buildIntro());
487
+ root.appendChild(buildCurrentCard(data));
488
+ root.appendChild(buildProfilesCard(data));
489
+ root.appendChild(buildHowToCard());
490
+
491
+ pane.appendChild(root);
492
+ })
493
+ .catch(function (err) {
494
+ pane.textContent = '';
495
+ pane.appendChild(buildError(
496
+ 'Could not load MCP profile data. Is the daemon running?',
497
+ function () { window.odRenderMcp(pane); }
498
+ ));
499
+ });
500
+ };
501
+
502
+ // Auto-run at DOMContentLoaded if the pane already exists in DOM
503
+ document.addEventListener('DOMContentLoaded', function () {
504
+ var pane = document.getElementById('mcp-pane');
505
+ if (pane) window.odRenderMcp(pane);
506
+ });
507
+
508
+ }());