superlocalmemory 3.7.8 → 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.
- package/.claude-plugin/marketplace.json +1 -1
- package/ATTRIBUTION.md +1 -3
- package/CHANGELOG.md +69 -0
- package/README.md +199 -29
- package/package.json +4 -2
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/CLAUDE.md +8 -8
- package/plugin/agents/slm-governance-advisor.md +80 -0
- package/plugin/agents/slm-loop-runner.md +71 -0
- package/plugin/agents/slm-memory-advisor.md +10 -5
- package/plugin/agents/slm-optimize-advisor.md +9 -3
- package/plugin/commands/slm-loop.md +31 -0
- package/plugin/hooks/hooks.json +79 -0
- package/plugin/requirements.txt +1 -1
- package/plugin/scripts/slm-launch +46 -7
- package/plugin/settings.json +9 -0
- package/plugin/skills/slm-cache/SKILL.md +9 -1
- package/plugin/skills/slm-compress/SKILL.md +8 -1
- package/plugin/skills/slm-governance/SKILL.md +248 -0
- package/plugin/skills/slm-graph/SKILL.md +17 -3
- package/plugin/skills/slm-loop/SKILL.md +99 -0
- package/plugin/skills/slm-mesh/SKILL.md +282 -0
- package/plugin/skills/slm-profile/SKILL.md +148 -0
- package/plugin/skills/slm-recall/SKILL.md +46 -10
- package/plugin/skills/slm-remember/SKILL.md +48 -1
- package/plugin/skills/slm-scope/SKILL.md +176 -0
- package/plugin/skills/slm-session/SKILL.md +24 -1
- package/plugin/skills/slm-status/SKILL.md +18 -1
- package/plugin-src/agents/slm-governance-advisor.md +80 -0
- package/plugin-src/agents/slm-loop-runner.md +71 -0
- package/plugin-src/agents/slm-memory-advisor.md +10 -5
- package/plugin-src/agents/slm-optimize-advisor.md +9 -3
- package/plugin-src/commands/slm-loop.md +31 -0
- package/plugin-src/hooks/hooks.json +79 -0
- package/plugin-src/manifest.json +7 -2
- package/plugin-src/requirements.txt +1 -1
- package/plugin-src/rules/AGENTS.md +57 -18
- package/plugin-src/rules/CLAUDE.md.fragment +8 -8
- package/plugin-src/scripts/slm-launch +46 -7
- package/plugin-src/settings.json +9 -0
- package/plugin-src/skills/slm-cache/SKILL.md +9 -1
- package/plugin-src/skills/slm-compress/SKILL.md +8 -1
- package/plugin-src/skills/slm-governance/SKILL.md +248 -0
- package/plugin-src/skills/slm-graph/SKILL.md +17 -3
- package/plugin-src/skills/slm-loop/SKILL.md +99 -0
- package/plugin-src/skills/slm-mesh/SKILL.md +282 -0
- package/plugin-src/skills/slm-profile/SKILL.md +148 -0
- package/plugin-src/skills/slm-recall/SKILL.md +46 -10
- package/plugin-src/skills/slm-remember/SKILL.md +48 -1
- package/plugin-src/skills/slm-scope/SKILL.md +176 -0
- package/plugin-src/skills/slm-session/SKILL.md +24 -1
- package/plugin-src/skills/slm-status/SKILL.md +18 -1
- package/pyproject.toml +1 -1
- package/scripts/postinstall/validation.js +2 -0
- package/scripts/postinstall-interactive.js +74 -2
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/access/__init__.py +3 -0
- package/src/superlocalmemory/access/rbac.py +477 -0
- package/src/superlocalmemory/cli/commands.py +94 -10
- package/src/superlocalmemory/cli/compress_cmd.py +17 -7
- package/src/superlocalmemory/cli/loop_cmd.py +192 -0
- package/src/superlocalmemory/cli/main.py +39 -4
- package/src/superlocalmemory/cli/mesh_cmd.py +38 -0
- package/src/superlocalmemory/cli/optimize_cmd.py +3 -0
- package/src/superlocalmemory/cli/pending_store.py +49 -13
- package/src/superlocalmemory/cli/proxy_cmd.py +4 -0
- package/src/superlocalmemory/cli/scale_engine_cmd.py +6 -0
- package/src/superlocalmemory/cli/setup_wizard.py +22 -13
- package/src/superlocalmemory/compliance/audit.py +6 -0
- package/src/superlocalmemory/compliance/gdpr.py +128 -138
- package/src/superlocalmemory/compliance/retention.py +176 -45
- package/src/superlocalmemory/core/backend_orchestrator.py +5 -43
- package/src/superlocalmemory/core/community_summary.py +267 -0
- package/src/superlocalmemory/core/config.py +216 -3
- package/src/superlocalmemory/core/consolidation_engine.py +95 -22
- package/src/superlocalmemory/core/context_cache.py +61 -18
- package/src/superlocalmemory/core/embedding_worker.py +17 -2
- package/src/superlocalmemory/core/embeddings.py +12 -1
- package/src/superlocalmemory/core/engine.py +17 -1
- package/src/superlocalmemory/core/engine_ingestion.py +29 -0
- package/src/superlocalmemory/core/engine_wiring.py +13 -0
- package/src/superlocalmemory/core/entity_community.py +178 -0
- package/src/superlocalmemory/core/graph_analyzer.py +39 -2
- package/src/superlocalmemory/core/graph_pruner.py +13 -8
- package/src/superlocalmemory/core/key_expander.py +138 -0
- package/src/superlocalmemory/core/maintenance.py +23 -0
- package/src/superlocalmemory/core/modes.py +1 -1
- package/src/superlocalmemory/core/mutations.py +2 -2
- package/src/superlocalmemory/core/pii.py +105 -0
- package/src/superlocalmemory/core/progressive_abstraction.py +208 -0
- package/src/superlocalmemory/core/recall_pipeline.py +2 -0
- package/src/superlocalmemory/core/recall_worker.py +20 -6
- package/src/superlocalmemory/core/scale_engine.py +60 -1
- package/src/superlocalmemory/core/security_primitives.py +40 -2
- package/src/superlocalmemory/core/store_pipeline.py +35 -11
- package/src/superlocalmemory/core/worker_pool.py +21 -6
- package/src/superlocalmemory/encoding/entity_reflexion.py +200 -0
- package/src/superlocalmemory/encoding/entity_resolver.py +34 -24
- package/src/superlocalmemory/encoding/fact_extractor.py +26 -1
- package/src/superlocalmemory/encoding/temporal_validator.py +64 -1
- package/src/superlocalmemory/evolution/evolution_store.py +122 -45
- package/src/superlocalmemory/evolution/llm_dispatch.py +12 -1
- package/src/superlocalmemory/evolution/model_selection.py +160 -0
- package/src/superlocalmemory/evolution/mutation_generator.py +16 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +127 -42
- package/src/superlocalmemory/evolution/triggers.py +22 -13
- package/src/superlocalmemory/graph/cozo_backend.py +43 -20
- package/src/superlocalmemory/hooks/adapter_base.py +5 -1
- package/src/superlocalmemory/hooks/auto_recall.py +13 -1
- package/src/superlocalmemory/hooks/claude_code_hooks.py +11 -0
- package/src/superlocalmemory/hooks/codex_assets.py +64 -5
- package/src/superlocalmemory/hooks/hook_daemon.py +20 -3
- package/src/superlocalmemory/hooks/memory_protocol.py +54 -0
- package/src/superlocalmemory/hooks/portable_kit.py +114 -1
- package/src/superlocalmemory/infra/backup.py +12 -1
- package/src/superlocalmemory/infra/daemon_identity.py +40 -4
- package/src/superlocalmemory/infra/data_root.py +43 -4
- package/src/superlocalmemory/infra/event_bus.py +107 -24
- package/src/superlocalmemory/infra/rate_limiter.py +93 -0
- package/src/superlocalmemory/ingestion/adapter_manager.py +4 -1
- package/src/superlocalmemory/ingestion/credentials.py +1 -1
- package/src/superlocalmemory/learning/cross_project.py +28 -19
- package/src/superlocalmemory/learning/reward_proxy.py +42 -9
- package/src/superlocalmemory/loops/__init__.py +56 -0
- package/src/superlocalmemory/loops/budget.py +58 -0
- package/src/superlocalmemory/loops/engine.py +164 -0
- package/src/superlocalmemory/loops/ledger.py +243 -0
- package/src/superlocalmemory/loops/models.py +152 -0
- package/src/superlocalmemory/loops/rules.py +52 -0
- package/src/superlocalmemory/mcp/_daemon_proxy.py +3 -0
- package/src/superlocalmemory/mcp/_pool_adapter.py +2 -0
- package/src/superlocalmemory/mcp/profiles.py +103 -0
- package/src/superlocalmemory/mcp/server.py +21 -49
- package/src/superlocalmemory/mcp/tools_active.py +4 -7
- package/src/superlocalmemory/mcp/tools_code_graph.py +51 -5
- package/src/superlocalmemory/mcp/tools_core.py +8 -1
- package/src/superlocalmemory/mcp/tools_evolution.py +6 -3
- package/src/superlocalmemory/mcp/tools_loops.py +300 -0
- package/src/superlocalmemory/mcp/tools_mesh.py +140 -4
- package/src/superlocalmemory/mcp/tools_optimize.py +15 -8
- package/src/superlocalmemory/mesh/broker.py +237 -129
- package/src/superlocalmemory/mesh/remote_sync.py +50 -8
- package/src/superlocalmemory/optimize/NOTICE +1 -6
- package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +1 -4
- package/src/superlocalmemory/optimize/adapters/openai_adapter.py +1 -4
- package/src/superlocalmemory/optimize/cache/semantic.py +27 -19
- package/src/superlocalmemory/optimize/compress/align.py +32 -26
- package/src/superlocalmemory/optimize/compress/ccr.py +14 -71
- package/src/superlocalmemory/optimize/compress/router.py +105 -22
- package/src/superlocalmemory/optimize/config/defaults.py +1 -1
- package/src/superlocalmemory/optimize/config/schema.py +87 -4
- package/src/superlocalmemory/optimize/metrics/counters.py +13 -4
- package/src/superlocalmemory/optimize/metrics/estimator.py +0 -3
- package/src/superlocalmemory/optimize/proxy/_helpers.py +31 -4
- package/src/superlocalmemory/optimize/storage/db.py +38 -9
- package/src/superlocalmemory/optimize/storage/schema.py +10 -0
- package/src/superlocalmemory/parameterization/pattern_extractor.py +6 -3
- package/src/superlocalmemory/retrieval/agentic.py +1 -1
- package/src/superlocalmemory/retrieval/bm25_channel.py +68 -10
- package/src/superlocalmemory/retrieval/engine.py +168 -26
- package/src/superlocalmemory/retrieval/entity_channel.py +7 -5
- package/src/superlocalmemory/retrieval/hopfield_channel.py +9 -2
- package/src/superlocalmemory/retrieval/semantic_channel.py +114 -21
- package/src/superlocalmemory/retrieval/spreading_activation.py +11 -2
- package/src/superlocalmemory/retrieval/temporal_channel.py +48 -9
- package/src/superlocalmemory/retrieval/temporal_frame.py +102 -0
- package/src/superlocalmemory/retrieval/temporal_validity_filter.py +135 -0
- package/src/superlocalmemory/retrieval/time_window.py +181 -0
- package/src/superlocalmemory/server/api.py +4 -4
- package/src/superlocalmemory/server/profile_runtime.py +125 -8
- package/src/superlocalmemory/server/rbac_enforce.py +142 -0
- package/src/superlocalmemory/server/recall_health.py +24 -3
- package/src/superlocalmemory/server/recall_serializer.py +19 -1
- package/src/superlocalmemory/server/routes/abstraction.py +115 -0
- package/src/superlocalmemory/server/routes/agents.py +128 -38
- package/src/superlocalmemory/server/routes/backup.py +34 -10
- package/src/superlocalmemory/server/routes/behavioral.py +13 -12
- package/src/superlocalmemory/server/routes/brain.py +21 -5
- package/src/superlocalmemory/server/routes/chat.py +10 -5
- package/src/superlocalmemory/server/routes/compliance.py +171 -21
- package/src/superlocalmemory/server/routes/config_api.py +436 -0
- package/src/superlocalmemory/server/routes/data_io.py +30 -8
- package/src/superlocalmemory/server/routes/entity.py +9 -4
- package/src/superlocalmemory/server/routes/events.py +24 -8
- package/src/superlocalmemory/server/routes/evolution.py +135 -17
- package/src/superlocalmemory/server/routes/helpers.py +16 -1
- package/src/superlocalmemory/server/routes/ingest.py +7 -4
- package/src/superlocalmemory/server/routes/insights.py +3 -3
- package/src/superlocalmemory/server/routes/learning.py +14 -14
- package/src/superlocalmemory/server/routes/lifecycle.py +59 -8
- package/src/superlocalmemory/server/routes/memories.py +182 -57
- package/src/superlocalmemory/server/routes/mesh.py +95 -15
- package/src/superlocalmemory/server/routes/optimize.py +33 -1
- package/src/superlocalmemory/server/routes/prewarm.py +2 -0
- package/src/superlocalmemory/server/routes/profiles.py +63 -17
- package/src/superlocalmemory/server/routes/ratelimit.py +124 -0
- package/src/superlocalmemory/server/routes/rbac.py +367 -0
- package/src/superlocalmemory/server/routes/stats.py +13 -6
- package/src/superlocalmemory/server/routes/tiers.py +11 -9
- package/src/superlocalmemory/server/routes/v3_api.py +183 -69
- package/src/superlocalmemory/server/routes/ws.py +5 -2
- package/src/superlocalmemory/server/security_middleware.py +12 -5
- package/src/superlocalmemory/server/ui.py +20 -5
- package/src/superlocalmemory/server/unified_daemon.py +384 -56
- package/src/superlocalmemory/server/write_identity.py +38 -8
- package/src/superlocalmemory/storage/database.py +265 -53
- package/src/superlocalmemory/storage/migration_runner.py +53 -0
- package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +108 -0
- package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +86 -0
- package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +194 -0
- package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +87 -0
- package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +90 -0
- package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +136 -0
- package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +163 -0
- package/src/superlocalmemory/storage/models.py +4 -0
- package/src/superlocalmemory/storage/schema.py +87 -0
- package/src/superlocalmemory/storage/schema_v343.py +24 -12
- package/src/superlocalmemory/trust/gate.py +49 -8
- package/src/superlocalmemory/ui/assets/slm-icon-white.svg +64 -0
- package/src/superlocalmemory/ui/assets/slm-icon.svg +36 -0
- package/src/superlocalmemory/ui/css/design-system.css +621 -0
- package/src/superlocalmemory/ui/css/neural-glass.css +6 -0
- package/src/superlocalmemory/ui/css/od-bridge.css +158 -0
- package/src/superlocalmemory/ui/favicon.svg +35 -4
- package/src/superlocalmemory/ui/index.html +306 -173
- package/src/superlocalmemory/ui/js/brain.js +5 -20
- package/src/superlocalmemory/ui/js/core.js +47 -31
- package/src/superlocalmemory/ui/js/dashboard.js +314 -63
- package/src/superlocalmemory/ui/js/event-delegation.js +102 -0
- package/src/superlocalmemory/ui/js/knowledge-graph.js +11 -11
- package/src/superlocalmemory/ui/js/math-health.js +1 -1
- package/src/superlocalmemory/ui/js/memories.js +15 -4
- package/src/superlocalmemory/ui/js/memory-chat.js +7 -7
- package/src/superlocalmemory/ui/js/ng-entities.js +6 -8
- package/src/superlocalmemory/ui/js/ng-ingestion.js +4 -4
- package/src/superlocalmemory/ui/js/ng-mesh.js +4 -9
- package/src/superlocalmemory/ui/js/ng-shell.js +8 -8
- package/src/superlocalmemory/ui/js/ng-skills.js +54 -2
- package/src/superlocalmemory/ui/js/od-agents.js +544 -0
- package/src/superlocalmemory/ui/js/od-auth-gate.js +257 -0
- package/src/superlocalmemory/ui/js/od-backup.js +780 -0
- package/src/superlocalmemory/ui/js/od-brain.js +779 -0
- package/src/superlocalmemory/ui/js/od-entities.js +579 -0
- package/src/superlocalmemory/ui/js/od-graph.js +593 -0
- package/src/superlocalmemory/ui/js/od-health.js +539 -0
- package/src/superlocalmemory/ui/js/od-mcp.js +508 -0
- package/src/superlocalmemory/ui/js/od-memories.js +887 -0
- package/src/superlocalmemory/ui/js/od-mesh.js +539 -0
- package/src/superlocalmemory/ui/js/od-operations.js +1250 -0
- package/src/superlocalmemory/ui/js/od-optimize.js +787 -0
- package/src/superlocalmemory/ui/js/od-settings.js +1053 -0
- package/src/superlocalmemory/ui/js/od-shell.js +593 -0
- package/src/superlocalmemory/ui/js/od-skills.js +573 -0
- package/src/superlocalmemory/ui/js/od-team.js +258 -0
- package/src/superlocalmemory/ui/js/profiles.js +159 -46
- package/src/superlocalmemory/ui/js/settings.js +2 -2
- package/src/superlocalmemory/ui/js/timeline.js +34 -5
- package/src/superlocalmemory/ui/js/trust-dashboard.js +2 -2
- package/src/superlocalmemory/vector/lancedb_backend.py +8 -6
- 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
|
+
}());
|