superlocalmemory 3.4.0 → 3.4.3
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/README.md +7 -8
- package/docs/screenshots/01-dashboard-main.png +0 -0
- package/docs/screenshots/02-knowledge-graph.png +0 -0
- package/docs/screenshots/03-patterns-learning.png +0 -0
- package/docs/screenshots/04-learning-dashboard.png +0 -0
- package/docs/screenshots/05-behavioral-analysis.png +0 -0
- package/docs/screenshots/06-graph-communities.png +0 -0
- package/package.json +2 -2
- package/pyproject.toml +11 -2
- package/scripts/postinstall.js +26 -7
- package/src/superlocalmemory/cli/commands.py +42 -60
- package/src/superlocalmemory/cli/daemon.py +107 -47
- package/src/superlocalmemory/cli/main.py +10 -0
- package/src/superlocalmemory/cli/setup_wizard.py +137 -9
- package/src/superlocalmemory/core/config.py +28 -0
- package/src/superlocalmemory/core/consolidation_engine.py +38 -1
- package/src/superlocalmemory/core/engine.py +9 -0
- package/src/superlocalmemory/core/engine_wiring.py +5 -1
- package/src/superlocalmemory/core/graph_analyzer.py +254 -12
- package/src/superlocalmemory/core/health_monitor.py +313 -0
- package/src/superlocalmemory/core/reranker_worker.py +19 -5
- package/src/superlocalmemory/ingestion/__init__.py +13 -0
- package/src/superlocalmemory/ingestion/adapter_manager.py +234 -0
- package/src/superlocalmemory/ingestion/base_adapter.py +177 -0
- package/src/superlocalmemory/ingestion/calendar_adapter.py +340 -0
- package/src/superlocalmemory/ingestion/credentials.py +118 -0
- package/src/superlocalmemory/ingestion/gmail_adapter.py +369 -0
- package/src/superlocalmemory/ingestion/parsers.py +100 -0
- package/src/superlocalmemory/ingestion/transcript_adapter.py +156 -0
- package/src/superlocalmemory/learning/consolidation_worker.py +287 -53
- package/src/superlocalmemory/learning/entity_compiler.py +377 -0
- package/src/superlocalmemory/mesh/__init__.py +12 -0
- package/src/superlocalmemory/mesh/broker.py +344 -0
- package/src/superlocalmemory/retrieval/entity_channel.py +141 -4
- package/src/superlocalmemory/retrieval/spreading_activation.py +45 -0
- package/src/superlocalmemory/server/api.py +15 -8
- package/src/superlocalmemory/server/routes/behavioral.py +8 -4
- package/src/superlocalmemory/server/routes/chat.py +320 -0
- package/src/superlocalmemory/server/routes/entity.py +95 -0
- package/src/superlocalmemory/server/routes/ingest.py +110 -0
- package/src/superlocalmemory/server/routes/insights.py +368 -0
- package/src/superlocalmemory/server/routes/learning.py +106 -6
- package/src/superlocalmemory/server/routes/memories.py +20 -9
- package/src/superlocalmemory/server/routes/mesh.py +186 -0
- package/src/superlocalmemory/server/routes/stats.py +25 -3
- package/src/superlocalmemory/server/routes/timeline.py +252 -0
- package/src/superlocalmemory/server/routes/v3_api.py +161 -0
- package/src/superlocalmemory/server/ui.py +8 -0
- package/src/superlocalmemory/server/unified_daemon.py +691 -0
- package/src/superlocalmemory/storage/schema_v343.py +229 -0
- package/src/superlocalmemory/ui/index.html +168 -58
- package/src/superlocalmemory/ui/js/graph-event-bus.js +83 -0
- package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
- package/src/superlocalmemory/ui/js/knowledge-graph.js +942 -0
- package/src/superlocalmemory/ui/js/memory-chat.js +344 -0
- package/src/superlocalmemory/ui/js/memory-timeline.js +265 -0
- package/src/superlocalmemory/ui/js/quick-actions.js +334 -0
- package/src/superlocalmemory.egg-info/PKG-INFO +0 -594
- package/src/superlocalmemory.egg-info/SOURCES.txt +0 -279
- package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
- package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
- package/src/superlocalmemory.egg-info/requires.txt +0 -47
- package/src/superlocalmemory.egg-info/top_level.txt +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under the Elastic License 2.0 - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
|
|
5
|
+
"""SuperLocalMemory V3.4.3 "The Unified Brain" — Schema Extensions.
|
|
6
|
+
|
|
7
|
+
All new tables for v3.4.3 features:
|
|
8
|
+
- Phase C: Mesh broker tables (mesh_peers, mesh_messages, mesh_state, mesh_locks, mesh_events)
|
|
9
|
+
- Phase D: Entity compilation (ALTER entity_profiles + new index)
|
|
10
|
+
- Phase E: Ingestion log (ingestion_log)
|
|
11
|
+
|
|
12
|
+
Design rules (inherited from schema_v32.py):
|
|
13
|
+
- CREATE IF NOT EXISTS for idempotency
|
|
14
|
+
- profile_id where applicable
|
|
15
|
+
- Never ALTER existing column types (add new columns only)
|
|
16
|
+
|
|
17
|
+
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import logging
|
|
23
|
+
import sqlite3
|
|
24
|
+
from typing import Final
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Table names (for reference and rollback)
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
V343_TABLES: Final[tuple[str, ...]] = (
|
|
33
|
+
"mesh_peers",
|
|
34
|
+
"mesh_messages",
|
|
35
|
+
"mesh_state",
|
|
36
|
+
"mesh_locks",
|
|
37
|
+
"mesh_events",
|
|
38
|
+
"ingestion_log",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
# DDL — Phase C: Mesh Broker Tables
|
|
43
|
+
# ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
_MESH_DDL = """
|
|
46
|
+
-- Mesh Peers
|
|
47
|
+
CREATE TABLE IF NOT EXISTS mesh_peers (
|
|
48
|
+
peer_id TEXT PRIMARY KEY,
|
|
49
|
+
session_id TEXT NOT NULL,
|
|
50
|
+
summary TEXT DEFAULT '',
|
|
51
|
+
status TEXT DEFAULT 'active',
|
|
52
|
+
host TEXT DEFAULT '127.0.0.1',
|
|
53
|
+
port INTEGER DEFAULT 0,
|
|
54
|
+
registered_at TEXT NOT NULL,
|
|
55
|
+
last_heartbeat TEXT NOT NULL
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
-- Mesh Messages
|
|
59
|
+
CREATE TABLE IF NOT EXISTS mesh_messages (
|
|
60
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
61
|
+
from_peer TEXT NOT NULL,
|
|
62
|
+
to_peer TEXT NOT NULL,
|
|
63
|
+
msg_type TEXT DEFAULT 'text',
|
|
64
|
+
content TEXT NOT NULL,
|
|
65
|
+
read INTEGER DEFAULT 0,
|
|
66
|
+
created_at TEXT NOT NULL
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
-- Mesh State (shared key-value store)
|
|
70
|
+
CREATE TABLE IF NOT EXISTS mesh_state (
|
|
71
|
+
key TEXT PRIMARY KEY,
|
|
72
|
+
value TEXT NOT NULL,
|
|
73
|
+
set_by TEXT NOT NULL,
|
|
74
|
+
updated_at TEXT NOT NULL
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
-- Mesh Locks (file-level locks for coordination)
|
|
78
|
+
CREATE TABLE IF NOT EXISTS mesh_locks (
|
|
79
|
+
file_path TEXT PRIMARY KEY,
|
|
80
|
+
locked_by TEXT NOT NULL,
|
|
81
|
+
locked_at TEXT NOT NULL,
|
|
82
|
+
expires_at TEXT NOT NULL DEFAULT '9999-12-31T23:59:59Z'
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
-- Mesh Events (audit log)
|
|
86
|
+
CREATE TABLE IF NOT EXISTS mesh_events (
|
|
87
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
88
|
+
event_type TEXT NOT NULL,
|
|
89
|
+
payload TEXT DEFAULT '{}',
|
|
90
|
+
emitted_by TEXT NOT NULL,
|
|
91
|
+
created_at TEXT NOT NULL
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_messages_to
|
|
95
|
+
ON mesh_messages(to_peer, read);
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_events_type
|
|
97
|
+
ON mesh_events(event_type, created_at);
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
# ---------------------------------------------------------------------------
|
|
101
|
+
# DDL — Phase D: Entity Compilation (ALTER entity_profiles)
|
|
102
|
+
# ---------------------------------------------------------------------------
|
|
103
|
+
|
|
104
|
+
_ENTITY_COMPILATION_ALTERS = [
|
|
105
|
+
"ALTER TABLE entity_profiles ADD COLUMN project_name TEXT DEFAULT ''",
|
|
106
|
+
"ALTER TABLE entity_profiles ADD COLUMN compiled_truth TEXT DEFAULT ''",
|
|
107
|
+
"ALTER TABLE entity_profiles ADD COLUMN timeline TEXT DEFAULT '[]'",
|
|
108
|
+
"ALTER TABLE entity_profiles ADD COLUMN compilation_confidence REAL DEFAULT 0.5",
|
|
109
|
+
"ALTER TABLE entity_profiles ADD COLUMN last_compiled_at TEXT DEFAULT NULL",
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
_ENTITY_COMPILATION_INDEX = """
|
|
113
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_entity_profiles_compilation
|
|
114
|
+
ON entity_profiles(entity_id, profile_id, project_name);
|
|
115
|
+
CREATE INDEX IF NOT EXISTS idx_entity_profiles_project
|
|
116
|
+
ON entity_profiles(profile_id, project_name);
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
# DDL — Phase E: Ingestion Log
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
_INGESTION_DDL = """
|
|
124
|
+
CREATE TABLE IF NOT EXISTS ingestion_log (
|
|
125
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
126
|
+
source_type TEXT NOT NULL,
|
|
127
|
+
dedup_key TEXT NOT NULL,
|
|
128
|
+
fact_ids TEXT DEFAULT '[]',
|
|
129
|
+
metadata TEXT DEFAULT '{}',
|
|
130
|
+
status TEXT DEFAULT 'ingested',
|
|
131
|
+
ingested_at TEXT NOT NULL,
|
|
132
|
+
UNIQUE(source_type, dedup_key)
|
|
133
|
+
);
|
|
134
|
+
CREATE INDEX IF NOT EXISTS idx_ingestion_dedup
|
|
135
|
+
ON ingestion_log(source_type, dedup_key);
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
# ---------------------------------------------------------------------------
|
|
139
|
+
# Version marker
|
|
140
|
+
# ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
_VERSION_DDL = """
|
|
143
|
+
CREATE TABLE IF NOT EXISTS schema_version (
|
|
144
|
+
version TEXT PRIMARY KEY,
|
|
145
|
+
applied_at TEXT NOT NULL
|
|
146
|
+
);
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# ---------------------------------------------------------------------------
|
|
151
|
+
# Migration runner
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
def apply_v343_schema(db_path: str | sqlite3.Connection) -> dict:
|
|
155
|
+
"""Apply all v3.4.3 schema changes. Idempotent — safe to call multiple times.
|
|
156
|
+
|
|
157
|
+
Returns dict with migration status and any errors.
|
|
158
|
+
"""
|
|
159
|
+
result = {"applied": [], "skipped": [], "errors": []}
|
|
160
|
+
|
|
161
|
+
if isinstance(db_path, sqlite3.Connection):
|
|
162
|
+
conn = db_path
|
|
163
|
+
own_connection = False
|
|
164
|
+
else:
|
|
165
|
+
conn = sqlite3.connect(str(db_path))
|
|
166
|
+
own_connection = True
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
# Check if already applied
|
|
170
|
+
try:
|
|
171
|
+
row = conn.execute(
|
|
172
|
+
"SELECT version FROM schema_version WHERE version = '3.4.3'"
|
|
173
|
+
).fetchone()
|
|
174
|
+
if row:
|
|
175
|
+
result["skipped"].append("v3.4.3 already applied")
|
|
176
|
+
return result
|
|
177
|
+
except sqlite3.OperationalError:
|
|
178
|
+
pass # schema_version table doesn't exist yet
|
|
179
|
+
|
|
180
|
+
# Apply version table
|
|
181
|
+
conn.executescript(_VERSION_DDL)
|
|
182
|
+
|
|
183
|
+
# Phase C: Mesh tables
|
|
184
|
+
try:
|
|
185
|
+
conn.executescript(_MESH_DDL)
|
|
186
|
+
result["applied"].append("mesh tables (5 tables, 2 indexes)")
|
|
187
|
+
except sqlite3.OperationalError as e:
|
|
188
|
+
result["errors"].append(f"mesh: {e}")
|
|
189
|
+
|
|
190
|
+
# Phase D: Entity compilation ALTER TABLE
|
|
191
|
+
for alter_sql in _ENTITY_COMPILATION_ALTERS:
|
|
192
|
+
try:
|
|
193
|
+
conn.execute(alter_sql)
|
|
194
|
+
result["applied"].append(alter_sql.split("ADD COLUMN")[1].strip().split()[0])
|
|
195
|
+
except sqlite3.OperationalError:
|
|
196
|
+
# Column already exists — fine (idempotent)
|
|
197
|
+
pass
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
conn.executescript(_ENTITY_COMPILATION_INDEX)
|
|
201
|
+
result["applied"].append("entity_profiles indexes")
|
|
202
|
+
except sqlite3.OperationalError as e:
|
|
203
|
+
result["errors"].append(f"entity indexes: {e}")
|
|
204
|
+
|
|
205
|
+
# Phase E: Ingestion log
|
|
206
|
+
try:
|
|
207
|
+
conn.executescript(_INGESTION_DDL)
|
|
208
|
+
result["applied"].append("ingestion_log table")
|
|
209
|
+
except sqlite3.OperationalError as e:
|
|
210
|
+
result["errors"].append(f"ingestion: {e}")
|
|
211
|
+
|
|
212
|
+
# Mark version
|
|
213
|
+
conn.execute(
|
|
214
|
+
"INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (?, ?)",
|
|
215
|
+
("3.4.3", __import__("datetime").datetime.now().isoformat()),
|
|
216
|
+
)
|
|
217
|
+
conn.commit()
|
|
218
|
+
|
|
219
|
+
if result["applied"]:
|
|
220
|
+
logger.info("Schema v3.4.3 applied: %s", ", ".join(result["applied"]))
|
|
221
|
+
|
|
222
|
+
except Exception as e:
|
|
223
|
+
result["errors"].append(f"fatal: {e}")
|
|
224
|
+
logger.error("Schema v3.4.3 migration failed: %s", e)
|
|
225
|
+
finally:
|
|
226
|
+
if own_connection:
|
|
227
|
+
conn.close()
|
|
228
|
+
|
|
229
|
+
return result
|
|
@@ -654,6 +654,9 @@
|
|
|
654
654
|
</button>
|
|
655
655
|
</div>
|
|
656
656
|
<span class="text-white-50 d-none d-md-inline" id="navbar-subtitle">Knowledge Graph Explorer</span>
|
|
657
|
+
<a href="https://github.com/qualixar/superlocalmemory" target="_blank" class="btn btn-sm btn-outline-light ms-2 d-none d-md-inline-flex align-items-center" style="font-size:0.75rem; gap:4px;" title="Star us on GitHub">
|
|
658
|
+
<i class="bi bi-github"></i> <i class="bi bi-star"></i> Star
|
|
659
|
+
</a>
|
|
657
660
|
<button class="btn btn-sm theme-toggle" id="refresh-dashboard-btn" onclick="refreshDashboard()" title="Refresh Dashboard" style="padding:4px 8px;">
|
|
658
661
|
<i class="bi bi-arrow-clockwise" aria-hidden="true"></i>
|
|
659
662
|
</button>
|
|
@@ -894,7 +897,7 @@
|
|
|
894
897
|
<div class="row align-items-center mb-2">
|
|
895
898
|
<div class="col-md-8">
|
|
896
899
|
<h5 class="mb-0">Interactive Knowledge Graph</h5>
|
|
897
|
-
<small class="text-muted">Zoom, pan, click nodes to explore •
|
|
900
|
+
<small class="text-muted" id="graph-renderer-label">Zoom, pan, click nodes to explore • <span id="graph-engine-name">Sigma.js WebGL</span></small>
|
|
898
901
|
<div id="graph-stats" class="mt-2"></div>
|
|
899
902
|
</div>
|
|
900
903
|
<div class="col-md-4 text-end">
|
|
@@ -902,62 +905,161 @@
|
|
|
902
905
|
<i class="bi bi-arrow-clockwise"></i> Refresh
|
|
903
906
|
</button>
|
|
904
907
|
<select class="form-select form-select-sm d-inline-block w-auto" id="graph-max-nodes" onchange="loadGraph()" aria-label="Select maximum number of nodes to display">
|
|
905
|
-
<option value="50"
|
|
908
|
+
<option value="50">50 nodes</option>
|
|
906
909
|
<option value="100">100 nodes</option>
|
|
907
|
-
<option value="200">200 nodes</option>
|
|
910
|
+
<option value="200" selected>200 nodes</option>
|
|
908
911
|
<option value="500">500 nodes</option>
|
|
912
|
+
<option value="1000">1,000 nodes</option>
|
|
913
|
+
<option value="2000">2,000 nodes</option>
|
|
914
|
+
<option value="5000">All (5K+)</option>
|
|
909
915
|
</select>
|
|
910
916
|
</div>
|
|
911
917
|
</div>
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
918
|
+
<!-- Filter status (kept for cluster/modal integration) -->
|
|
919
|
+
<div id="graph-status-container" style="display:none;">
|
|
920
|
+
<div id="graph-status-full"></div>
|
|
921
|
+
<div id="graph-status-filtered"></div>
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
<!-- v3.4.1: Sigma.js controls bar -->
|
|
925
|
+
<div class="row g-2 mb-2" id="sigma-controls">
|
|
926
|
+
<div class="col-12">
|
|
927
|
+
<div class="d-flex align-items-center gap-2">
|
|
928
|
+
<div class="input-group input-group-sm" style="max-width:400px;">
|
|
929
|
+
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
930
|
+
<input type="text" class="form-control" id="sigma-search-input"
|
|
931
|
+
placeholder="Search memories in graph..." aria-label="Search graph nodes"
|
|
932
|
+
oninput="sigmaSearch(this.value)">
|
|
933
|
+
<button class="btn btn-outline-secondary" type="button"
|
|
934
|
+
onclick="sigmaClearSearch(); document.getElementById('sigma-search-input').value='';">
|
|
935
|
+
<i class="bi bi-x-lg"></i>
|
|
936
|
+
</button>
|
|
937
|
+
</div>
|
|
938
|
+
<div class="btn-group btn-group-sm">
|
|
939
|
+
<button class="btn btn-outline-secondary" onclick="sigmaZoomIn()" title="Zoom In"><i class="bi bi-zoom-in"></i></button>
|
|
940
|
+
<button class="btn btn-outline-secondary" onclick="sigmaZoomOut()" title="Zoom Out"><i class="bi bi-zoom-out"></i></button>
|
|
941
|
+
<button class="btn btn-outline-secondary" onclick="sigmaResetView()" title="Reset View"><i class="bi bi-arrows-angle-expand"></i></button>
|
|
942
|
+
</div>
|
|
923
943
|
</div>
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
<div id="graph-status-container">
|
|
927
|
-
<!-- When viewing FULL graph (default state) -->
|
|
928
|
-
<div id="graph-status-full" style="display:block;" role="status" aria-live="polite">
|
|
929
|
-
<div class="d-flex align-items-center">
|
|
930
|
-
<span class="text-muted small">
|
|
931
|
-
<i class="bi bi-diagram-3"></i> <span id="graph-status-full-text">Showing all memories</span>
|
|
932
|
-
</span>
|
|
933
|
-
<button class="btn btn-sm btn-outline-secondary ms-2" onclick="loadGraph()" aria-label="Refresh current graph view">
|
|
934
|
-
<i class="bi bi-arrow-clockwise"></i> Refresh
|
|
935
|
-
</button>
|
|
936
|
-
</div>
|
|
937
|
-
</div>
|
|
944
|
+
</div>
|
|
945
|
+
</div>
|
|
938
946
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
947
|
+
<div class="row g-2">
|
|
948
|
+
<!-- LEFT PANEL: Legend + Communities + Stats -->
|
|
949
|
+
<div class="col-md-2" id="graph-left-panel">
|
|
950
|
+
<div class="card p-2" style="font-size:0.8rem; max-height:550px; overflow-y:auto;">
|
|
951
|
+
<h6 class="mb-2"><i class="bi bi-palette"></i> Legend</h6>
|
|
952
|
+
<div class="mb-1"><span style="display:inline-block;width:12px;height:12px;border-radius:50%;background:#667eea;"></span> Semantic</div>
|
|
953
|
+
<div class="mb-1"><span style="display:inline-block;width:12px;height:12px;border-radius:50%;background:#43e97b;"></span> Episodic</div>
|
|
954
|
+
<div class="mb-1"><span style="display:inline-block;width:12px;height:12px;border-radius:50%;background:#f093fb;"></span> Opinion</div>
|
|
955
|
+
<div class="mb-1"><span style="display:inline-block;width:12px;height:12px;border-radius:50%;background:#4facfe;"></span> Temporal</div>
|
|
956
|
+
<hr class="my-2">
|
|
957
|
+
<h6 class="mb-2 d-flex justify-content-between align-items-center">
|
|
958
|
+
<span><i class="bi bi-collection"></i> Communities</span>
|
|
959
|
+
<div class="btn-group btn-group-sm" role="group" aria-label="Community source">
|
|
960
|
+
<input type="radio" class="btn-check" name="community-source" id="community-live" checked onchange="handleCommunitySourceToggle('live')">
|
|
961
|
+
<label class="btn btn-outline-secondary py-0 px-1" style="font-size:0.65rem;" for="community-live">Live</label>
|
|
962
|
+
<input type="radio" class="btn-check" name="community-source" id="community-backend" onchange="handleCommunitySourceToggle('backend')">
|
|
963
|
+
<label class="btn btn-outline-secondary py-0 px-1" style="font-size:0.65rem;" for="community-backend">Backend</label>
|
|
951
964
|
</div>
|
|
965
|
+
</h6>
|
|
966
|
+
<div class="mb-1" id="community-resolution-container">
|
|
967
|
+
<label class="form-label small mb-0">Resolution <span id="community-resolution-value" class="text-muted">1.0</span></label>
|
|
968
|
+
<input type="range" class="form-range" id="community-resolution" min="0.1" max="3.0" step="0.1" value="1.0"
|
|
969
|
+
oninput="handleResolutionChange(this.value)">
|
|
970
|
+
</div>
|
|
971
|
+
<div id="community-list-panel">
|
|
972
|
+
<div class="text-muted small">No communities detected yet.</div>
|
|
973
|
+
<button class="btn btn-sm btn-outline-primary w-100 mt-1" onclick="runCommunityDetection()">
|
|
974
|
+
<i class="bi bi-cpu"></i> Detect
|
|
975
|
+
</button>
|
|
976
|
+
</div>
|
|
977
|
+
<hr class="my-2">
|
|
978
|
+
<h6 class="mb-2"><i class="bi bi-graph-up"></i> Stats</h6>
|
|
979
|
+
<div id="sigma-stats-panel">
|
|
980
|
+
<div class="text-muted">Loading...</div>
|
|
981
|
+
</div>
|
|
982
|
+
<hr class="my-2">
|
|
983
|
+
<h6 class="mb-2"><i class="bi bi-funnel"></i> Filter</h6>
|
|
984
|
+
<select class="form-select form-select-sm mb-1" id="sigma-category-filter"
|
|
985
|
+
onchange="sigmaFilterByCategory(this.value)">
|
|
986
|
+
<option value="">All types</option>
|
|
987
|
+
<option value="semantic">Semantic</option>
|
|
988
|
+
<option value="episodic">Episodic</option>
|
|
989
|
+
<option value="opinion">Opinion</option>
|
|
990
|
+
<option value="temporal">Temporal</option>
|
|
991
|
+
</select>
|
|
992
|
+
</div>
|
|
993
|
+
</div>
|
|
994
|
+
|
|
995
|
+
<!-- CENTER: Graph canvas -->
|
|
996
|
+
<div class="col-md-7">
|
|
997
|
+
<div id="graph-container"
|
|
998
|
+
role="application"
|
|
999
|
+
aria-label="Interactive knowledge graph"
|
|
1000
|
+
aria-describedby="graph-stats"
|
|
1001
|
+
style="width:100%; height:550px; border:1px solid #dee2e6; border-radius:8px; background:#fafbfc;">
|
|
1002
|
+
</div>
|
|
1003
|
+
</div>
|
|
1004
|
+
|
|
1005
|
+
<!-- RIGHT PANEL: Node detail -->
|
|
1006
|
+
<div class="col-md-3" id="graph-right-panel">
|
|
1007
|
+
<div class="card p-2" id="sigma-detail-panel" style="font-size:0.85rem; max-height:550px; overflow-y:auto;">
|
|
1008
|
+
<h6 class="mb-2"><i class="bi bi-info-circle"></i> Node Detail</h6>
|
|
1009
|
+
<div id="sigma-detail-content" class="text-muted">
|
|
1010
|
+
Click a node to see its details, connected memories, and trust score.
|
|
952
1011
|
</div>
|
|
953
1012
|
</div>
|
|
954
1013
|
</div>
|
|
955
1014
|
</div>
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1015
|
+
|
|
1016
|
+
<!-- v3.4.1: Quick Insight Actions -->
|
|
1017
|
+
<div class="row g-2 mt-2">
|
|
1018
|
+
<div class="col-12">
|
|
1019
|
+
<div class="card p-2">
|
|
1020
|
+
<div class="d-flex flex-wrap gap-1 mb-2">
|
|
1021
|
+
<button class="btn btn-sm btn-outline-info" data-insight-action="changed_this_week">
|
|
1022
|
+
<i class="bi bi-clock-history"></i> Changed This Week
|
|
1023
|
+
</button>
|
|
1024
|
+
<button class="btn btn-sm btn-outline-warning" data-insight-action="opinions">
|
|
1025
|
+
<i class="bi bi-lightbulb"></i> Opinions & Rationale
|
|
1026
|
+
</button>
|
|
1027
|
+
<button class="btn btn-sm btn-outline-danger" data-insight-action="contradictions">
|
|
1028
|
+
<i class="bi bi-exclamation-triangle"></i> Contradictions
|
|
1029
|
+
</button>
|
|
1030
|
+
<button class="btn btn-sm btn-outline-success" data-insight-action="health">
|
|
1031
|
+
<i class="bi bi-heart-pulse"></i> Memory Health
|
|
1032
|
+
</button>
|
|
1033
|
+
<button class="btn btn-sm btn-outline-primary" data-insight-action="cross_project">
|
|
1034
|
+
<i class="bi bi-diagram-3"></i> Cross-Project Links
|
|
1035
|
+
</button>
|
|
1036
|
+
</div>
|
|
1037
|
+
<div id="insight-results" style="max-height:300px; overflow-y:auto;"></div>
|
|
1038
|
+
</div>
|
|
1039
|
+
</div>
|
|
1040
|
+
</div>
|
|
1041
|
+
|
|
1042
|
+
<!-- v3.4.1: Memory Timeline (D3.js) -->
|
|
1043
|
+
<div id="memory-timeline-panel" class="mt-3">
|
|
1044
|
+
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
1045
|
+
<h6 class="mb-0"><i class="bi bi-clock-history"></i> Memory Timeline</h6>
|
|
1046
|
+
<div class="btn-group btn-group-sm" role="group" id="timeline-zoom-group">
|
|
1047
|
+
<button type="button" class="btn btn-outline-secondary active" data-zoom="week">Week</button>
|
|
1048
|
+
<button type="button" class="btn btn-outline-secondary" data-zoom="day">Day</button>
|
|
1049
|
+
<button type="button" class="btn btn-outline-secondary" data-zoom="month">Month</button>
|
|
1050
|
+
</div>
|
|
1051
|
+
<div class="btn-group btn-group-sm ms-2" role="group" id="timeline-group-by-group">
|
|
1052
|
+
<button type="button" class="btn btn-outline-info active" data-groupby="category">By Type</button>
|
|
1053
|
+
<button type="button" class="btn btn-outline-info" data-groupby="community">By Community</button>
|
|
1054
|
+
</div>
|
|
1055
|
+
</div>
|
|
1056
|
+
<div id="memory-timeline-chart" style="width:100%;height:280px;overflow:hidden;border:1px solid #dee2e6;border-radius:8px;background:#fafbfc;"></div>
|
|
1057
|
+
<div class="d-flex gap-3 mt-1 small text-muted">
|
|
1058
|
+
<span><span class="badge" style="background:#198754"> </span> High trust (>=0.7)</span>
|
|
1059
|
+
<span><span class="badge" style="background:#ffc107"> </span> Medium (0.4-0.7)</span>
|
|
1060
|
+
<span><span class="badge" style="background:#dc3545"> </span> Low (<0.4)</span>
|
|
1061
|
+
<span><span class="badge" style="background:#6c757d"> </span> Unknown</span>
|
|
1062
|
+
</div>
|
|
961
1063
|
</div>
|
|
962
1064
|
|
|
963
1065
|
<!-- Skip link for keyboard users -->
|
|
@@ -1830,22 +1932,30 @@
|
|
|
1830
1932
|
<!-- D3.js (kept for backward compatibility) -->
|
|
1831
1933
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
|
1832
1934
|
|
|
1833
|
-
<!-- Cytoscape.js
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
<script src="https://
|
|
1837
|
-
<script src="https://
|
|
1838
|
-
<
|
|
1839
|
-
<script src="https://unpkg.com/cytoscape-navigator@1.3.3/cytoscape-navigator.js"></script>
|
|
1935
|
+
<!-- Cytoscape.js REMOVED in v3.4.1 — replaced by Sigma.js WebGL -->
|
|
1936
|
+
|
|
1937
|
+
<!-- Sigma.js v3 + graphology (v3.4.1 — WebGL graph) -->
|
|
1938
|
+
<script src="https://cdn.jsdelivr.net/npm/graphology@0.25.4/dist/graphology.umd.min.js"></script>
|
|
1939
|
+
<script src="https://cdn.jsdelivr.net/npm/graphology-library@0.8.0/dist/graphology-library.min.js"></script>
|
|
1940
|
+
<script src="https://cdn.jsdelivr.net/npm/sigma@2.4.0/build/sigma.min.js"></script>
|
|
1840
1941
|
|
|
1841
1942
|
<!-- Modular JS (v2.5 — split from monolith app.js) -->
|
|
1842
1943
|
<script src="static/js/core.js"></script>
|
|
1843
1944
|
|
|
1844
|
-
<!--
|
|
1845
|
-
<script src="static/js/graph-
|
|
1846
|
-
|
|
1945
|
+
<!-- v3.4.1: Event bus (must load before graph + chat) -->
|
|
1946
|
+
<script src="static/js/graph-event-bus.js"></script>
|
|
1947
|
+
<!-- v3.4.1: Sigma.js Knowledge Graph (defines globals: filterState, loadGraph, renderGraph) -->
|
|
1948
|
+
<script src="static/js/knowledge-graph.js"></script>
|
|
1949
|
+
<!-- Shared UI utilities (showLoadingSpinner, updateGraphStats, etc.) -->
|
|
1847
1950
|
<script src="static/js/graph-ui.js"></script>
|
|
1848
|
-
|
|
1951
|
+
<!-- Filter functions (filterByCluster, filterByEntity — used by clusters.js, modal.js) -->
|
|
1952
|
+
<script src="static/js/graph-filters.js"></script>
|
|
1953
|
+
<!-- v3.4.1: Ask My Memory chat interface -->
|
|
1954
|
+
<script src="static/js/memory-chat.js"></script>
|
|
1955
|
+
<!-- v3.4.1: Quick Insight Actions (5 one-click intelligence buttons) -->
|
|
1956
|
+
<script src="static/js/quick-actions.js"></script>
|
|
1957
|
+
<!-- v3.4.1: Memory Timeline (D3 time axis, zoom, trust colors) -->
|
|
1958
|
+
<script src="static/js/memory-timeline.js"></script>
|
|
1849
1959
|
|
|
1850
1960
|
<script src="static/js/memories.js"></script>
|
|
1851
1961
|
<script src="static/js/search.js"></script>
|
|
@@ -1872,8 +1982,8 @@
|
|
|
1872
1982
|
<script src="static/js/fact-detail.js"></script>
|
|
1873
1983
|
|
|
1874
1984
|
<footer>
|
|
1875
|
-
<p>SuperLocalMemory V3 by <a href="https://github.com/varun369">Varun Pratap Bhardwaj</a></p>
|
|
1876
|
-
<p><a href="https://github.com/qualixar/superlocalmemory">GitHub
|
|
1985
|
+
<p>SuperLocalMemory V3 by <a href="https://github.com/varun369">Varun Pratap Bhardwaj</a> · <a href="https://qualixar.com">Qualixar</a></p>
|
|
1986
|
+
<p><a href="https://github.com/qualixar/superlocalmemory">GitHub</a> · AGPL-3.0-or-later · <a href="https://github.com/qualixar/superlocalmemory/stargazers">⭐ Star us on GitHub</a></p>
|
|
1877
1987
|
</footer>
|
|
1878
1988
|
</body>
|
|
1879
1989
|
</html>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// SuperLocalMemory v3.4.1 — Graph Event Bus
|
|
2
|
+
// Copyright (c) 2026 Varun Pratap Bhardwaj — AGPL-3.0-or-later
|
|
3
|
+
// CustomEvent-based pub/sub for graph ↔ chat bidirectional linking.
|
|
4
|
+
// Renderer-agnostic — works regardless of which graph engine is active.
|
|
5
|
+
|
|
6
|
+
var SLMEventBus = (function() {
|
|
7
|
+
var _debounceTimers = {};
|
|
8
|
+
|
|
9
|
+
function publish(eventName, detail) {
|
|
10
|
+
window.dispatchEvent(new CustomEvent(eventName, {
|
|
11
|
+
detail: Object.freeze(detail || {}),
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function publishDebounced(eventName, detail, delayMs) {
|
|
16
|
+
if (_debounceTimers[eventName]) {
|
|
17
|
+
clearTimeout(_debounceTimers[eventName]);
|
|
18
|
+
}
|
|
19
|
+
_debounceTimers[eventName] = setTimeout(function() {
|
|
20
|
+
publish(eventName, detail);
|
|
21
|
+
_debounceTimers[eventName] = null;
|
|
22
|
+
}, delayMs || 200);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function subscribe(eventName, callback) {
|
|
26
|
+
window.addEventListener(eventName, function(e) {
|
|
27
|
+
callback(e.detail);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { publish: publish, publishDebounced: publishDebounced, subscribe: subscribe };
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
// Expose globally
|
|
35
|
+
window.SLMEventBus = SLMEventBus;
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// EVENT DEFINITIONS
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// slm:graph:nodeClicked — { factId, label } — graph node was clicked
|
|
41
|
+
// slm:graph:highlightNode — { factId } — highlight a node in graph
|
|
42
|
+
// slm:chat:citationClicked — { factId } — citation badge clicked in chat
|
|
43
|
+
// slm:chat:queryAbout — { query } — fill chat input and send
|
|
44
|
+
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// WIRING: Graph → Chat
|
|
47
|
+
// ============================================================================
|
|
48
|
+
|
|
49
|
+
SLMEventBus.subscribe('slm:graph:nodeClicked', function(detail) {
|
|
50
|
+
// Double-click on graph node → fill chat with query about that node
|
|
51
|
+
// (Single click handled by openSigmaNodeDetail in knowledge-graph.js)
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
SLMEventBus.subscribe('slm:chat:queryAbout', function(detail) {
|
|
55
|
+
if (!detail || !detail.query) return;
|
|
56
|
+
var input = document.getElementById('chat-input');
|
|
57
|
+
if (input) {
|
|
58
|
+
input.value = detail.query;
|
|
59
|
+
// Switch to chat panel if on detail panel
|
|
60
|
+
if (typeof showChatPanel === 'function') showChatPanel();
|
|
61
|
+
// Auto-send
|
|
62
|
+
if (typeof sendChatFromInput === 'function') sendChatFromInput();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// WIRING: Chat → Graph
|
|
68
|
+
// ============================================================================
|
|
69
|
+
|
|
70
|
+
SLMEventBus.subscribe('slm:chat:citationClicked', function(detail) {
|
|
71
|
+
if (!detail || !detail.factId) return;
|
|
72
|
+
// Highlight the cited node in the graph
|
|
73
|
+
if (typeof sigmaHighlightNode === 'function') {
|
|
74
|
+
sigmaHighlightNode(detail.factId);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
SLMEventBus.subscribe('slm:graph:highlightNode', function(detail) {
|
|
79
|
+
if (!detail || !detail.factId) return;
|
|
80
|
+
if (typeof sigmaHighlightNode === 'function') {
|
|
81
|
+
sigmaHighlightNode(detail.factId);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
@@ -123,7 +123,7 @@ function setupGraphEventListeners() {
|
|
|
123
123
|
graphTab.addEventListener('shown.bs.tab', function(event) {
|
|
124
124
|
console.log('[Event] Knowledge Graph tab SHOWN (tab switch)');
|
|
125
125
|
|
|
126
|
-
if (cy) {
|
|
126
|
+
if (cy || sigmaInstance) {
|
|
127
127
|
// Graph already exists - user is returning to KG tab from another tab
|
|
128
128
|
// Clear filter and reload to show full graph
|
|
129
129
|
console.log('[Event] Returning to KG tab from another tab - clearing filter');
|