superlocalmemory 3.7.8 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/ATTRIBUTION.md +1 -3
- package/CHANGELOG.md +129 -0
- package/README.md +205 -123
- package/package.json +12 -3
- package/plugin/.claude-plugin/plugin.json +2 -3
- 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/rules/AGENTS.md +57 -18
- 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-graph/SKILL.md +17 -3
- 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-session/SKILL.md +24 -1
- package/plugin-src/skills/slm-status/SKILL.md +18 -1
- package/pyproject.toml +2 -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 +228 -17
- package/src/superlocalmemory/cli/compress_cmd.py +17 -7
- package/src/superlocalmemory/cli/daemon.py +7 -0
- package/src/superlocalmemory/cli/loop_cmd.py +187 -0
- package/src/superlocalmemory/cli/main.py +49 -8
- 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/cli/version_banner.py +17 -3
- 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 +23 -59
- 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 +21 -7
- package/src/superlocalmemory/core/embeddings.py +131 -46
- package/src/superlocalmemory/core/engine.py +41 -22
- package/src/superlocalmemory/core/engine_ingestion.py +359 -43
- 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/ingestion_command.py +134 -25
- package/src/superlocalmemory/core/injection.py +12 -7
- package/src/superlocalmemory/core/key_expander.py +138 -0
- package/src/superlocalmemory/core/maintenance.py +23 -0
- package/src/superlocalmemory/core/maintenance_scheduler.py +17 -7
- 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 +7 -3
- 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 +186 -29
- 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/hook_handlers.py +6 -1
- package/src/superlocalmemory/hooks/memory_protocol.py +54 -0
- package/src/superlocalmemory/hooks/portable_kit.py +148 -3
- 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/model_rollback.py +3 -0
- package/src/superlocalmemory/learning/ranker_retrain_online.py +2 -0
- package/src/superlocalmemory/learning/reward.py +50 -0
- package/src/superlocalmemory/learning/reward_proxy.py +42 -9
- package/src/superlocalmemory/learning/source_quality.py +523 -1
- 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 +263 -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 +32 -79
- 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 +12 -4
- package/src/superlocalmemory/mcp/tools_evolution.py +6 -3
- package/src/superlocalmemory/mcp/tools_learning.py +2 -2
- 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 +221 -47
- package/src/superlocalmemory/retrieval/entity_channel.py +7 -5
- package/src/superlocalmemory/retrieval/hopfield_channel.py +9 -2
- package/src/superlocalmemory/retrieval/reranker.py +3 -4
- 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/config_file.py +90 -0
- package/src/superlocalmemory/server/origin.py +50 -0
- 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 +317 -70
- package/src/superlocalmemory/server/routes/behavioral.py +349 -71
- package/src/superlocalmemory/server/routes/brain.py +69 -12
- 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 +438 -0
- package/src/superlocalmemory/server/routes/data_io.py +30 -8
- package/src/superlocalmemory/server/routes/entity.py +108 -26
- package/src/superlocalmemory/server/routes/events.py +24 -8
- package/src/superlocalmemory/server/routes/evolution.py +189 -68
- 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 +289 -118
- package/src/superlocalmemory/server/routes/learning_telemetry.py +153 -0
- 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 +200 -31
- 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 +132 -0
- package/src/superlocalmemory/server/routes/rbac.py +367 -0
- package/src/superlocalmemory/server/routes/stats.py +103 -158
- package/src/superlocalmemory/server/routes/tiers.py +11 -9
- package/src/superlocalmemory/server/routes/token.py +3 -13
- package/src/superlocalmemory/server/routes/v3_api.py +247 -89
- 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 +827 -72
- package/src/superlocalmemory/server/write_identity.py +38 -8
- package/src/superlocalmemory/storage/database.py +265 -53
- package/src/superlocalmemory/storage/migration_runner.py +132 -1
- package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +5 -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/migrations/M028_fact_entity_associations.py +270 -0
- package/src/superlocalmemory/storage/migrations/M029_behavioral_history_indexes.py +137 -0
- package/src/superlocalmemory/storage/migrations/M030_entity_explorer_indexes.py +93 -0
- package/src/superlocalmemory/storage/migrations/__init__.py +4 -0
- package/src/superlocalmemory/storage/models.py +4 -0
- package/src/superlocalmemory/storage/schema.py +136 -1
- package/src/superlocalmemory/storage/schema_v32.py +2 -0
- package/src/superlocalmemory/storage/schema_v343.py +24 -12
- package/src/superlocalmemory/storage/schema_v347.py +4 -0
- 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 +303 -173
- package/src/superlocalmemory/ui/js/brain.js +5 -20
- package/src/superlocalmemory/ui/js/core.js +100 -41
- package/src/superlocalmemory/ui/js/dashboard.js +403 -65
- 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 +871 -0
- package/src/superlocalmemory/ui/js/od-brain.js +816 -0
- package/src/superlocalmemory/ui/js/od-entities.js +579 -0
- package/src/superlocalmemory/ui/js/od-graph.js +600 -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 +929 -0
- package/src/superlocalmemory/ui/js/od-mesh.js +553 -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 +1107 -0
- package/src/superlocalmemory/ui/js/od-shell.js +809 -0
- package/src/superlocalmemory/ui/js/od-skills.js +600 -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 +17 -3
- 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/plugin-src/.mcp.json +0 -12
- package/plugin-src/agents/slm-memory-advisor.md +0 -44
- package/plugin-src/agents/slm-optimize-advisor.md +0 -38
- package/plugin-src/hooks/.gitkeep +0 -0
- package/plugin-src/hooks/hooks.json +0 -23
- package/plugin-src/manifest.json +0 -25
- package/plugin-src/requirements.txt +0 -1
- package/plugin-src/rules/CLAUDE.md.fragment +0 -44
- package/plugin-src/scripts/ensure-venv.bat +0 -122
- package/plugin-src/scripts/ensure-venv.sh +0 -105
- package/plugin-src/scripts/slm-launch +0 -23
- package/plugin-src/scripts/slm-launch.bat +0 -23
- package/plugin-src/settings.json +0 -16
- package/src/superlocalmemory/learning/behavioral_listener.py +0 -94
|
@@ -1,60 +1,391 @@
|
|
|
1
1
|
// SuperLocalMemory V3 — Dashboard
|
|
2
2
|
// Part of Qualixar | https://superlocalmemory.com
|
|
3
|
+
//
|
|
4
|
+
// OD integration (v3.8.0):
|
|
5
|
+
// loadDashboard() → GET /api/v3/dashboard → system card (#dashboard-mode etc.)
|
|
6
|
+
// loadDashboardStats() → GET /api/stats → OD KPI strip (#k-mem, #k-nodes, #k-edges)
|
|
7
|
+
// loadDashboardFeed() → GET /api/memories?limit=6 → activity feed (#feed)
|
|
8
|
+
// loadDashboardSources() → real provenance from /api/stats → capture-sources (#src)
|
|
9
|
+
// loadDashboardTimeline() → real daily fact counts from /api/timeline → #sp-big
|
|
10
|
+
|
|
11
|
+
var DASHBOARD_CACHE_MS = 30000;
|
|
12
|
+
var dashboardLastRefresh = 0;
|
|
13
|
+
var dashboardRefreshInFlight = null;
|
|
14
|
+
var dashboardCacheGeneration = 0;
|
|
15
|
+
var dashboardRefreshQueued = false;
|
|
16
|
+
|
|
17
|
+
window.slmInvalidateDashboardCache = function() {
|
|
18
|
+
dashboardCacheGeneration += 1;
|
|
19
|
+
dashboardLastRefresh = 0;
|
|
20
|
+
if (dashboardRefreshInFlight) dashboardRefreshQueued = true;
|
|
21
|
+
};
|
|
3
22
|
|
|
4
23
|
// Auto-refresh dashboard when tab becomes visible (fixes stale data after settings change)
|
|
5
24
|
document.addEventListener('visibilitychange', function() {
|
|
6
|
-
if (!document.hidden)
|
|
25
|
+
if (!document.hidden) refreshDashboard();
|
|
7
26
|
});
|
|
8
27
|
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
28
|
+
// Focus and tab navigation use a short cache window. This keeps normal
|
|
29
|
+
// browser switching from repeatedly querying a large local database.
|
|
30
|
+
window.addEventListener('focus', function() { refreshDashboard(); });
|
|
31
|
+
|
|
32
|
+
// Load when the Dashboard tab is shown via the sidebar. od-shell.js's activateTab()
|
|
33
|
+
// dispatches shown.bs.tab on the hidden #dashboard-tab button.
|
|
34
|
+
document.getElementById('dashboard-tab')?.addEventListener('shown.bs.tab', function() { refreshDashboard(); });
|
|
35
|
+
|
|
36
|
+
// refreshDashboard coalesces concurrent startup/navigation events and keeps a
|
|
37
|
+
// 30-second snapshot. Mutations pass {force:true} to re-read daemon truth.
|
|
38
|
+
window.refreshDashboard = function(options) {
|
|
39
|
+
var force = options && options.force === true;
|
|
40
|
+
var now = Date.now();
|
|
41
|
+
if (dashboardRefreshInFlight) {
|
|
42
|
+
if (force) dashboardRefreshQueued = true;
|
|
43
|
+
return dashboardRefreshInFlight;
|
|
13
44
|
}
|
|
14
|
-
|
|
45
|
+
if (!force && dashboardLastRefresh && now - dashboardLastRefresh < DASHBOARD_CACHE_MS) {
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
}
|
|
48
|
+
var refreshGeneration = dashboardCacheGeneration;
|
|
49
|
+
dashboardRefreshInFlight = Promise.all([
|
|
50
|
+
loadDashboard(),
|
|
51
|
+
loadDashboardStats(),
|
|
52
|
+
loadDashboardTimeline(),
|
|
53
|
+
loadDashboardFeed()
|
|
54
|
+
]).then(function(results) {
|
|
55
|
+
dashboardLastRefresh = refreshGeneration === dashboardCacheGeneration && results.every(Boolean)
|
|
56
|
+
? Date.now()
|
|
57
|
+
: 0;
|
|
58
|
+
}).finally(function() {
|
|
59
|
+
dashboardRefreshInFlight = null;
|
|
60
|
+
}).then(function() {
|
|
61
|
+
if (!dashboardRefreshQueued) return;
|
|
62
|
+
dashboardRefreshQueued = false;
|
|
63
|
+
return window.refreshDashboard({ force: true });
|
|
64
|
+
});
|
|
65
|
+
return dashboardRefreshInFlight;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// ----------------------------------------------------------------
|
|
69
|
+
// loadDashboardStats — GET /api/stats → OD KPI strip
|
|
70
|
+
// ----------------------------------------------------------------
|
|
71
|
+
async function loadDashboardStats() {
|
|
72
|
+
try {
|
|
73
|
+
var r = await fetch('/api/stats', { credentials: 'same-origin' });
|
|
74
|
+
if (!r.ok) return false;
|
|
75
|
+
var data = await r.json();
|
|
76
|
+
var ov = data.overview || {};
|
|
77
|
+
|
|
78
|
+
var memories = ov.total_memories || 0;
|
|
79
|
+
var facts = ov.total_facts || 0;
|
|
80
|
+
var nodes = ov.graph_nodes || 0;
|
|
81
|
+
var edges = ov.graph_edges || 0;
|
|
82
|
+
var clusters = ov.total_clusters || 0;
|
|
83
|
+
|
|
84
|
+
// OD KPI strip
|
|
85
|
+
setKpiValue('k-mem', memories);
|
|
86
|
+
setKpiValue('k-nodes', nodes);
|
|
87
|
+
setKpiValue('k-edges', edges);
|
|
88
|
+
setKpiValue('k-facts', facts);
|
|
89
|
+
setKpiValue('k-clu', clusters);
|
|
90
|
+
|
|
91
|
+
// Legacy hidden compat IDs (core.js loadStats() may race — that's OK,
|
|
92
|
+
// the hidden IDs are only a data bridge, not visible).
|
|
93
|
+
setTextById('stat-memories', memories);
|
|
94
|
+
setTextById('stat-facts', facts);
|
|
95
|
+
setTextById('stat-nodes', nodes);
|
|
96
|
+
setTextById('stat-edges', edges);
|
|
97
|
+
loadDashboardSources(data);
|
|
98
|
+
return true;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
// Non-fatal: KPI strip shows — values
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ----------------------------------------------------------------
|
|
106
|
+
// loadDashboardTimeline — renders real daily fact counts from /api/timeline
|
|
107
|
+
// ----------------------------------------------------------------
|
|
108
|
+
async function loadDashboardTimeline() {
|
|
109
|
+
var spBig = document.getElementById('sp-big');
|
|
110
|
+
if (!spBig) return true;
|
|
111
|
+
try {
|
|
112
|
+
var response = await fetch('/api/timeline?days=365&group_by=day&include_categories=false', {
|
|
113
|
+
credentials: 'same-origin'
|
|
114
|
+
});
|
|
115
|
+
if (!response.ok) throw new Error('timeline unavailable');
|
|
116
|
+
var stats = await response.json();
|
|
117
|
+
var points = Array.isArray(stats.timeline) ? stats.timeline : [];
|
|
118
|
+
var byDate = {};
|
|
119
|
+
points.forEach(function(point) {
|
|
120
|
+
if (point && point.period) byDate[String(point.period)] = Number(point.count) || 0;
|
|
121
|
+
});
|
|
122
|
+
var counts = [];
|
|
123
|
+
var today = new Date();
|
|
124
|
+
today.setHours(0, 0, 0, 0);
|
|
125
|
+
for (var dayOffset = 364; dayOffset >= 0; dayOffset--) {
|
|
126
|
+
var day = new Date(today);
|
|
127
|
+
day.setDate(today.getDate() - dayOffset);
|
|
128
|
+
counts.push(byDate[day.toISOString().slice(0, 10)] || 0);
|
|
129
|
+
}
|
|
130
|
+
var total = counts.reduce(function(sum, value) { return sum + value; }, 0);
|
|
131
|
+
var avgEl = document.getElementById('k-avg-day');
|
|
132
|
+
if (avgEl) avgEl.textContent = (total / 365).toFixed(1);
|
|
133
|
+
|
|
134
|
+
if (!total || typeof window.slmSpark !== 'function') {
|
|
135
|
+
spBig.textContent = 'No dated memory history recorded for this profile.';
|
|
136
|
+
spBig.className = 'muted';
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
spBig.className = '';
|
|
140
|
+
spBig.innerHTML = window.slmSpark(counts, {
|
|
141
|
+
w: 600,
|
|
142
|
+
h: 140,
|
|
143
|
+
color: 'var(--violet)'
|
|
144
|
+
});
|
|
145
|
+
if (spBig.querySelector('svg')) {
|
|
146
|
+
spBig.querySelector('svg').style.cssText = 'width:100%;height:140px;display:block;';
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
} catch (e) {
|
|
150
|
+
spBig.textContent = 'Memory history unavailable.';
|
|
151
|
+
spBig.className = 'muted';
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ----------------------------------------------------------------
|
|
157
|
+
// loadDashboardFeed — GET /api/memories?limit=6 → activity feed
|
|
158
|
+
// ----------------------------------------------------------------
|
|
159
|
+
async function loadDashboardFeed() {
|
|
160
|
+
var feedEl = document.getElementById('feed');
|
|
161
|
+
if (!feedEl) return true;
|
|
162
|
+
|
|
163
|
+
var CATEGORY_COLORS = {
|
|
164
|
+
'episodic': ['rgba(34,197,94,0.12)', '#22c55e'],
|
|
165
|
+
'semantic': ['rgba(139,92,246,0.12)', '#8b5cf6'],
|
|
166
|
+
'temporal': ['rgba(6,182,212,0.12)', '#06b6d4'],
|
|
167
|
+
'opinion': ['rgba(245,158,11,0.12)', '#f59e0b'],
|
|
168
|
+
'default': ['rgba(100,116,139,0.12)','#64748b'],
|
|
169
|
+
};
|
|
170
|
+
var CATEGORY_ICONS = {
|
|
171
|
+
'episodic': 'bi bi-journal-text',
|
|
172
|
+
'semantic': 'bi bi-diagram-3',
|
|
173
|
+
'temporal': 'bi bi-clock',
|
|
174
|
+
'opinion': 'bi bi-lightbulb',
|
|
175
|
+
'default': 'bi bi-file-earmark',
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
var r = await fetch('/api/memories?limit=6', { credentials: 'same-origin' });
|
|
180
|
+
if (!r.ok) {
|
|
181
|
+
feedEl.innerHTML = '<div class="muted" style="padding:12px;text-align:center;font-size:13px">No recent activity</div>';
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
var data = await r.json();
|
|
185
|
+
var items = data.memories || data.results || data || [];
|
|
186
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
187
|
+
feedEl.innerHTML = '<div class="muted" style="padding:12px;text-align:center;font-size:13px">No memories yet — start capturing!</div>';
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Build feed using DOM methods (XSS-safe — no innerHTML with user content)
|
|
192
|
+
feedEl.textContent = '';
|
|
193
|
+
items.slice(0, 6).forEach(function(mem) {
|
|
194
|
+
var cat = (mem.category || 'default').toLowerCase();
|
|
195
|
+
var cols = CATEGORY_COLORS[cat] || CATEGORY_COLORS['default'];
|
|
196
|
+
var icon = CATEGORY_ICONS[cat] || CATEGORY_ICONS['default'];
|
|
197
|
+
var text = (mem.content || mem.text || '').substring(0, 120);
|
|
198
|
+
var agent = mem.agent_id || mem.source || 'system';
|
|
199
|
+
var ts = mem.created_at || mem.updated_at || '';
|
|
200
|
+
var relTime = ts ? relativeTime(ts) : '';
|
|
201
|
+
|
|
202
|
+
var item = document.createElement('div');
|
|
203
|
+
item.className = 'feed-item';
|
|
204
|
+
|
|
205
|
+
var ic = document.createElement('span');
|
|
206
|
+
ic.className = 'ic';
|
|
207
|
+
ic.style.cssText = 'background:' + cols[0] + ';color:' + cols[1] + ';';
|
|
208
|
+
var iEl = document.createElement('i');
|
|
209
|
+
iEl.className = icon;
|
|
210
|
+
ic.appendChild(iEl);
|
|
211
|
+
|
|
212
|
+
var body = document.createElement('div');
|
|
213
|
+
body.style.flex = '1';
|
|
214
|
+
var textNode = document.createElement('div');
|
|
215
|
+
textNode.textContent = text;
|
|
216
|
+
var agentNode = document.createElement('div');
|
|
217
|
+
agentNode.className = 'dim';
|
|
218
|
+
agentNode.style.cssText = 'font-size:11.5px;margin-top:2px;font-family:SF Mono,Consolas,monospace;';
|
|
219
|
+
agentNode.textContent = agent + (cat !== 'default' ? ' · ' + cat : '');
|
|
220
|
+
body.appendChild(textNode);
|
|
221
|
+
body.appendChild(agentNode);
|
|
222
|
+
|
|
223
|
+
var time = document.createElement('time');
|
|
224
|
+
time.textContent = relTime;
|
|
15
225
|
|
|
16
|
-
|
|
17
|
-
|
|
226
|
+
item.appendChild(ic);
|
|
227
|
+
item.appendChild(body);
|
|
228
|
+
item.appendChild(time);
|
|
229
|
+
feedEl.appendChild(item);
|
|
230
|
+
});
|
|
231
|
+
return true;
|
|
232
|
+
} catch (e) {
|
|
233
|
+
feedEl.innerHTML = '<div class="muted" style="padding:12px;text-align:center;font-size:13px">Activity unavailable</div>';
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ----------------------------------------------------------------
|
|
239
|
+
// loadDashboardSources — profile-scoped provenance returned by /api/stats
|
|
240
|
+
// ----------------------------------------------------------------
|
|
241
|
+
function loadDashboardSources(stats) {
|
|
242
|
+
var srcEl = document.getElementById('src');
|
|
243
|
+
if (!srcEl) return;
|
|
244
|
+
var sourceStatus = stats && stats.ingestion_sources_status;
|
|
245
|
+
if (sourceStatus && sourceStatus.available === false) {
|
|
246
|
+
srcEl.textContent = 'Provenance metrics are temporarily unavailable.';
|
|
247
|
+
srcEl.className = 'muted';
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
var sources = stats && Array.isArray(stats.ingestion_sources)
|
|
251
|
+
? stats.ingestion_sources
|
|
252
|
+
: [];
|
|
253
|
+
if (!sources.length) {
|
|
254
|
+
srcEl.textContent = 'No provenance recorded for this profile.';
|
|
255
|
+
srcEl.className = 'muted';
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
var LABELS = {
|
|
260
|
+
'store': 'Historical / engine store',
|
|
261
|
+
'http': 'Dashboard, hooks, and API',
|
|
262
|
+
'http-observe': 'Auto-capture observations',
|
|
263
|
+
'mcp-offline-worker': 'Queued MCP ingestion',
|
|
264
|
+
'cli-sync': 'CLI sync',
|
|
265
|
+
'unknown': 'Unclassified'
|
|
266
|
+
};
|
|
267
|
+
var COLORS = ['var(--violet)', 'var(--cyan)', 'var(--warn,#f59e0b)', 'var(--fg-3)'];
|
|
268
|
+
var total = sources.reduce(function(sum, source) {
|
|
269
|
+
return sum + (Number(source.count) || 0);
|
|
270
|
+
}, 0);
|
|
271
|
+
|
|
272
|
+
srcEl.className = '';
|
|
273
|
+
srcEl.textContent = '';
|
|
274
|
+
sources.forEach(function(source, index) {
|
|
275
|
+
var count = Number(source.count) || 0;
|
|
276
|
+
var percent = total ? Math.round((count / total) * 100) : 0;
|
|
277
|
+
var row = document.createElement('div');
|
|
278
|
+
row.style.marginBottom = '14px';
|
|
279
|
+
|
|
280
|
+
var heading = document.createElement('div');
|
|
281
|
+
heading.style.cssText = 'display:flex;justify-content:space-between;font-size:13px;margin-bottom:6px';
|
|
282
|
+
var label = document.createElement('span');
|
|
283
|
+
label.textContent = LABELS[source.source_type] || source.source_type || 'Unclassified';
|
|
284
|
+
var value = document.createElement('b');
|
|
285
|
+
value.className = 'num';
|
|
286
|
+
value.textContent = count.toLocaleString() + ' · ' + percent + '%';
|
|
287
|
+
heading.appendChild(label);
|
|
288
|
+
heading.appendChild(value);
|
|
289
|
+
|
|
290
|
+
var meter = document.createElement('div');
|
|
291
|
+
meter.className = 'meter';
|
|
292
|
+
var fill = document.createElement('i');
|
|
293
|
+
fill.style.width = percent + '%';
|
|
294
|
+
fill.style.background = COLORS[index % COLORS.length];
|
|
295
|
+
meter.appendChild(fill);
|
|
296
|
+
|
|
297
|
+
row.appendChild(heading);
|
|
298
|
+
row.appendChild(meter);
|
|
299
|
+
srcEl.appendChild(row);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ----------------------------------------------------------------
|
|
304
|
+
// relativeTime — converts ISO timestamp to "Xm ago" etc.
|
|
305
|
+
// ----------------------------------------------------------------
|
|
306
|
+
function relativeTime(ts) {
|
|
307
|
+
try {
|
|
308
|
+
var diff = (Date.now() - new Date(ts).getTime()) / 1000;
|
|
309
|
+
if (diff < 60) return Math.round(diff) + 's ago';
|
|
310
|
+
if (diff < 3600) return Math.round(diff / 60) + 'm ago';
|
|
311
|
+
if (diff < 86400) return Math.round(diff / 3600) + 'h ago';
|
|
312
|
+
return Math.round(diff / 86400) + 'd ago';
|
|
313
|
+
} catch (e) { return ''; }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ----------------------------------------------------------------
|
|
317
|
+
// setKpiValue — formats large numbers with locale commas
|
|
318
|
+
// ----------------------------------------------------------------
|
|
319
|
+
function setKpiValue(id, val) {
|
|
320
|
+
var el = document.getElementById(id);
|
|
321
|
+
if (!el) return;
|
|
322
|
+
if (val === null || val === undefined) { el.textContent = '—'; return; }
|
|
323
|
+
el.textContent = Number(val).toLocaleString();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function setTextById(id, val) {
|
|
327
|
+
var el = document.getElementById(id);
|
|
328
|
+
if (el) el.textContent = String(val);
|
|
329
|
+
}
|
|
18
330
|
|
|
19
331
|
async function loadDashboard() {
|
|
20
332
|
var PANE_ID = 'dashboard-pane';
|
|
21
333
|
try {
|
|
22
|
-
var response = await fetch('/api/v3/dashboard');
|
|
334
|
+
var response = await fetch('/api/v3/dashboard', { credentials: 'same-origin' });
|
|
23
335
|
if (!response.ok) {
|
|
24
336
|
showPaneError(PANE_ID, paneErrorMessage(response.status), loadDashboard, true);
|
|
25
|
-
return;
|
|
337
|
+
return false;
|
|
26
338
|
}
|
|
27
339
|
var data = await response.json();
|
|
28
340
|
|
|
29
341
|
clearPaneError(PANE_ID, true);
|
|
30
342
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
343
|
+
setTextById('dashboard-mode', 'Mode ' + data.mode.toUpperCase());
|
|
344
|
+
setTextById('dashboard-mode-desc', data.mode_name + (data.provider !== 'none' ? ' — ' + data.provider : ''));
|
|
345
|
+
setTextById('dashboard-memory-count', data.fact_count || data.memory_count || '0');
|
|
346
|
+
setTextById('dashboard-provider', data.provider === 'none' ? 'None' : data.provider);
|
|
347
|
+
setTextById('dashboard-model', data.model || '');
|
|
348
|
+
setTextById('dashboard-profile', data.profile || 'default');
|
|
349
|
+
setTextById('dashboard-basedir', data.base_dir || '~/.superlocalmemory');
|
|
350
|
+
|
|
38
351
|
var ver = data.version || '';
|
|
39
352
|
var dashVer = document.getElementById('dashboard-version');
|
|
40
353
|
var settVer = document.getElementById('settings-version');
|
|
41
354
|
if (dashVer) dashVer.textContent = ver;
|
|
42
355
|
if (settVer) settVer.textContent = ver;
|
|
43
356
|
|
|
44
|
-
//
|
|
357
|
+
// OD dashboard subtitle
|
|
358
|
+
var subtitle = document.getElementById('od-dash-subtitle');
|
|
359
|
+
if (subtitle && data.mode_name) {
|
|
360
|
+
subtitle.textContent = 'Mode ' + data.mode.toUpperCase() + ' · ' + data.mode_name +
|
|
361
|
+
' · local-only · v' + (ver || '?');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Update mode badge in sidebar (ng-premount hidden element)
|
|
45
365
|
var badge = document.getElementById('mode-badge');
|
|
46
366
|
if (badge) badge.textContent = 'Mode ' + data.mode.toUpperCase();
|
|
47
367
|
|
|
48
|
-
// Highlight active mode button
|
|
368
|
+
// Highlight active mode button in OD system card
|
|
49
369
|
document.querySelectorAll('.mode-btn').forEach(function(btn) {
|
|
50
370
|
btn.classList.toggle('active', btn.dataset.mode === data.mode);
|
|
51
371
|
});
|
|
372
|
+
return true;
|
|
52
373
|
} catch (e) {
|
|
53
374
|
showPaneError(PANE_ID, paneErrorMessage(0), loadDashboard, true);
|
|
54
375
|
console.log('Dashboard load error:', e);
|
|
376
|
+
return false;
|
|
55
377
|
}
|
|
56
378
|
}
|
|
57
379
|
|
|
380
|
+
// Fire all OD + legacy loaders on first DOMContentLoaded (dashboard is the default pane)
|
|
381
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
382
|
+
// od-shell.js calls activateTab('dashboard-pane') which dispatches shown.bs.tab,
|
|
383
|
+
// but the listener may not yet be attached at that point. Call directly as well.
|
|
384
|
+
setTimeout(function() {
|
|
385
|
+
refreshDashboard({ force: true });
|
|
386
|
+
}, 200);
|
|
387
|
+
});
|
|
388
|
+
|
|
58
389
|
// Mode switch buttons
|
|
59
390
|
document.addEventListener('click', function(e) {
|
|
60
391
|
if (e.target.classList.contains('mode-btn')) {
|
|
@@ -72,84 +403,91 @@ document.addEventListener('click', function(e) {
|
|
|
72
403
|
}
|
|
73
404
|
});
|
|
74
405
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
var
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
406
|
+
// B2 (3.7.9): token cached in a private closure, never sessionStorage.
|
|
407
|
+
var dashboardInstallToken = (function () {
|
|
408
|
+
var _cache = null;
|
|
409
|
+
return async function () {
|
|
410
|
+
if (_cache) return _cache;
|
|
411
|
+
var response = await fetch('/internal/token', {credentials: 'same-origin'});
|
|
412
|
+
if (!response.ok) return '';
|
|
413
|
+
var payload = await response.json();
|
|
414
|
+
var token = payload && payload.token ? payload.token : '';
|
|
415
|
+
if (token) _cache = token;
|
|
416
|
+
return token;
|
|
417
|
+
};
|
|
418
|
+
})();
|
|
86
419
|
|
|
87
420
|
// Quick store
|
|
88
421
|
document.getElementById('quick-store-btn')?.addEventListener('click', async function() {
|
|
89
|
-
var input = document.getElementById('quick-store-input');
|
|
90
|
-
var content = input.value.trim();
|
|
422
|
+
var btn = this, input = document.getElementById('quick-store-input');
|
|
423
|
+
var content = input ? input.value.trim() : '';
|
|
91
424
|
if (!content) return;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
headers: {
|
|
101
|
-
'Content-Type': 'application/json',
|
|
102
|
-
'X-Install-Token': token
|
|
103
|
-
},
|
|
104
|
-
body: JSON.stringify({content: content})
|
|
105
|
-
}).then(function(r) {
|
|
106
|
-
if (!r.ok) return r.json().catch(function() { return {}; }).then(function(d) {
|
|
107
|
-
showToast('Store failed: ' + (d.detail || d.error || r.status), 'error');
|
|
425
|
+
btn.disabled = true; btn.textContent = 'Storing…';
|
|
426
|
+
try {
|
|
427
|
+
var token = await dashboardInstallToken();
|
|
428
|
+
if (!token) throw new Error('local write credential unavailable');
|
|
429
|
+
var r = await fetch('/remember', {
|
|
430
|
+
method: 'POST', credentials: 'same-origin',
|
|
431
|
+
headers: {'Content-Type': 'application/json', 'X-Install-Token': token},
|
|
432
|
+
body: JSON.stringify({content: content})
|
|
108
433
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
434
|
+
if (!r.ok) {
|
|
435
|
+
var d = await r.json().catch(function(){return{};});
|
|
436
|
+
throw new Error(d.detail || d.error || 'HTTP ' + r.status);
|
|
437
|
+
}
|
|
438
|
+
await r.json();
|
|
439
|
+
if (input) input.value = '';
|
|
440
|
+
refreshDashboard({ force: true });
|
|
114
441
|
showToast('Stored!');
|
|
115
|
-
}
|
|
442
|
+
} catch(e) {
|
|
443
|
+
showToast('Store failed: ' + e.message);
|
|
444
|
+
} finally {
|
|
445
|
+
btn.disabled = false; btn.textContent = 'Store';
|
|
446
|
+
}
|
|
116
447
|
});
|
|
117
448
|
|
|
118
449
|
// Quick recall
|
|
119
450
|
document.getElementById('quick-recall-btn')?.addEventListener('click', function() {
|
|
120
|
-
var
|
|
451
|
+
var btn = this, qEl = document.getElementById('quick-recall-input');
|
|
452
|
+
var query = qEl ? qEl.value.trim() : '';
|
|
121
453
|
if (!query) return;
|
|
454
|
+
var div = document.getElementById('quick-recall-results');
|
|
455
|
+
if (div) div.innerHTML = '<span style="color:var(--fg-2);font-size:12px">Searching…</span>';
|
|
456
|
+
btn.disabled = true;
|
|
122
457
|
fetch('/api/search', {
|
|
123
|
-
method: 'POST',
|
|
458
|
+
method: 'POST', credentials: 'same-origin',
|
|
124
459
|
headers: {'Content-Type': 'application/json'},
|
|
460
|
+
slmInvalidatesCache: false,
|
|
461
|
+
slmRequiresWriteAuth: false,
|
|
125
462
|
body: JSON.stringify({query: query, limit: 5})
|
|
126
463
|
}).then(function(r) {
|
|
464
|
+
btn.disabled = false;
|
|
127
465
|
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
128
466
|
return r.json();
|
|
129
467
|
}).then(function(data) {
|
|
130
468
|
var div = document.getElementById('quick-recall-results');
|
|
469
|
+
if (!div) return;
|
|
131
470
|
if (!data.results || data.results.length === 0) {
|
|
132
471
|
div.textContent = 'No results found.';
|
|
133
472
|
return;
|
|
134
473
|
}
|
|
135
|
-
// Build results using DOM methods for safety
|
|
136
474
|
div.textContent = '';
|
|
137
475
|
data.results.forEach(function(r, i) {
|
|
138
476
|
var row = document.createElement('div');
|
|
139
|
-
row.
|
|
477
|
+
row.style.cssText = 'padding:5px 0;border-bottom:1px solid var(--border);font-size:12.5px';
|
|
140
478
|
var strong = document.createElement('strong');
|
|
141
479
|
strong.textContent = (i + 1) + '. ';
|
|
142
480
|
row.appendChild(strong);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
row.appendChild(scoreSpan);
|
|
481
|
+
row.appendChild(document.createTextNode((r.content || r.text || '').substring(0, 150)));
|
|
482
|
+
var sc = document.createElement('span');
|
|
483
|
+
sc.style.cssText = 'color:var(--fg-2);margin-left:6px;font-size:11.5px';
|
|
484
|
+
sc.textContent = '(' + (r.score || 0).toFixed(2) + ')';
|
|
485
|
+
row.appendChild(sc);
|
|
149
486
|
div.appendChild(row);
|
|
150
487
|
});
|
|
151
488
|
}).catch(function(e) {
|
|
489
|
+
btn.disabled = false;
|
|
152
490
|
var div = document.getElementById('quick-recall-results');
|
|
153
|
-
if (div) div.textContent = 'Search failed
|
|
491
|
+
if (div) div.textContent = 'Search failed: ' + e.message;
|
|
154
492
|
});
|
|
155
493
|
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
3
|
+
// B2 (3.7.9): CSP-safe event delegation. Replaces inline on*= handlers
|
|
4
|
+
// (which force script-src 'unsafe-inline') with data-act-* attributes
|
|
5
|
+
// dispatched by document-level listeners. Registry keys are an allowlist
|
|
6
|
+
// by construction — no reflective window[name] invocation.
|
|
7
|
+
(function () {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
// action-key -> handler(el, event). Handlers call existing globals.
|
|
11
|
+
const ACTIONS = {
|
|
12
|
+
// --- bespoke ---
|
|
13
|
+
'scroll-into': (el) => { const t = document.getElementById(el.dataset.target); if (t) t.scrollIntoView({ behavior: 'smooth', block: 'start' }); },
|
|
14
|
+
'sigma-clear-search': () => { sigmaClearSearch(); const i = document.getElementById('sigma-search-input'); if (i) i.value = ''; },
|
|
15
|
+
'export-all': (el, e) => { if (e) e.preventDefault(); exportAll(el.dataset.format); },
|
|
16
|
+
'export-search-results': (el, e) => { if (e) e.preventDefault(); exportSearchResults(); },
|
|
17
|
+
'set-memory-filter': (el) => setMemoryFilter(el.dataset.filter),
|
|
18
|
+
'community-source': (el) => handleCommunitySourceToggle(el.dataset.source),
|
|
19
|
+
// --- value (this.value) ---
|
|
20
|
+
'handle-resolution-change': (el) => handleResolutionChange(el.value),
|
|
21
|
+
'sigma-filter-by-category': (el) => sigmaFilterByCategory(el.value),
|
|
22
|
+
'sigma-search': (el) => sigmaSearch(el.value),
|
|
23
|
+
// --- no-arg ---
|
|
24
|
+
'backup-learning-db': () => backupLearningDb(),
|
|
25
|
+
'clear-event-stream': () => clearEventStream(),
|
|
26
|
+
'compact-dry-run': () => compactDryRun(),
|
|
27
|
+
'compact-execute': () => compactExecute(),
|
|
28
|
+
'connect-git-hub': () => connectGitHub(),
|
|
29
|
+
'connect-google-drive': () => connectGoogleDrive(),
|
|
30
|
+
'copy-memory-to-clipboard': () => copyMemoryToClipboard(),
|
|
31
|
+
'create-backup-now': () => createBackupNow(),
|
|
32
|
+
'create-profile': () => createProfile(),
|
|
33
|
+
'create-retention-policy': () => createRetentionPolicy(),
|
|
34
|
+
'evaluate-tiers-now': () => evaluateTiersNow(),
|
|
35
|
+
'export-backup': () => exportBackup(),
|
|
36
|
+
'export-memory-as-markdown': () => exportMemoryAsMarkdown(),
|
|
37
|
+
'filter-events': () => filterEvents(),
|
|
38
|
+
'load-agents': () => loadAgents(),
|
|
39
|
+
'load-clusters': () => loadClusters(),
|
|
40
|
+
'load-compliance': () => loadCompliance(),
|
|
41
|
+
'load-entity-explorer': () => loadEntityExplorer(),
|
|
42
|
+
'load-graph': () => loadGraph(),
|
|
43
|
+
'load-health-monitor': () => loadHealthMonitor(),
|
|
44
|
+
'load-ingestion-status': () => loadIngestionStatus(),
|
|
45
|
+
'load-mesh-peers': () => loadMeshPeers(),
|
|
46
|
+
'load-skill-evolution': () => loadSkillEvolution(),
|
|
47
|
+
'refresh-dashboard': () => refreshDashboard(),
|
|
48
|
+
'reset-learning-data': () => resetLearningData(),
|
|
49
|
+
'run-community-detection': () => runCommunityDetection(),
|
|
50
|
+
'save-backup-config': () => saveBackupConfig(),
|
|
51
|
+
'search-memories': () => searchMemories(),
|
|
52
|
+
'sigma-reset-view': () => sigmaResetView(),
|
|
53
|
+
'sigma-zoom-in': () => sigmaZoomIn(),
|
|
54
|
+
'sigma-zoom-out': () => sigmaZoomOut(),
|
|
55
|
+
'sync-cloud-now': () => syncCloudNow(),
|
|
56
|
+
'toggle-dark-mode': () => toggleDarkMode(),
|
|
57
|
+
// --- phase 2: handlers on JS-generated markup (dynamic args via data-*) ---
|
|
58
|
+
'toggle-privacy-blur': () => togglePrivacyBlur(),
|
|
59
|
+
'open-settings-tab': () => { const t = document.querySelector('[data-target=settings]'); if (t) t.click(); },
|
|
60
|
+
'show-chat-panel': () => showChatPanel(),
|
|
61
|
+
'show-detail-panel': () => showDetailPanel(),
|
|
62
|
+
'send-chat-from-input': () => sendChatFromInput(),
|
|
63
|
+
'cancel-chat': () => cancelChat(),
|
|
64
|
+
'send-chat-query': (el) => sendChatQuery(el.dataset.query),
|
|
65
|
+
'chat-submit-on-enter': (el, e) => { if (e && e.key === 'Enter') sendChatFromInput(); },
|
|
66
|
+
'citation-click': (el, e) => { if (e) e.preventDefault(); _onCitationClick(el.dataset.factId); },
|
|
67
|
+
'filter-entities': (el) => filterEntities(el.value),
|
|
68
|
+
'navigate-entity-page': (el) => navigateEntityPage(parseInt(el.dataset.page, 10)),
|
|
69
|
+
'show-entity-detail': (el) => showEntityDetail(el.dataset.entity),
|
|
70
|
+
'recompile-entity': (el) => recompileEntity(el.dataset.entity),
|
|
71
|
+
'close-entity-detail': () => { const p = document.getElementById('entity-detail-panel'); if (p) p.style.display = 'none'; },
|
|
72
|
+
'trigger-evolution': () => triggerEvolution(),
|
|
73
|
+
'enable-evolution': () => enableEvolution(),
|
|
74
|
+
'save-evolution-config': () => saveEvolutionConfig(),
|
|
75
|
+
'sigma-highlight-node': (el) => sigmaHighlightNode(el.dataset.nodeId),
|
|
76
|
+
'open-memory-detail': (el) => openMemoryDetail({ id: el.dataset.memId, content: el.dataset.memContent, category: el.dataset.memCategory, importance: parseFloat(el.dataset.memImportance) }, 'graph'),
|
|
77
|
+
'sigma-filter-community': (el) => sigmaFilterByCommunity(parseInt(el.dataset.communityId, 10), el.dataset.communitySrc),
|
|
78
|
+
'odg-select': (el) => odgSelect(el.dataset.odgId), // od-graph.js node inspector + citation clicks
|
|
79
|
+
'load-memories-page': (el) => loadMemories(parseInt(el.dataset.page, 10)),
|
|
80
|
+
'disconnect-destination': (el) => disconnectDestination(el.dataset.destId),
|
|
81
|
+
'adapter-action': (el) => adapterAction(el.dataset.adapter, el.dataset.adapterAction),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const ATTR = { click: 'actClick', change: 'actChange', input: 'actInput', keydown: 'actKeydown' };
|
|
85
|
+
|
|
86
|
+
function makeHandler(type) {
|
|
87
|
+
const key = ATTR[type];
|
|
88
|
+
return function (event) {
|
|
89
|
+
let el = event.target;
|
|
90
|
+
while (el && el.nodeType === 1) {
|
|
91
|
+
if (el.dataset && el.dataset[key]) {
|
|
92
|
+
const fn = ACTIONS[el.dataset[key]];
|
|
93
|
+
if (typeof fn === 'function') fn(el, event);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
el = el.parentElement;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
['click', 'change', 'input', 'keydown'].forEach((t) => document.addEventListener(t, makeHandler(t)));
|
|
102
|
+
})();
|